书店管理系统(Servlet+MySQL)
这个工程主要是对之前的一些总结吧,尽可能地用上所学的所有功能来实现,具体代码稍后也会上传到Github上。
在前端上并没有用上CSS等技术,只用上了基础的HTML和部分JavaScript,这是因为这一篇文章注重于功能的具体实现而不是美观。在美观方面,我更倾向于在完成所有的工作之后,再一点点优化。而且我对于CSS的了解也不是很深,就不在这里献丑了。
这个小练习应用的主要技术是Servlet,当然还有与Servlet紧密结合,密不可分的JSP,MySQL只涉及最基础的语法和应用,而且为了方便操作,我主要是使用DBeaver客户端对MySQL进行操作,这样的操作大大提升了效率,而且更为直观。
其他工具是EclipseEE(2021.9)+JDK14+Tomcat9.0。Tomcat10.0以后的版本变化太大,和我从图书馆借来的教材区别过多,所以没有采用最新的技术。
总体上是跟着教材<电子工业出版社>出版的《JavaWeb程序设计》的设计思路,这本书的作者是张磊和丁香乾老师。这本教材给我的感受颇深,尤其要感谢这两位老师。
1.数据库设计
建立一个数据库bookshop,数据库中实现两个表,表中的数据分别如下
表1:主要用于实现用户的登录和注册(名字主键)
表2:实现图书的信息输入,是系统的主体部分,主要实现图书的展示,线上的下单,还有后台的处理.

2.先实现数据库连接,JDBC的基石,DAO类
"D:\Friedrich Hsing’s Documents\JDBC配置文件\数据库操作类(实现).txt"
我把这个文件的代码复制了一份,放置在这个地址下,方便之后取用。
数据库相关的代码放置在包com.db中。包括DAO,UserDao及其BookDao
主要实现四个方法
这些方法的具体运行原理并不重要,重要的是应用并根据这个文件写出个性化配置的数据库连接类
public Connection getConn(String server, String dbname, String user, String pwd)
这个方法实现数据库和程序之间的关系
这些参数的内容都将在web.xml文件中进行声明,
key value在JDBC类中通过
ServletContext ctx=this.getServletContext(); String value=ctx.getInitParameter("key");这两句代码实现,实现将这些信息传递到JDBC类的代码中。
public int executeUpdate(String prepareSql, String[] param)
实现数据的删改增操作,其中prepareSql指的是SQL语法,param数组指的是替换掉SQL语句中的“?”字符
返回一个int数据,executeUpdate 的返回值是一个整数,指示受影响的行数。
一般返回数字>0时,我们默认为操作成功
public ResultSet executeQuery(String preparedSql, String[] param)
实现数据的查询,返回这个数据库查询中的结果。
public void closeAll()
资源释放
至此,完成了数据库连接类,下面开始进行第一个功能的实现
3.注册与登录功能实现
第一步,实现对象封装:User类
主要参数:对应数据库userdetail的属性一一对应,再实现getting方法和setting方法。
第二步,实现数据库连接类个性化配置,UserDao类
UserDao类实现对DAO类的继承extends。在这个基础上,先构思一下UserDao具体操作的流程和功能。
注意所有操作的逻辑归根两个:删改增+查找
- 添加新用户
- 通过名字查找用户所有信息
- 通过确认名字删除用户
- 更改已注册用户信息
- 获得所有用户数据
注意:所有的方法都要记得最后实现closeAll资源关闭,推荐使用try-catch-finally结构最后实现closeAll
实现功能1:添加新用户
对应方法:public boolean AddUser(User user)
SQL指令:INSERT INTO userdetail(username,userpass,role,regtime)values(?,?,?,?)
具体步骤:this.executeUpdate(sql, new String[] {user.getUsername(), user.getUserpass(),""+ user.getRole(), user.getRegtime()});
前面的sql代表SQL指令,后面的数组将具体的值(value)取代前面的“?”字符实现机器识别的SQL指令。然后连接数据库实现具体功能。
注意:String与String数据之间用“,”隔开,但是int数据前需要添加""+结构才可以被识别
实现功能2:查找用户
对应方法:public User getUserByName(String name)
SQL指令:SELECT * FROM userdetail WHERE username=?
具体步骤:ResultSet rs=this.executeQuery(sql, new String[] {name});
rs是Java中的通用结果集,需要通过方法getString或者getInt转换成通用数据结构,再将这些数据进行封装,得到一个User对象user
要点:数据类型转化+数据封装
最后将这个user返回。
实现功能3:删除用户
原理基本和新增一样,就是SQL指令要修改一下
对应方法:public boolean delUser(String name)
SQL指令:DELETE FROM userdetail WHERE username=?
具体步骤:this.executeUpdate(sql, new String[] {name});
实现功能4:修改用户信息
(通过名字先获得用户初始信息)
对应方法:public boolean editUser(User user)
对应指令:UPDATE userdetail SET userpass=?,role=?,regtime=?,lognum=?WHERE username=?
具体步骤:this.executeUpdate(sql, new String[] {user.getUsername(), user.getUserpass(), ""+user.getRole(),user.getRegtime()});
注意:这里的”?“与param数组的参数不是一一对应的了,而是存在一定的顺序。名字(获取信息的来源)是放在第一位的
由于总体上的设计,我认为通过姓名实现对用户的查找是比较科学的(其实还可以通过ID账号,但是这只是个联系,实验的范围原则上不会太大),所以再数据库的设计上,我就实现了设置名字为表主键操作逻辑。
返回所有用户的操作逻辑和后面书籍操作一致,所以一并放在后面写。
那现在,第一个功能的数据库设置基本告一段落,现在马上进行Servlet的编写和配置
第三步,在Servlet之前,先写一个拦截器,实现一些基础设置
这个系统中有很多的Servlet文件,所以写一个拦截器实现一些重叠的功能。典型的就是设置response和request的字符类型为UTF-8的操作。这样的操作基本上每一个Servlet文件都需要应用到,一个一个的写效率太过低下,所以统一写一个拦截器效果比较好。
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// TODO Auto-generated method stub
// place your code here
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html; charset=utf-8");
// pass the request along the filter chain
chain.doFilter(request, response);
}
放置在包com.filter中,这个包主要放置拦截器。
第四步,Servlet+JSP实现注册功能
1.Servlet设计
实现注册,主要用的就是数据库插入信息的功能。所以要注意import定制的数据库操作类
实现应用数据库操作类主要分成几个步骤
- 从web.xml得到包括数据库的服务器+数据库名+用户名+用户密码//具体使用数据库哪个数据表通常通过使用具体的DAO类中的SQL语法实现的
- 从request中获取需要的参数,并封装出一个User类
- 实现连接数据库的
getConn方法 - 实现连接数据库类的
AddUser方法
以下是主要doGet方法实现
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
System.out.println("连接servlet成功!");
PrintWriter out=response.getWriter();
String username=request.getParameter("username");
String pwd=request.getParameter("password");
String role=request.getParameter("role");
Date curtime=new Date();
SimpleDateFormat dateFormat=new SimpleDateFormat("yyyyy-MM-dd hh:mm:ss");
String regtime=dateFormat.format(curtime);
User user=new User();
user.setUsername(username);
user.setUserpass(pwd);
user.setRegtime(role);
user.setRegtime(regtime);
ServletContext ctx=this.getServletContext();
String server=ctx.getInitParameter("server");
String dbname=ctx.getInitParameter("dbname");
String dbuser=ctx.getInitParameter("user");
String dbpwd=ctx.getInitParameter("pwd");
UserDao dao=new UserDao();
try {
dao.getConn(server, dbname, dbuser, dbpwd);
if(dao.AddUser(user)){
out.println("Add user successed!");
}else {
out.println("Fuck! failed again!");
}
}catch(ClassNotFoundException e) {
e.printStackTrace();
}catch(Exception e) {
e.printStackTrace();
}
}
2.JSP设计
几个设计上的注意要点吧。
- 表单注意和Servlet紧密结合设计,action参数的设置。表单id为regist,表单name为adduserpage。
- 用户类型原则上分成两类:普通用户和管理员。这一对应数据库中的role(权限)参数,数据类型为int。所以我们设计一个选项框
用户类型:<input type="radio" name="role" value="0" checked>普通用户 `
<input type="radio" name="role" value="1">管理员
3.初次之外,在提交之前设计一个JavaScript程序用于判断输入信息是否正常。
<input type="button" value="一键提交" onclick="MyChecked()">
对应的JavaScript程序如下:
将html中的表单传入JavaScript进行判断,如果出现问题再使用alert弹窗。再JavaScript进行提交submit()操作。
技术上的重点在于对document.表单(.参数).操作格式的应用
<script type="text/javascript">
function MyChecked()
{
var id= document.adduserpage.username.value;
var pwd= document.adduserpage.password.value;
var repwd=document.adduserpage.repassword.value;
if(id==null||id=="")
alert("您的用户名不能为空!");
else if(pwd==null||pwd=="")
alert("您的密码设置不能为空!");
else if(repwd==null||repwd=="")
alert("请输入确认密码");
else if(pwd!=repwd)
alert("确认密码与初始密码不同!");
else
document.adduserpage.submit();
}
</script>
顺手又写了一个一键重置,对应代码如下
<input type="button" value="一键重置" onclick="reSet()">
function reSet()
{
document.getElementById("regist").reset();
}
至此,网站的用户注册效果基本实现。
在实现之后我又想多添加一个功能,那就是实现管理员用户注册时不直接进入数据库(或者先不授权?),而是提交一个申请。等待数据库端通过指令集方式更改。这个功能涉及到对于数据库的重新设计,先不实现了。
第五步,Servlet+JSP实现登录功能
在写这篇文章的时候发现实现登录功能的Servlet还没有结合个性化的数据库操作类UserDao升级,还是根据通用性DAO的落后版本,所以刚刚又花费了10分钟解决了一下,顺便增加了判断登陆失败原因的判断,例如是密码输入错误还是压根就没有注册。
1.Servlet设计
基本上和第四步一样。连接数据库,获得前端数据情况,判断是否账号密码一致。如果不一致,顺便给出不一致的原因。
在判断账号和密码是否一致的这个逻辑设计如下:
先通过UserDao实现通过前端输入的名字查找用户。
将查找出的用户的信息中的密码部分取出来,与前端输入的密码进行对比。
顺便如果无法查出这个用户,这说明尚未注册。
具体代码如下:2.0版本,基于全新个性化定制设计的UserDao进行重写
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
ServletContext context=this.getServletContext();
PrintWriter out=response.getWriter();
String username=request.getParameter("username");
String userpass=request.getParameter("password");
String server=context.getInitParameter("server");
String dbname=context.getInitParameter("dbname");
String user=context.getInitParameter("user");
String pwd=context.getInitParameter("pwd");
User tempuser=new User();
UserDao dao=new UserDao();
try {
dao.getConn(server, dbname, user, pwd);
tempuser=dao.getUserByName(username);
if(tempuser!=null) {
String password=tempuser.getUserpass();
if(password.equals(userpass)) {
System.out.println("success");
out.println("success");
}else {
System.out.println("password is wrong");
out.println("password is wrong");
}
}else {
System.out.println("we can't find this user");
out.println("database cannot find the user");
}
}catch(ClassNotFoundException e) {
e.printStackTrace();
}catch(Exception e) {
e.printStackTrace();
}
}
2.JSP设计
其实对于有手就行的JSP设计没有什么需要注意的地方。
JSP对应表单name为loginpage
<script type="text/javascript">
function LoginSubmit()
{
var id= document.loginpage.username.value;
var pwd=document.loginpage.password.value;
if(id==null||id=="")
{
alert("请填写用户名!");
}
else if(pwd==null||pwd=="")
{
alert("请填写密码!");
}
else
document.loginpage.submit();
}
</script>
至此,这个网站的注册和登录功能就全部实现了。
在上述代码设计的过程中,我主要在意的是尽可能按照个性化定制的DAO进行全部重新设计.虽然可以仅仅依靠基础的DAO类实现对数据库的操作,但是我想要尽可能避免出现在Servlet程序中出现SQL指令的行为,因为这样并不易于实现代码的长期维护,而且实现个性化DAO也有利于逻辑上的清晰。
除此之外,在进入图书管理代码的设计之前,需要将整个过程的逻辑先考虑清楚。
需要实现哪些功能?
- 搜索数据库中相应图书(按照出版社,书名,ISBN进行检索)(搜索引擎效果)
- 实现书店全部图书展示
- 判断当前用户身份,如果是管理员允许实现新添图书,下撤图书的功能。