基于javaEE+jqueryEasyUi+eclipseLink+MySQL的课程设计客房管理信息系统
1. 系统概述
1.1 系统功能概述
1)客户管理。能够增加一个客户,包括:身份证号、客户名称、出生年月、性别、联系电话、邮箱、会员类别等信息,默认会员类别为空;能够修改和删除客户信息;能够根据客户名称、联系电话查询客户基本信息。
2)客户入住。能够根据客房标准和日期查询状态为“空闲”的客房信息,显示楼层号、房间号、费用;能够根据客户名和联系方式查询房间预订信息,显示:楼层号、房间号、预订开始时间,预订结束时间;能够为指定的客户办理指定客房的入住手续,修改客户状态为“入住”,并记录入住时间、前台操作员。
3)退房管理。能够根据房间号查询客房信息;能够完成指定客户对指定房间的退房操作(利用存储过程实现),即首先增加一条客户实际入住记录,包括:客户身份证编号、客户名、房间号、入住时间、退房时间、房费、前台操作员,然后修改客房状态为“空闲”;最后根据会员类别和入住天数计算房费。
4)预订客房。能够根据标准和日期查询客房空闲情况;能够为指定客户预订指定的客房,并记录预订开始时间、预订结束时间、联系人、联系电话、前台操作员、操作时间等信息。
5)预订查询。能够根据客户名或联系电话查询其预订的客房信息,其中,一个客户可以预订多个客房;能够根据楼层号、房间号查询客房的预订详细信息。
图1-1 功能框图
1.2 系统体系结构
图1-2 体系结构图
Browser/Server结构是伴随着因特网的兴起,对Client/Server结构的一种改进。从本质上说,Browser/Server结构也是一种Client/Server结构,它可看作是一种由传统的二层模式Client/Server结构发展而来的三层模式Client/Server结构在Web上应用的特例。
Browser/Server结构主要是利用了不断成熟的Web浏览器技术:结合浏览器的多种脚本语言和ActiveX技术,用通用浏览器实现原来需要复杂专用软件才能实现的强大功能,同时节约了开发成本。
B/S最大的优点就是可以在任何地方进行操作而不用安装任何专门的软件,只要有一台能上网的电脑就能使用,客户端零安装、零维护。系统的扩展非常容易。
B/S结构的使用越来越多,特别是由需求推动了AJAX技术的发展,它的程序也能在客户端电脑上进行部分处理,从而大大的减轻了服务器的负担;并增加了交互性,能进行局部实时刷新。
1.3开发环境
此次设计主要采用MyEclipse加Tomcat后台服务器进行,设计过程中页面主要使用JSP技术完成,下面对MyEclipse、Tomcat和SQL2008数据库进行简要介绍。
MyEclipse,是一个十分优秀的用于开发Java, J2EE的Eclipse插件集合,MyEclipse的功能非常强大,支持也十分广泛,尤其是对各种开元产品的支持十分不错。MyEclipse企业级工作平台(MyEclipse Enterprise Workbench ,简称MyEclipse)是对Eclipse IDE的扩展,利用它我们可以在数据库和JavaEE的开发、发布,以及应用程序服务器的整合方面极大的提高工作效率。它是功能丰富的JavaEE集成开发环境,包括了完备的编码、调试、测试和发布功能,完整支持HTML,JSP,CSS,Javascript,SQL.
Tomcat是一个小型的轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选。可以这样认为,当在一台机器上配置好Apahce服务器,可利用它响应对HTML页面的访问请求。实际上Tomcat 部分是Apache 服务器的扩展,但它是独立运行的,所以当运行tomcat 时,它实际上作为一个与Apache 独立的进程单独运行的
MySQL是一个小型关系型数据库管理系统,开发者为瑞典MySQL AB公司。目前MySQL被广泛地应用在Internet上的中小型网站中。由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,许多中小型网站为了降低网站总体拥有成本而选择了MySQL作为网站数据库。
JSP技术使用Java编程语言编写类XML的tags和scriptlets,来封装产生动态网页的处理逻辑。网页还能通过tags和scriptlets访问存在于服务端的资源的应用逻辑。JSP将网页逻辑与网页设计和显示分离,支持可重用的基于组件的设计,使基于Web的应用程序的开发变得迅速和容易。Web服务器在遇到访问JSP网页的请求时,首先执行其中的程序段,然后将执行结果连同JSP文件中的HTML代码一起返回给客户。插入的Java程序段可以操作数据库、重新定向网页等,以实现建立动态网页所需要的功能。JSP与Servlet一样,是在服务器端执行的,通常返回给客户端就是一个HTML文本,因此客户端只要有浏览器能浏览。JSP页面由HTML代码和嵌入其中的Java代码所组成。服务器在页面被客户端请求以后对这些Java代码进行处理,然后将生成的HTML页面返回给客户端的浏览器。Servlet是JSP的技术基础,而且大型的Web应用程序的开发需要Java Servlet和JSP配合才能完成。JSP具备了Java技术的简单易用,完全的面向对象,具有平台无关性且安全可靠,主要面向因特网的所有特点.
JavaScript是一种基于对象和事件驱动并具有相对安全性的客户端脚本语言。同时也是一种广泛用于客户端Web开发的脚本语言,常用来给HTML网页添加动态功能,比如响应用户的各种操作。JavaScript的一个重要功能就是面向对象的功能,通过基于对象的程序设计,可以用更直观、模块化和可重复使用的方式进行程序开发。在HTML基础上,使用JavaScript可以开发交互式Web网页。JavaScript的出现使得网页和用户之间实现了一种实时性的、动态的、交互性的关系,使网页包含更多活跃的元素和更加精彩的内容。
2 数据库设计
表2.1关系模型表
关系名 | 属性及码 | 其他约束条件 |
客户 | 身份证号,客户名称,出生年月,性别,联系电话,邮箱,会员类别 | 1、身份证号是唯一标识; 2、客户名称不允许为空; 3、联系电话不允许为空; |
客房 | 房间号,楼层号,标准,费用,地理位置 | 房间号是唯一标识; |
入住 | 身份证号,房间号,客户名,入住时间,退房时间,前台操作员,预付金 | 1、 身份证号引用客户关系中的身份证号; 2、 房间号引用客房关系中的房间号; |
用户 | 用户名,用户类型,默认密码,真实姓名,年龄,性别 | 用户名是唯一标识; |
预订客房 | 房间号,预定开始时间,预定结束时间,联系人,联系电话,前台操作员,操作时间 | 1、客房号引用客房关系中的房间号; 2、联系电话不允许为空; |
会员 | 会员号,会员类型,会员折扣 | 会员类型不能为空 |
房间增加消费信息 | 消费编号,房间号,消费类型,消费金额,消费时间,备注 | 客房号引用客房关系中的房间号; |
表2.2 book 订单表
字段名 | 主键 | 外键 | 类型 | 字节数 | 长度 | 小数位 | 字段说明 |
cid | √ | √ | char | 18 | 18 | 0 | 身份证号 |
rno | √ | √ | varchar | 10 | 10 | 0 | 房间号 |
username | √ | varchar | 20 | 20 | 0 | 前台操作人员 | |
btime | √ | datatime | 0 | 0 | 0 | 入住开始时间 | |
etime | datetime | 0 | 0 | 0 | 入住结束时间 | ||
prePay | decimal | 9 | 18 | 1 | 预支金额 |
表2.3 advance 预定表
字段名 | 主键 | 外键 | 类型 | 字节数 | 长度 | 小数位 | 字段说明 |
rno | √ | √ | varchar | 10 | 10 | 0 | 房间号 |
username | √ | varchar | 20 | 20 | 0 | 前台操作员 | |
person | varchar | 20 | 20 | 0 | 联系人 | ||
phone | √ | char | 11 | 11 | 0 | 联系电话 | |
btime | √ | datetime | 20 | 20 | 0 | 身份证号 | |
etime | datetime | 9 | 18 | 1 | 总消费额 | ||
otime | datetime | 4 | 10 | 0 | 等级编号 |
3 系统概要设计
系统有两类用户:前台操作员和系统管理员。其中,前台管理员负责客房预订、入住登记、房客查询、收费管理等功能,系统管理员负责客房信息输入、客房信息查询、前台操作员管理、统计报表等功能。系统主要包括6大功能模块:基本信息管理、入住管理、会员管理、客房预订管理、收费管理、统计报表管理。
1)客户管理。能够增加一个客户,包括:身份证号、客户名称、出生年月、性别、联系电话、邮箱、会员类别等信息,默认会员类别为空;能够修改和删除客户信息;能够根据客户名称、联系电话查询客户基本信息。
2)客户入住。能够根据客房标准和日期查询状态为“空闲”的客房信息,显示楼层号、房间号、费用;能够根据客户名和联系方式查询房间预订信息,显示:楼层号、房间号、预订开始时间,预订结束时间;能够为指定的客户办理指定客房的入住手续,修改客户状态为“入住”,并记录入住时间、前台操作员。
3)退房管理。能够根据房间号查询客房信息;能够完成指定客户对指定房间的退房操作(利用存储过程实现),即首先增加一条客户实际入住记录,包括:客户身份证编号、客户名、房间号、入住时间、退房时间、房费、前台操作员,然后修改客房状态为“空闲”;最后根据会员类别和入住天数计算房费。
图3-1用例图
图3-2预定客房顺序图
图3-3会员状态图
图3-4类图
图3-5前台操作员活动图
图3-6系统管理员活动图
4系统详细设计与实现
(1) 登录功能。实现用户了登录功能。判断用户的类型,按用户类型显示不同的页面。
(2) 客户入住。能够根据客房标准和日期查询状态为“空闲”的客房信息,显示楼层号、房间号、费用;能够根据客户名和联系方式查询房间预订信息,显示:楼层号、房间号、预订开始时间,预订结束时间;能够为指定的客户办理指定客房的入住手续,修改客户状态为“入住”,并记录入住时间、前台操作员。
(3) 退房管理。能够根据房间号查询客房信息;能够完成指定客户对指定房间的退房操作(利用存储过程实现),即首先增加一条客户实际入住记录,包括:客户身份证编号、客户名、房间号、入住时间、退房时间、房费、前台操作员,然后修改客房状态为“空闲”;最后根据会员类别和入住天数计算房费。
(4) 预订客房。能够根据标准和日期查询客房空闲情况;能够为指定客户预订指定的客房,并记录预订开始时间、预订结束时间、联系人、联系电话、前台操作员、操作时间等信息。
(5) 预订查询。能够根据客户名或联系电话查询其预订的客房信息,其中,一个客户可以预订多个客房;能够根据楼层号、房间号查询客房的预订详细信息。
4.1 登录模块实现
4.1.1 界面设计
此界面实现了用户的登录功能。如图4-1登录界面所示。
图4-1登录界面
4.1.2登录功能实现
此界面主要实现了用户的登录功能。此部分代码文件:login.jsp,LoginServlet,UserDao.java,User.java
功能实现:通过login.jsp 的form表单提交到LoginServlet进行处理,再调用UserDao.java中方法实现登录验证.
1. login.js
<divid="loginAndRegisterForm">
<formmethod="post"id="loginForm">
<table>
<tr>
<thstyle="text-align:left;">用户名:</th>
<!-- class="easyui-textbox"表示使用EasyUI的textbox组件-->
<td><inputtype="text"id="userName"style="width:150px;" name="username"class="easyui-textbox"/></td> </tr>
<tr>
<thstyle="text-align:left;">密码:</th>
<td><inputtype="password"id="userPwd"style="width:150px;" name="password"class="easyui-passwordbox"/></td>
</tr>
<tr>
<thstyle="text-align:left;">用户类型:</th>
<td>
<selectname="usertype"class="easyui-textbox"id="option">
<optionvalue="1">前台操作员</option>
<optionvalue="2">系统管理员</option>
</select>
</td>
</tr>
</table>
</form>
</div>
2. LoginServlet.java
privatevoid login(HttpServletRequestrequest, HttpServletResponse response) throws IOException{String username = request.getParameter("username");
String password = request.getParameter("password");
String usertype = request.getParameter("usertype");
Json json = new Json();
User u = UserDao.getUserByName(username, password);
if(u!=null && u.getUsertype().equals(usertype)){request.getSession().setAttribute("currentUser",u);json.setMsg("登录成功");json.setSuccess(true);if(usertype.equals("1")){json.setUrl("/operator/index.jsp");}elseif(usertype.equals("2")){json.setUrl("/admin/index.jsp");}else{json.setUrl("/error.jsp");}
}else{json.setMsg("用户名或密码错误,登录失败!");json.setSuccess(false);
}
String jsonStr = JSON.toJSONString(json);//将json字符串作为响应内容输出到客户端浏览器。response.getWriter().write(jsonStr);
}
4.2客户入住模块实现
4.2.1 界面设计
此界面前台操作员处理客户入住。如:图4-2客户入住界面。
图4-2客户入住界面
图4-3客户入住界面
4.2.2 客户入住功能实现
该功能实现了前台操作员处理客户入住的功能。代码文件包括 bookList.jsp,BookServlet.java.
描述:通过bookList.jsp中的form表单向BookServlet.java进行处理.
1. booklist.jsp
<tableid="dg"title="客户入住"class="easyui-datagrid"fitColumns="true"pagination="true"
data-options="rownumbers:true,toolbar:'#tb'">
<thead>
<tr>
<thfield="cb"checkbox="true"align="center"></th>
<thfield="rno"width="50"align="center">房间号</th>
<thfield="fno"width="50"align="center">楼层号</th>
<thfield="standard"width="50"align="center">房间标准</th>
<thfield="cost"width="50"align="center">房间费用</th>
<thfield="position"width="50"align="center">地理位置</th>
</tr>
</thead>
</table>
<divid="tb">
<div><span> 房间标准: </span><selectid="standard"class="easyui-combobox"data-options="panelHeight:'auto'"style="width:150px;">
<optionvalue="">全部</option><optionvalue="大床房">大床房</option>
<optionvalue="标间">标间</option>
<optionvalue="豪华套房">豪华套房</option></select><span> 入住开始时间: </span>
<inputtype="text" class="easyui-datebox"id="btime"style="width:150px;">
<span> 入住结束时间: </span>
<inputtype="text" class="easyui-datebox" id="etime"style="width:150px;">
<ahref="javascript:searchRoom()"class="easyui-linkbutton"iconCls="icon-search"plain="true">搜索</a>
<ahref="javascript:openDialog()"class="easyui-linkbutton"iconCls="icon-edit"plain="true">入住</a>
<ahref="javascript:reload()"class="easyui-linkbutton"iconCls="icon-reload"plain="true">刷新</a>
</div>
</div>
<divid="dlg"class="easyui-dialog"style="width:400px; padding:10px 20px"
closed="true"buttons="#dlg-buttons">
<formid="fm"method="post">
<tablecellspacing="8px"><tr>
<td>房间号</td>
<td><inputname="rno"class="textbox" readonly="true">
</td>
</tr>
<tr>
<td>楼层号</td>
<td><inputname="fno"class="textbox"readonly="true">
</td>
</tr>
<tr>
<td>房间标准</td>
<td><inputname="standard"class="textbox"readonly="true">
</td>
</tr>
<tr>
<td>房间费用</td>
<td><inputname="cost"class="textbox"readonly="true">
</td>
</tr>
<tr>
<td>地理位置</td>
<td><inputname="position"class="textbox"readonly="true">
</td>
</tr><tr>
<td>身份证号</td>
<td><inputname="cid"class="easyui-validatebox"data-options="required:true">
</td>
</tr>
<tr>
<td>预付金</td>
<td><inputname="prepay"class="easyui-numberbox">
</td>
</tr>
</table>
</form>
</div><divid="dlg-buttons">
<div>
<ahref="javascript:saveStudent()"class="easyui-linkbutton"iconCls="icon-ok"plain="true">确认</a>
<ahref="javascript:closeStudentDialog()"class="easyui-linkbutton"iconCls="icon-cancel"plain="true">关闭</a>
</div>
</div>
3. BookServlet.java
privatevoid book(HttpServletRequest request, HttpServletResponse response) throws IOException{
String cid = request.getParameter("cid");
String btime = request.getParameter("btime");
String etime = request.getParameter("etime");
String rno = request.getParameter("rno");
doubleprepay = Double.parseDouble(request.getParameter("prepay"));
Json json = new Json();
User u = (User)request.getSession().getAttribute("currentUser");
intuserid = u.getUserid();
if(CustomerDao.getCustomer(cid) == null){json.setSuccess(false);json.setMsg("用户身份证号不存在,请先添加用户信息");
}else{
try {
BookDao.addBook(rno, cid, btime, userid, etime, prepay);
json.setSuccess(true);
json.setMsg("");
} catch (Exception e) {
// TODO Auto-generated catch blockjson.setSuccess(false);json.setMsg(e.getMessage());
e.printStackTrace();}
}String jsonStr = JSON.toJSONString(json);//将json字符串作为响应内容输出到客户端浏览器。response.getWriter().write(jsonStr);}
4.3退房管理模块实现
4.3.1 界面设计
此界面前台操作员处理客户退房管理。如:图4-4退房管理界面。
图4.4退房管理界面
4.3.2 退房管理功能实现
该功能实现了前台操作员处理客户入住的功能。代码文件包括 dropList.jsp,BookServlet.java.
描述:通过dropList.jsp中的form表单向BookServlet.java进行处理.
- dropList.jsp
<scripttype="text/javascript">function deleteRoom() {
var selectedRows = $("#dg").datagrid("getSelections");
if(selectedRows.length == 0) {
$.messager.alert("系统提示", "请选择要退房的房间");
return;
}
if(selectedRows.length != 1) {
$.messager.alert("系统提示", "请选择一个要退房的客房");
return;
}
var row = selectedRows[0];
$.messager.confirm("系统提示", "您确定退房么?", function(r) {
if(r) {$.post("${pageContext.request.contextPath}/BookServlet?action=search1",
{ rno:row.rno,cid:row.cid,btime:row.btime,etime:row.etime}, function(result){if(result.success) {
$.messager.alert("系统提示", result.msg);
searchRoom();
} else {
$.messager.alert("系统提示", "退房失败!");
}
}, "json");
}
});
}
function searchRoom() {
$.post("${pageContext.request.contextPath}/BookServlet?action=drop", {rno:$('#rno').val()
}, function(data, states) {
$("#dg").datagrid("loadData", data);
},"json");
}
function reload() {
searchRoom();
}
</script>
</head>
<bodystyle="margin: 1px; font-family: microsoft yahei">
<tableid="dg"title="退房管理"class="easyui-datagrid"fitColumns="true"pagination="true"
data-options="rownumbers:true,toolbar:'#tb'">
<thead>
<tr>
<thfield="cb"checkbox="true"align="center"></th>
<thfield="rno"width="50"align="center">房间号</th>
<thfield="fno"width="50"align="center">楼层号</th>
<thfield="standard"width="50"align="center">房间标准</th>
<thfield="cost"width="50"align="center">房间费用</th>
<thfield="position"width="50"align="center">地理位置</th>
<thfield="cid"width="50"align="center">身份证号</th>
<thfield="btime"width="50"align="center">入住时间</th>
<thfield="etime"width="50"align="center">退房时间</th>
</tr>
</thead>
</table>
<divid="tb">
<div><span> 房间号: </span><inputtype="text" class="easyui-textbox"id="rno"style="width:150px;">
<ahref="javascript:searchRoom()"class="easyui-linkbutton"iconCls="icon-search"plain="true">搜索</a>
<ahref="javascript:deleteRoom()"class="easyui-linkbutton"iconCls="icon-edit"plain="true">退房</a>
<ahref="javascript:reload()"class="easyui-linkbutton"iconCls="icon-reload"plain="true">刷新</a>
</div>
</div>
1. BookServlet.java
privatevoid drop(HttpServletRequest request, HttpServletResponse response) throws IOException{
String rno = request.getParameter("rno");
List<Map<String, String>> list = new ArrayList<Map<String,String>>();list = BookBpo.searchList(rno);
Object jsonArray = JSON.toJSON(list);
JSONObject result = new JSONObject();
result.put("rows", jsonArray);
result.put("total", list.size());
response.getWriter().print(result);
}privatevoid search1(HttpServletRequest request, HttpServletResponse response) throws IOException{
String cid = request.getParameter("cid");
String btime = request.getParameter("btime");
String etime = request.getParameter("etime");
String rno = request.getParameter("rno");
Json json = new Json();
User u = (User)request.getSession().getAttribute("currentUser");
intuserid = u.getUserid();
try {
BookBpo.dropBook(rno, cid, userid, btime, etime);
try{
History h = HistoryDao.getHistory(rno, cid, btime);
json.setSuccess(true);
json.setMsg("房间号:"+rno+"<br/>入住时间:"+btime+"<br/>退房时间:"+etime+"<br/>总费用:"+h.getSumpay());
}catch(Exception e){json.setSuccess(false);json.setMsg(e.getMessage());e.printStackTrace();
}} catch (Exception e) {
// TODO Auto-generated catch blockjson.setSuccess(false);json.setMsg(e.getMessage());e.printStackTrace();}String jsonStr = JSON.toJSONString(json);//将json字符串作为响应内容输出到客户端浏览器。response.getWriter().write(jsonStr);
}
4.4预订客房模块实现
4.4.1 界面设计
此界面前台操作员处理预定客户。如:图4-5预定客户界面。
图4-5预定客户界面
图4-6预定客户界面
4.4.2 预订客房功能实现
该功能实现了前台操作员处理预定客户的功能。代码文件包括该功能实现了前台操作员处理预定查询的功能。代码文件包括 advanceList.jsp,AdvanceServlet.java.
描述:通过advanceList.jsp中的form表单向AdvanceServlet.java进行处理.
- advanceList
<bodystyle="margin: 1px; font-family: microsoft yahei">
<tableid="dg"title="预定客房"class="easyui-datagrid"fitColumns="true"pagination="true"
data-options="rownumbers:true,toolbar:'#tb'">
<thead>
<tr>
<thfield="cb"checkbox="true"align="center"></th>
<thfield="rno"width="50"align="center">房间号</th>
<thfield="fno"width="50"align="center">楼层号</th>
<thfield="standard"width="50"align="center">房间标准</th>
<thfield="cost"width="50"align="center">房间费用</th>
<thfield="position"width="50"align="center">地理位置</th>
</tr>
</thead>
</table>
<divid="tb">
<div><span> 房间标准: </span><selectid="standard"class="easyui-combobox"data-options="panelHeight:'auto'"style="width:150px;">
<optionvalue="">全部</option>
<optionvalue="大床房">大床房</option>
<optionvalue="标间">标间</option>
<optionvalue="豪华套房">豪华套房</option></select><span> 预订开始时间: </span>
<inputtype="text" class="easyui-datebox"id="btime"style="width:150px;">
<span> 预订结束时间: </span>
<inputtype="text" class="easyui-datebox" id="etime"style="width:150px;">
<ahref="javascript:searchRoom()"class="easyui-linkbutton"iconCls="icon-search"plain="true">搜索</a>
<ahref="javascript:openDialog()"class="easyui-linkbutton"iconCls="icon-edit"plain="true">预定</a>
<ahref="javascript:reload()"class="easyui-linkbutton"iconCls="icon-reload"plain="true">刷新</a>
</div>
</div>
<divid="dlg"class="easyui-dialog"style="width:400px; padding:10px 20px"
closed="true"buttons="#dlg-buttons">
<formid="fm"method="post">
<tablecellspacing="8px"><tr>
<td>房间号</td>
<td><inputname="rno"class="textbox" readonly="true">
</td>
</tr>
<tr>
<td>楼层号</td>
<td><inputname="fno"class="textbox"readonly="true">
</td>
</tr>
<tr>
<td>房间标准</td>
<td><inputname="standard"class="textbox"readonly="true">
</td>
</tr>
<tr>
<td>房间费用</td>
<td><inputname="cost"class="textbox"readonly="true">
</td>
</tr>
<tr>
<td>地理位置</td>
<td><inputname="position"class="textbox"readonly="true">
</td>
</tr>
<tr>
<td>预定人</td>
<td><inputname="person"class="easyui-validatebox"data-options="required:true">
</td>
</tr>
<tr>
<td>预定人电话</td>
<td><inputname="phone"class="easyui-validatebox"data-options="required:true">
</td>
</tr>
</table>
</form>
</div><divid="dlg-buttons">
<div>
<ahref="javascript:saveStudent()"class="easyui-linkbutton"iconCls="icon-ok"plain="true">确认</a>
<ahref="javascript:closeStudentDialog()"class="easyui-linkbutton"iconCls="icon-cancel"plain="true">关闭</a>
</div>
</div>
- AdvanceServlet.java
privatevoid advance(HttpServletRequest request, HttpServletResponse response) throws IOException{
String rno = request.getParameter("rno");
String btime = request.getParameter("btime");
String etime = request.getParameter("etime");
String phone = request.getParameter("phone");
String person = request.getParameter("person");
Json json = new Json();
User u = (User)request.getSession().getAttribute("currentUser");
intuserid = u.getUserid();
try {
AdvanceDao.addAdvance(rno, phone, btime, userid, etime, person);
json.setSuccess(true);
json.setMsg("");} catch (Exception e) {
// TODO Auto-generated catch blockjson.setSuccess(false);json.setMsg(e.getMessage());
e.printStackTrace();}String jsonStr = JSON.toJSONString(json);//将json字符串作为响应内容输出到客户端浏览器。response.getWriter().write(jsonStr);}
4.5.1 界面设计
此界面前台操作员根据时间查询客房预定的客房。如:图4-7预定查询界面。
图4-7预定客户界面
图4-8预定客户界面
4.5.2 预定查询功能实现
该功能实现了前台操作员处理预定查询的功能。代码文件包括 advanceList.jsp,AdvanceServlet.java.
描述:通过advanceList.jsp中的form表单向AdvanceServlet.java进行处理.
1. advanceList.jsp
<bodystyle="margin: 1px; font-family: microsoft yahei">
<tableid="dg"title="预定查询"class="easyui-datagrid"fitColumns="true"pagination="true"
data-options="rownumbers:true,toolbar:'#tb'">
<thead>
<tr>
<thfield="cb"checkbox="true"align="center"></th>
<thfield="rno"width="50"align="center">房间号</th>
<thfield="fno"width="50"align="center">楼层号</th>
<thfield="standard"width="50"align="center">房间标准</th>
<thfield="cost"width="50"align="center">房间费用</th>
<thfield="position"width="50"align="center">地理位置</th>
<thfield="person"width="50"align="center">客户名</th>
<thfield="phone"width="50"align="center">联系电话</th>
<thfield="btime"width="50"align="center">预订开始时间</th>
<thfield="etime"width="50"align="center">预订结束时间</th>
</tr>
</thead>
</table>
<divid="tb">
<div><span> 客户名: </span><inputtype="text" class="easyui-textbox"id="person"style="width:150px;"><span> 客户电话: </span><inputtype="text" class="easyui-textbox"id="phone"style="width:150px;">
<ahref="javascript:searchRoom()"class="easyui-linkbutton"iconCls="icon-search"plain="true">搜索</a>
<ahref="javascript:openDialog()"class="easyui-linkbutton"iconCls="icon-edit"plain="true">入住</a>
<ahref="javascript:reload()"class="easyui-linkbutton"iconCls="icon-reload"plain="true">刷新</a>
</div>
</div>
<divid="dlg"class="easyui-dialog"style="width:400px; padding:10px 20px"
closed="true"buttons="#dlg-buttons">
<formid="fm"method="post">
<tablecellspacing="8px"><tr>
<td>房间号</td>
<td><inputname="rno"class="textbox" readonly="true">
</td>
</tr>
<tr>
<td>入住时间</td>
<td><inputname="btime" class="textbox" readonly="true">
</td>
</tr>
<tr>
<td>退房时间</td>
<td><inputname="etime" class="textbox" readonly="true">
</td>
</tr><tr>
<td>客户名</td>
<td><inputname="person"class="textbox" readonly="true">
</td>
</tr><tr>
<td>电话</td>
<td><inputname="phone"class="textbox" readonly="true">
</td>
</tr>
<tr>
<td>身份证号</td>
<td><inputname="cid"class="easyui-validatebox"data-options="required:true">
</td>
</tr>
<tr>
<td>预付金</td>
<td><inputname="prepay"class="easyui-numberbox">
</td>
</tr>
</table>
</form>
</div><divid="dlg-buttons">
<div>
<ahref="javascript:saveStudent()"class="easyui-linkbutton"iconCls="icon-ok"plain="true">确认</a>
<ahref="javascript:closeStudentDialog()"class="easyui-linkbutton"iconCls="icon-cancel"plain="true">关闭</a>
</div>
</div>
2. AdvanceServlet.java
privatevoid search(HttpServletRequest request, HttpServletResponse response) throws IOException{
String standard = request.getParameter("standard");
String btime = request.getParameter("btime");
String etime = request.getParameter("etime");
List<Map<String, String>> list = new ArrayList<Map<String,String>>();list = AdvanceBpo.selectList(standard, btime, etime);
Object jsonArray = JSON.toJSON(list);
JSONObject result = new JSONObject();
result.put("rows", jsonArray);
result.put("total", list.size());
response.getWriter().print(result);
}
publicstatic List<Room> roomAdanvce(String standard,String btime,String etime){
EntityManager em = EntityManagerUtil.getEntityManager();
String sql = null;
if(standard.equals("") || standard == null){sql = "SELECT * FROM room r WHERE r.rno not in (SELECT rno from advance a WHERE a.btime between '"+btime+"' and '"+etime+"' UNION SELECT rno from book b WHERE b.btime between '"+btime+"' and '"+etime+"')";
}else{ sql = "SELECT * FROM room r WHERE r.rno not in (SELECT rno from advance a WHERE a.btime between '"+btime+"' and '"+etime+"' UNION SELECT rno from book b WHERE b.btime between '"+btime+"' and '"+etime+"') and r.standard='"+standard+"'";}
Query query=em.createNativeQuery(sql, Room.class);
List<Room> Rooms = query.getResultList();
em.close();
returnRooms;
}publicstatic List<Map<String,String>> selectList(String standard,String btime,String etime){
List<Map<String,String>> tt = new ArrayList<Map<String,String>>();
List<Room> Rooms = roomAdanvce(standard, btime, etime);
Map<String,String> cc = null;
for (Room user: Rooms) {cc = new HashMap<String,String>();cc.put("rno", user.getRno());cc.put("fno", user.getFno());cc.put("standard", user.getStandard());cc.put("cost", String.valueOf(user.getCost()));cc.put("position", user.getPosition());tt.add(cc);
}
returntt;
}
5 总结
通过本次课程设计使我进一步熟练掌握了JavaWeb开发的流程,增加了团队之间的合作。在运行程序过程中404错误,经过检查后不是路径问题的错误,在重新安装Tomcat后并不起作用,经过请教老师发现,是在web.xml中配置有问题,多写了一个斜杠,通过本次的经验教训使我明白细心的重要性。
参考文献
[1] 萨师煊, 王珊. 数据库系统概论[M].北京:高等教育出版社,2006.
[2] 计磊.精通J2EE整合应用案例[M].北京:人民邮电出版社,2006
[3] 王红.Java Web应用开发技术应用.北京:电子工业出版社,2009
[4] 孙卫琴.Java Web 开发技术详解[M].北京:电子工业出版社,2009
[5] 唐有国.Jsp网站开发详解[M].北京:清华大学出版社,2010
[6]刘卫宏.Eclipse使用教程[M].科学出版社,2007
[7]王珊,陈红.数据库原理教程[M].清华大学出版社,2009
[8]施伯乐,Tomcat和Java web详解[M].科学出版社,2008
[9]封超,Java Web 应用开发[M].人民邮电出版社,2009
[10]吴忠福,数据库设计结构探讨[M].科学出版社,2007
相关文章:
基于javaEE+jqueryEasyUi+eclipseLink+MySQL的课程设计客房管理信息系统
1. 系统概述 1.1 系统功能概述 1)客户管理。能够增加一个客户,包括:身份证号、客户名称、出生年月、性别、联系电话、邮箱、会员类别等信息,默认会员类别为空;能够修改和删除客户信息;能够根据客户名称、联系电话查询…...
3款本周高潜力开源AI工具(多模态集成_隐私本地化)
本周聚焦 AI 技术领域,为开发者精选 3 款兼具创新性与实用性的开源项目。这些项目覆盖图像生成、智能助手、大语言模型框架等方向,通过技术突破解决开发痛点,助力开发者高效构建智能应用。 更多精彩科技推荐请点击->:更多精彩科…...
第一期第10讲
Linux常用的压缩文件扩展名有 .tar, .tar.bz2, .tar.gz 使用gzip压缩和解压缩 对单个文件压缩: gzip a.c //压缩a.c为a.c.gz gzip -d a.c.gz //解压缩为a.c 对文件夹压缩: gzip -r test //对test文件夹里的文件进行压缩,不对test进行压缩…...
计算方法在单细胞数据分析中的应用及AI拓展
单细胞技术的出现彻底革新了我们对生物系统的理解,揭示了看似同质的细胞群体内部复杂的异质性。为了从这些技术产生的大量复杂数据中提取有意义的见解,精密的计算方法是不可或缺的。 AI拓展 单细胞数据分析的核心在于处理和解释高维度数据的能力&#…...
如何配置环境变量HADOOP_HOMEM、AVEN_HOME?不配置会怎么样
以下是在不同操作系统中配置 HADOOP_HOME 和 JAVA_HOME 环境变量的方法,以及不配置可能产生的后果: 配置 HADOOP_HOME - Windows系统:下载并解压Hadoop安装包,然后右键“此电脑”,选择“属性”,点击“高级…...
【现代深度学习技术】循环神经网络03:语言模型和数据集
【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈PyTorch深度学习 ⌋ ⌋ ⌋ 深度学习 (DL, Deep Learning) 特指基于深层神经网络模型和方法的机器学习。它是在统计机器学习、人工神经网络等算法模型基础上,结合当代大数据和大算力的发展而发展出来的。深度学习最重…...
【学习笔记】Taming 3DGS泛读
原文链接:https://arxiv.org/abs/2406.15643 代码链接:https://github.com/nullptr81/3dgs-accel 一、学习内容 1.研究背景 3DGS在新视角合成(NVS)中表现优异,但优化过程低效: 存在 1)资源需…...
SAP系统交货已完成标识
问题:交货已完成标识 现象:采购订单一直处于未完成交货状态,及交货完成标识处于非勾选状态 原因:采购订单交货完成标识勾会在两种情况下勾选, a.交货数量在容差范围内; b.手动勾选。 某些特殊情况…...
【正点原子STM32MP257连载】第四章 ATK-DLMP257B功能测试——音频测试 #ES8388 #录音测试
1)实验平台:正点原子ATK-DLMP257B开发板 2)浏览产品:https://www.alientek.com/Product_Details/135.html 3)全套实验源码手册视频下载:正点原子资料下载中心 文章目录 第四章 ATK-DLMP257B功能测试——音频…...
WPF 使用 DI EF CORE SQLITE
WPF 使用 DI EF CORE SQLITE 1.安装 nuget包 <PackageReference Include"Microsoft.EntityFrameworkCore.Sqlite" Version"9.0.4" />2.创建DbContext的实现类,创建有参构造函数 public XXContext(DbContextOptions<XXXContext> o…...
探索鸿蒙沉浸式:打造无界交互体验
一、鸿蒙沉浸式简介 在鸿蒙系统中,沉浸式是一种极具特色的设计理念,它致力于让用户在使用应用时能够全身心投入到内容本身,而尽可能减少被系统界面元素的干扰。通常来说,就是将应用的内容区巧妙地延伸到状态栏和导航栏所在的界面…...
Linux红帽:RHCSA认证知识讲解(十 三)在serverb上破解root密码
Linux红帽:RHCSA认证知识讲解(十 三)在serverb上破解root密码 前言操作步骤 前言 在红帽 Linux 系统的管理工作中,系统管理员可能会遇到需要重置 root 密码的情况。本文将详细介绍如何通过救援模式进入系统并重新设置 root 密码。…...
【网络安全】谁入侵了我的调制解调器?(一)
文章目录 我被黑了159.65.76.209,你是谁?黑客攻击黑客?交出证据三年后我被黑了 两年前,在我家里使用家庭网络远程办公时,遇到了一件非常诡异的事情。当时,我正在利用一个“盲 XXE 漏洞”,这个漏洞需要借助一个外部 HTTP 服务器来“走私”文件。为了实现这一点,我在 AW…...
阿里一面:Nacos配置中心交互模型是 push 还是 pull ?(原理+源码分析)
对于Nacos大家应该都不太陌生,出身阿里名声在外,能做动态服务发现、配置管理,非常好用的一个工具。然而这样的技术用的人越多面试被问的概率也就越大,如果只停留在使用层面,那面试可能要吃大亏。 比如我们今天要讨论的…...
MySQL 慢查询日志深入分析与工具实战(mysqldumpslow pt-query-digest)
🎯 学习目标 • ✅ 熟悉慢查询日志结构与核心字段 • ✅ 掌握日志开启与 SQL 记录机制 • ✅ 使用 pt-query-digest 工具进行分析 • ✅ 解读分析结果并提出优化建议 📂 基本概念 项目 内容说明 功能 记录执行时间超过阈值的 SQL 启动参数…...
JVM:垃圾回收
一、垃圾回收概述 (1)垃圾回收主要解决的问题 内存溢出:当程序在运行过程中,所需的内存超出了 JVM 被分配到的内存空间时,就会发生内存溢出。垃圾回收会将不再被引用的对象进行回收,释放内存空间…...
与AI深度融合的Go开发框架sponge,解决使用cursor、trae等AI辅助编程工具开发项目时的部分痛点
摘要 AI 编程助手在近几年快速发展,帮助开发者提升了开发效率。然而,通用 AI 工具往往难以精准落地到具体业务与框架中。本文介绍了一款与 Go 框架深度融合的 AI 编程工具 —— sponge AI 助手。它不仅理解框架的结构,还能按照标准化流程自动…...
《AI大模型应知应会100篇》第21篇:Prompt设计原则:让大模型精准理解你的需求
第21篇:Prompt设计原则:让大模型精准理解你的需求 摘要 在与大模型交互时,如何高效地表达需求是决定输出质量的关键。本文将系统介绍高效Prompt设计的核心原则和方法论,并通过实战代码案例详细解释每个核心知识点,帮助…...
【更新完毕】2025泰迪杯数据挖掘竞赛A题数学建模思路代码文章教学:竞赛论文初步筛选系统
完整内容请看文末最后的推广群 基于自然语言处理的竞赛论文初步筛选系统 基于多模态分析的竞赛论文自动筛选与重复检测模型 摘要 随着大学生竞赛规模的不断扩大,参赛论文的数量激增,传统的人工筛选方法面临着工作量大、效率低且容易出错的问题。因此&…...
[Windows] 电脑自动备份插入的U盘数据
[Windows] 电脑自动备份U盘数据 链接:https://pan.xunlei.com/s/VONyazSEIqhnzZCHRlio9Vw2A1?pwdcmhc# [Windows] 电脑自动备份插入的U盘数据...
《JVM考古现场(二十一):奇点黎明·在事件视界编译时空曲率》
目录 楔子:事件视界警报 上卷时空曲率引擎 第一章:volatile场方程重构 第二章:synchronized黑洞能层 番外篇:时空涟漪观测站 中卷量子逃逸分析 第三章:柯西视界稳定性证明 第四章:白洞负熵连接 实战…...
list的一些常用接口
其实list的接口和前面的string和vector基本都是一样的,用法也基本类似,我们还是挑几个讲讲吧。 一.常用的接口 1.1 push_back 图中是一个空参构造加上一个push_back的使用,这两个接口的使用还是很简单的,看一下即可。下面是迭代器…...
芯洲SCT2434AQFPAR:3.6V-36V Vin, 3.5A, 高效率同步降压DCDC转换器
特性: AEC-Q100合格,结果如下:-器件温度等级1:-40C至125C环境工作温度范围宽输入电压范围:3.6V-36V持续输出电流3.5A 1V1%反馈参考电压集成60mΩ高侧功率MOSFET和36mΩ低侧功率MOSFET轻载PSM工作模式在睡眠模式下具有…...
单例模式:懒汉和饿汉
目录 一、关于设计模式 二、单例模式是什么 2.1 饿汉模式 2.2 懒汉模式 三、单例模式和多线程 3.1 饿汉模式 3.2 懒汉模式 一、关于设计模式 单例模式是一种设计模式,说它之前先来聊聊设计模式是什么。 设计模式,类似于于棋谱(大佬把…...
第八节:React HooksReact 18+新特性-React Server Components (RSC) 工作原理
• 与SSR区别:零客户端JS、服务端数据直出 • 搭配Next.js 14使用场景 React Server Components (RSC) 工作原理及 Next.js 14 应用场景解析 一、RSC 核心工作原理 React Server Components (RSC) 是 React 18 引入的颠覆性特性,其设计目标是 服务端与…...
Spark-SQL核心编程3
数据加载与保存 通用方式: SparkSQL 提供了通用的保存数据和数据加载的方式。这里的通用指的是使用相同的API,根据不同的参数读取和保存不同格式的数据,SparkSQL 默认读取和保存的文件格式为parquet 数据加载方法: spark.read.lo…...
利用XShell 创建隧道(tunnel)在本地可视化远程服务器上的Visdom
1. 创建隧道 打开Xshell,选择你想要操作的终端,单击右键 -> 选择属性 打开属性对话框后,单击添加按钮。 在弹出的对话框中,先填写自己本地的浏览器的地址以及对应的端口号。然后呢,再填写autod远程服务器的地址和…...
React 高级特性与最佳实践
在掌握了 React 的基础知识后,我们可以进一步探索 React 的高级特性和最佳实践。这些特性将帮助你构建更高效、可维护和可扩展的 React 应用。本文重点介绍 Hooks、Context、Refs 和高阶组件等核心高级特性。 1. Hooks:函数组件的强大工具 Hooks 是 Rea…...
考研数据结构之图(一)(包含真题及解析)
考研数据结构之图的存储与基本操作:邻接矩阵、邻接表、十字链表、邻接多重表 图(Graph)是数据结构中的重要非线性结构,广泛应用于网络路由、社交关系分析等领域。本文将详细讲解图的四种主要存储方式——邻接矩阵法、邻接表法、十…...
Qt QML实现Windows桌面颜色提取器
前言 实现一个简单的小工具,使用Qt QML实现Windows桌面颜色提取器,实时显示鼠标移动位置的颜色值,包括十六进制值和RGB值。该功能在实际应用中比较常见,比如截图的时候,鼠标移动就会在鼠标位置实时显示坐标和颜色值&a…...
2025 年网络安全的挑战与机遇
2024 年是网络安全领域风云变幻的一年。从备受瞩目的勒索软件攻击所带来的影响,到人工智能工具日益商品化,挑战不断增加。 关键基础设施的漏洞变得极为明显,身份盗窃次数也达到了前所未有的程度。然而,在这一片混乱之中ÿ…...
Vue 3 中 ref和reactive的详细使用场景
一、核心区别 特性refreactive数据类型基本类型 对象/数组(自动解包)仅对象/数组响应式原理通过 .value 触发响应直接代理对象模板中使用自动解包(无需 .value)直接访问属性解构/传递保持响应性需用 toRefs 保持响应性 二、使用…...
react使用createFromIconfontCN,自定义iconfont 图标
记录reactantdesign项目中使用createFromIconfontCN,自定义iconfont 图标 效果图: import { createFromIconfontCN } from ant-design/icons;const MyIcon createFromIconfontCN({scriptUrl: //at.alicdn.com/t/font_8d5l8fzk5b87iudi.js, // 在 icon…...
危化品经营单位安全生产管理人员备考要点
危化品经营单位安全生产管理人员备考要点 📌 考试核心内容 ✅ 必考法规: 《危险化学品安全管理条例》重点条款(如经营许可条件) GB 18218-2018《重大危险源辨识》新标准 安全生产法律责任(罚款金额/刑事责任&…...
音频炼金术:Threejs 让 3D 场景「听」起来更真实
在 Three.js 中允许在场景中添加声音,将声音与 3D 对象关联,实现更丰富的交互体验。 Audio Three.js 中的Audio对象用于表示音频源,它是一个THREE.Object3D的子类,用于控制音频播放、暂停、是否循环等设置的对象,可以…...
【C++】Stack和Queue的底层封装和实现
目录 stack容器适配器stack的模拟实现 queue的模拟实现deque了解deque的结构deque的管理方式和遍历元素方式deque的缺陷为啥库里面的stack和queue使用deque end stack 容器适配器 Stack可以封装成前面三个变量的形式,但是这里我们提出一个概念叫容器适配器…...
Vue3 SSR 工程化实践:日常工作中的性能优化与实战技巧
一、流式渲染与分块传输(面向性能的关键优化) 1.1 流式响应基础实现 // Node.js Express 示例(Vite SSR同理)import { renderToWebStream } from vue/server-rendererapp.get(/, async (req, res) > { res.setHeader(Conten…...
【Python进阶】字符串操作全解与高效应用
目录 前言:技术背景与价值当前技术痛点解决方案概述目标读者说明 一、技术原理剖析核心概念图解核心作用讲解关键技术模块技术选型对比 二、实战演示环境配置要求核心代码实现(10个案例)案例1:基础操作案例2:高效格式化…...
LeetCode[28]找出字符串中第一个匹配项的下标(KMP版本)
思路: 一开始我使用暴力过的,但是感觉还是不完美,想学习一下KMP的写法,所以这篇笔记就来了,首先KMP算法就要先维护一个最长相等前后缀的一个数组(统称前缀表),那么这个数组为什么能找…...
Cesium实现雨、闪电、雪、雾天气效果
基于 Cesium 的三维地理信息场景,集成了天气效果后处理、3D 模型加载、水域渲染等功能。以下是详细功能总结: 1. 场景初始化与基础配置 三维地球初始化 创建 Cesium Viewer 实例,隐藏默认控件(时间轴、动画控件等)&…...
上门送水小程序区域代理模块框架设计
一、逻辑分析 代理申请流程: 潜在代理商通过小程序提交代理申请,需要填写个人或企业基本信息、联系方式、期望代理区域等。系统收到申请后,进行初步审核,检查信息的完整性和合规性。运营人员进行人工审核,根据公司政策…...
GIS开发笔记(6)结合osg及osgEarth实现半球形区域绘制
一、实现效果 输入中心点坐标及半径,绘制半球形区域,地下部分不显示。 二、实现原理 根据中心点及半径绘制半球形区域,将其挂接到地球节点。 三、参考代码 void GlobeWidget::drawSphericalRegion(osg::Vec3d point,double radius) {// 使…...
UE5在场景3D物体上播放本地视频(带声音)
UE5在场景3D物体上播放本地视频(带声音) 0.在Map中创建一个立方体,调整大小看起来像屏幕一样 1.创建文件夹Movies在根目录下 2.把准备的视频复制到Movies文件夹下 3.把Movies文件夹下的视频拖入到UE自己创建的文件夹下,此时会有个文件媒体源…...
安装部署RabbitMQ
一、RabbitMQ安装部署 1、下载epel源 2、安装RabbitMQ 3、启动RabbitMQ web管理界面 启用插件 rabbitmq数据目录 创建rabbitmq用户 设置为管理员角色 给用户赋予权限 4、访问rabbitmq...
STM32启动流程详解
STM32启动流程详解 本文档详细介绍STM32微控制器从上电到main函数执行的完整启动流程。 1. 上电与复位过程 当STM32芯片上电或复位时,硬件会执行以下步骤: 上电复位(POR)/低电平复位(PDR): 芯片接通电源或NRST引脚置低时触发初始PC值设置: 程序计数器…...
【正点原子STM32MP257连载】第四章 ATK-DLMP257B功能测试——CPU温度CPU主频
1)实验平台:正点原子ATK-DLMP257B开发板 2)浏览产品:https://www.alientek.com/Product_Details/135.html 3)全套实验源码手册视频下载:正点原子资料下载中心 第四章 ATK-DLMP257B功能测试——CPU主频&…...
LVDS系列8:Xilinx 7系可编程输入延迟(一)
在解析LVDS信号时,十分重要的一环就是LVDS输入信号线在经过PCB输入到FPGA中后,本来该严格对齐的信号线会出现时延,所以需要在FPGA内部对其进行延时对齐后再进行解析。 Xilinx 7系器件中用于输入信号延时的组件为IDELAYE2可编程原语࿰…...
iotdb时序数据库使用
iotdb https://github.com/apache/iotdb.git 安装maven3.9.6以上版本执行编译 iotdb启动,使用安装包sbin目录下的start-standalone.bat sbin\start-standalone.bat 执行报错如果是内存问题,可以在对应的node配置中修改,如conf\datanode-ev…...
【Caddy】:现代化、自动 HTTPS 的 Web 服务器新星
🚀 Caddy:现代化、自动 HTTPS 的 Web 服务器新星! 在构建和部署 Web 应用时,你可能听说过或用过如 Nginx、Apache 等经典的 Web 服务器。但在今天,有一个越来越受欢迎的新选择——Caddy。 本文将带你认识 Caddy&…...
用 DeepSeek 精准解析,PDF 一键转电子书!
经常需要阅读大量的 PDF 文档,但在移动设备上阅读 PDF 通常体验极差。屏幕小、排版固定,需要不断放大缩小,眼睛容易疲劳,长时间阅读简直是一种折磨。 虽有不少 PDF 转换工具,但对扫描书籍支持不佳,经常丢失…...