1、实验目的
设计并实现一个精简的图书管理系统,要求具有图书入库、查询、借书、还书、借书证管理等功能。
2、实验平台
- WAMP
- win 10
- mysqli
3、系统需求分析
基本数据对象
- 书(书号、类别、书名、出版社、年份、作者、价格、总藏书量、库存)
- 借书证(卡号、姓名、单位、类别(学生/教师))
- 管理员(管理员ID,密码,姓名,联系方式)
- 结束记录(书号、借书证号、借期、还期、经手(管理员id))
基本功能模块
管理员登录
输入管理员ID, 密码; 登入系统 或 返回ID/密码 错误.
图书入库
- 单本入库
- 批量入库 (方便最后测试)
图书信息存放在文件中, 每条图书信息为一行. 一行中的内容如下
( 书号, 类别, 书名, 出版社, 年份, 作者, 价格, 数量 )
Note: 其中 年份、数量是整数类型; 价格是两位小数类型; 其余为字符串类型
Sample:
( book_no_1, Computer Science, Computer Architecture, xxx, 2004, xxx, 90.00, 2 )
图书查询
要求可以对书的 类别, 书名, 出版社, 年份(年份区间), 作者, 价格(区间) 进行查询. 每条图书信息包括以下内容:
( 书号, 类别, 书名, 出版社, 年份, 作者, 价格, 总藏书量, 库存 )
可选要求: 可以按用户指定属性对图书信息进行排序. (默认是书名)
借书
- 输入借书证卡号
显示该借书证所有已借书籍 (返回, 格式同查询模块) - 输入书号
如果该书还有库存,则借书成功,同时库存数减一。
否则输出该书无库存,且输出最近归还的时间。
还书
1.输入借书证卡号
显示该借书证所有已借书籍 (返回, 格式同查询模块)
2.输入书号
如果该书在已借书籍列表内, 则还书成功, 同时库存加一.
否则输出出错信息.
借书证管理
增加或删除一个借书证.
4、系统设计
4.1 总体设计
采用简单粗暴的MV(视图-模型)这一系统模型,在视图端(浏览器)发送请求,服务器处理这一请求并返回数据,视图接受数据并显示到视图中。
4.2 数据库表结构设计
表定义
create table book
(bno char(8),category char(10),title varchar(40),press varchar(30),year int,author varchar(20),price decimal(7,2),total int,stock int,primary key(bno)
);create table card
(cno char(7),name varchar(10),department varchar(40),type char(1),primary key(cno),check (type in ('T','S'))
);create table admin
(admin_id char(20),password char(20),name char(20),email char(30),primary key(admin_id)
);create table borrow
(cno char(7),bno char(8),borrow_date date,return_date date,done_by char(20),foreign key (bno) references book(bno) on delete cascade,foreign key (cno) references card(cno) on update cascade
);
但是,mysql的check是无用的,使用触发器来实现check功能:
DELIMITER $$
create trigger type_check_triger before insert on card
for each row
beginif(new.type not in ('T','S'))then signal sqlstate '04922'set message_text = "ERROR: card type not in ('T','S')";end if;
end $$
DELIMITER ;
4.3 管理员登录模块
首先进入主页,选择(管理员/查询)这两个功能之一。由于普通用户只能进行查询功能,就不需要它们登录了。
这里使用的是html的radio表单:
<form method="post" action="<?php echo htmlspecialchars($_SERVER['PHP_SELF']);?>"><input type="radio" name="q" value="admin">ADMIN<input type="radio" name="q" value="user">USER<input type="submit" value=" OK "><span class="error" style="color:brown"> <?php echo $choseerror;?></span>
</form>
php脚本根据表单提交选择用户查询界面或者登录界面:
<?php $choseerror="";$chose="";if($_SERVER["REQUEST_METHOD"] == "POST"){if(empty($_POST['q'])){$choseerror = "必须选择访问身份";} else {$chose=$_POST['q'];if($chose=="admin"){header("location:login.php");}else{header("location:query.php");}}}
?>
登录界面如下图:
选择admin身份,进入登录界面,输入账号和密码:
这个初始的账号是我在创建数据库的时候创建的:
在登录界面的login.php
中,首先和数据库建立连接,这里我使用了mysqli这个mysql拓展来连接。在连接的过程中有一点要注意的是,由于wamp默认了mariadb,所以你在连接的时候要指定mysql服务器的端口号。我就是在连接时找不到我创建的book
数据库,然后在这了卡了很久。
<?php$server_name="localhost";$username="root";$password="qazwsx";$dbname="book";$conn = new mysqli($server_name,$username,$password,$dbname,'3308');if ($conn->connect_error) {die("连接失败: " . $conn->connect_error);}
?>
之后再从book数据库中,select
看看是否有表单输入的账户id和pwd,按情况分别处理:
include 'connect.php';$id=$_POST['account'];$pwd=$_POST['password'];$sql_query="select * from admin where admin_id='".$id."' and password = '".$pwd."'";$sql=$conn->query($sql_query);$info=mysqli_fetch_array($sql);if($info==false){$loginerror = "ID或PWD错误!";}else{$_SESSION['admin_id']=$id;$_SESSION['pwd']=$pwd;header("location:index.php");}
账号密码错误提示:ID或PWD错误
登录成功后跳转到index.php
界面。
在index
界面选择所需要执行的功能。
4.4 图书入库模块
4.4.1单本入库
使用一个表单,submit后做出判断,如果是需要的格式就插入到数据库。
所谓对格式做出判断,一是要求非空,二是要求year,num是整形,price是两位小数:
//出版年份if (empty($_POST["year"])){$yearErr = "必需";$tbool=false;}else {$year = test_input($_POST["year"]);if (!preg_match("/^[0-9]*$/",$year)){$yearErr = "只允整数";$tbool=false; }}//价格if (empty($_POST["price"])){$priceErr = "必需";$tbool=false;}else {$price = test_input($_POST["price"]);if (!preg_match("/^([0-9]*)+(.[0-9]{1,2})?$/",$price)){$priceErr = "decimal(7.2)"; $tbool=false;}}
另外要考虑到:如果管理员入库一本馆藏中有的书,那么就不是insert而需要update。于是先做出判断:
$sql_query="select * from book where bno='".$bno."'";$sql=$conn->query($sql_query);$info=mysqli_fetch_array($sql);if($info==false){//并不存在这一本书...}else{//这本书已经在馆藏中了...}
单本插入(无该书馆藏):
插入结果,在命令行中查看:
已经有馆藏了,继续插入:
命令行select
显示新的4本也被入库:
4.4.2 批量入库
图书信息存在一个文件种,提交文件名:
批量插入后表如下:
同样,在有藏书的情况下再次入库:
批量导入和单本导入的差别并不大,主要涉及到对文件及字符串的处理:
<?php...省略$filename=$_POST['filename'];$file=fopen($filename,"r") or exit("无法打开文件".$filename);while(!feof($file)){$line = fgets($file);$line = test_input($line);if($line=="") continue;$line = mb_substr($line,1,mb_strlen($line)-2);$array = explode(",",$line);$bno=$array[0];...省略其它赋值include 'connect.php';//首先看看是否已经存在了这一本书,如果存在,则update,否则就是insert$sql_query="select * from book where bno=".$bno."";$sql=$conn->query($sql_query);$info=mysqli_fetch_array($sql);if($info==false){//并不存在这一本书...}else{//这本书已经在馆藏中了...}...省略
?>
4.4 图书查询模块
设置一个表单、收集需要的复合查询项。在php中将表单post的值进行处理,此处以price为例。当左/右区间为空时、设置为默认[0,9999.99]。检测值是否符合正则表达式、组装sql语句:
if (!empty($_POST["pricel"])){$pricel = test_input($_POST["pricel"]);if (!preg_match("/^([0-9]*)+(.[0-9]{1,2})?$/",$pricel)){$queryErr = $queryErr."价格左区间应当是decimal(7.2)形式!"; $tbool=false;}}if(!empty($_POST["pricer"])){$pricer = test_input($_POST["pricer"]);if (!preg_match("/^([0-9]*)+(.[0-9]{1,2})?$/",$pricer)){$queryErr = $queryErr."价格右区间应当是decimal(7.2)形式!"; $tbool=false;}}if($pricel > $pricer){$queryErr = $queryErr."价格左区间应当小于右区间!";$tbool=false;}else{$sql_query=$sql_query." and price between ".$pricel." and ".$pricer." ";}
查询输入出错:
应当左区间小于右区间且符合格式:
复合查询:
类别为小说、出版年份大于2000,价格小于40,按照出版年份排序:
4.5 借书模块
对于借书,首先判断借书证号是否存在,不存在则输出错误信息:
//测试是否有该借书证$sql_query="select * from card where cno = '".$cno."'";//echo $sql_query;$sql=$conn->query($sql_query);$info=mysqli_fetch_array($sql);if($info==false){//并不存在这一借书证号$borrowErr.="借书证".$cno."不存在!";}else{...}
然后判断所借的书是否非空,非空则判断是否已经借了这本书,
若没有借这本书,是否还有库存,如果没有库存,最近一次归还日期(实验要求的,我也不知道这个有啥用)
if(!empty($_POST["bno"])){$bno=$_POST["bno"];$sql_query="select * from borrow natural join book where cno = '".$cno."' and bno = '".$bno."' and return_date is null";$sql=$conn->query($sql_query);$info=mysqli_fetch_array($sql);//echo $sql_query;//print_r($info);if($info==false){//没有借这本书$sql_query="select * from book where bno = '".$bno."'";$sql=$conn->query($sql_query);$info=mysqli_fetch_array($sql);if($info==false){$borrowErr.="该书不存在";}else{$tmpstock=$info[8];if($tmpstock=="0"){$sql_query="select return_date from borrow where bno = '".$bno."' order by return_date desc";$sql=$conn->query($sql_query);$info=mysqli_fetch_array($sql);$last_re_date = $info[0];$borrowErr.= "该书库存为0!最近一次归还日期为:<br>".$last_re_date;}else{//从book的stock中减少一本$sql_query="update book set stock = ".$tmpstock." -1 where bno = '".$bno."'";//echo $sql_query;$sql=$conn->query($sql_query);//向borrow记录插入一本书$sql_query="insert into borrow values('".$cno."','".$bno."','".date("Y-m-d")."',null,'".$id."')";//echo $sql_query;$sql=$conn->query($sql_query);}}}else{//echo "hello";$borrowErr.="已经有一本了,给别人留点吧!";}}
书不存在
已经有了一本
没库存了:
4.6 还书模块
还书模块的要求与借书模块基本相近。
显示已经借的书籍:
还书(bno=1)之后:
还一本没有借的书:
4.7 借书证管理
我们用一个表单来收集一个card tuple所需要的属性,一个单选radio
来选择功能(添加/删除)。
对于插入,判断是否已经存在了一个相同的卡号,如果已存在,则输出错误信息。否则insert
插入:
if($fun=="add"){if($info==false){//插入$sql_query="insert into card values('".$cno."','".$name."','".$department."','".$type."')";$conn->query($sql_query);}else{//已经存在卡号$cardErr.="卡号已存在,无法添加!";}}
账号已存在:
插入成功:
输入信息不足:
对于删除,也是先查看卡号是否存在。如果存在且该卡号还有未归还的书籍,那么输出错误信息,否则删除。
if($info==false){//不存在$cardErr.="没有符合条件的卡号";}else{//已经存在卡号,是否有没有还的书$sql_query="select * from borrow natural join book where cno = '".$cno."' and return_date is null";$sql=$conn->query($sql_query);$info=mysqli_fetch_array($sql);if($info==false){//没有没还的书,可以删除$sql_query="delete from card where cno = '".$cno."'";$sql=$conn->query($sql_query);}else{//还不能删除$cardErr.="还有未归还的书!";}}
查看卡号是否存在:
删除成功:
无法删除一个有借书信息的卡号:
4.8 账户登出
清空session,跳转到首页。
<?phpsession_start();$_SESSION = array();if (isset($_COOKIE[session_name()])) {setcookie(session_name(),'',time()-42000,'');}session_destroy();header("location:home.php");
?>
5、总结
总共花了3天,摸索着学html、css、php,最后终于弄出来了这个数据库的期中实验项目,真的困难。
另外代码这个学期不会放出(毕竟要交作业,查重恐怖😱)
学期结束,代码:https://download.csdn.net/download/baidu_40614951/12549363