一、MVC设计模式
###jsp的开发模式
###三层架构&MVC练习
二、学生信息管理系统扩展
在之前的账号密码验证的基础上,对该系统进行功能扩展,更新删除,模糊查询,分页等功能。
###数据库准备(这里和之前的学生管理系统所用的字段不一样 ,更改一下即可)
CREATE DATABASE stus;
USE stus;
CREATE TABLE stu (
sid INT PRIMARY KEY AUTO_INCREMENT,
sname VARCHAR (20),
gender VARCHAR (5),
phone VARCHAR (20),
birthday DATE,
hobby VARCHAR(50),
info VARCHAR(200)
);
###Student类准备
public class Student {
private int sid;
private String sname;
private String gender;
private String phone;
private Date birthday;
private String hobby;
private String info;
public Student(int sid, String sname, String gender, String phone, Date birthday, String hobby, String info) {
this.sid = sid;
this.sname = sname;
this.gender = gender;
this.phone = phone;
this.birthday = birthday;
this.hobby = hobby;
this.info = info;
}
public Student(){
}
public Student(String sname, String gender, String phone, Date birthday, String hobby, String info) {
this.sname = sname;
this.gender = gender;
this.phone = phone;
this.birthday = birthday;
this.hobby = hobby;
this.info = info;
}
public void setSid(int sid) {
this.sid = sid;
}
public void setSname(String sname) {
this.sname = sname;
}
public void setGender(String gender) {
this.gender = gender;
}
public void setPhone(String phone) {
this.phone = phone;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
public void setInfo(String info) {
this.info = info;
}
public int getSid() {
return sid;
}
public String getSname() {
return sname;
}
public String getGender() {
return gender;
}
public String getPhone() {
return phone;
}
public Date getBirthday() {
return birthday;
}
public String getHobby() {
return hobby;
}
public String getInfo() {
return info;
}
}
###PageBean类准备,用于分页功能
public class PageBean<T> {
/**
* 这是一个用于封装了分页的数据。
* 里面包含:
*
* 该页的的学生集合数据
* 总的记录数
* 总的页数
* 当前页
* 每页显示的记录数
* @author xiaomi
* @param <T>
*
*/
private int currentPage;//当前页
private int totalPage;//总页数
private int pageSize;//每页的记录数
private int totalSize;//总的记录数
private List<T> list;//当前页的学生集合
public int getCurrentPage() { return currentPage; }
public int getTotalPage() { return totalPage; }
public int getPageSize() { return pageSize; }
public int getTotalSize() { return totalSize; }
public List<T> getList() { return list; }
public void setCurrentPage(int currentPage) { this.currentPage = currentPage; }
public void setTotalPage(int totalPage) { this.totalPage = totalPage;}
public void setPageSize(int pageSize) { this.pageSize = pageSize; }
public void setTotalSize(int totalSize) { this.totalSize = totalSize; }
public void setList(List<T> list) { this.list = list; }
}
###Jar包准备
###查询:
1.先写一个jsp页面,里面放一个超链接。
<h3><a href="StudentListServlet">显示所有学生列表</a></h3>
2.写servlet,接受请求,去调用Service,有service去调用到。
3.先写dao,做dao实现。(前面的图是dao接口[StuDao],后面的图是dao实现[StuDaoImpl])
4.在写service,做service的实现。(前面是service接口[StudentService],后面是实现[StudentServiceImpl])
5.在servlet中存储数据,并且做出页面响应[StudentListServlet]
6.在stu_list.jsp中将数据写出来
###增加
1.在stu_list.jsp中书写添加链接
<a href="add.jsp">添加</a></td>
先跳转到增加的页面,编写增加的页面[add.jsp]。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>添加学生</title>
</head>
<body>
<h3><b>添加学生页面</b></h3>
<form method="post" action="AddServlet">
<table border="1" width="500">
<tr>
<td>姓名</td>
<td><input type="text" name="sname"></td>
</tr>
<tr>
<td>性别</td>
<td>
<input type="radio" name="gender" value="男">男
<input type="radio" name="gender" value="女">女
</td>
</tr>
<tr>
<td>电话</td>
<td><input type="text" name="phone" ></td>
</tr>
<tr>
<td>生日</td>
<td><input type="text" name="birthday"></td>
</tr>
<tr>
<td>爱好</td>
<td>
<input type="checkbox" name="hobby" value="游泳">游泳
<input type="checkbox" name="hobby" value="篮球">篮球
<input type="checkbox" name="hobby" value="足球">足球
<input type="checkbox" name="hobby" value="看书">看书
<input type="checkbox" name="hobby" value="写字">写字
</td>
</tr>
<tr>
<td>简介</td>
<td>
<textarea name="info" rows="3" cols="20"></textarea>
</td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="添加" ></td>
</tr>
</table>
</form>
</body>
</html>
2.点击添加,提交数据到[AddServlet],处理数据。
public class AddServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
try {
System.out.println("我來添加了");
//1.获取客户端提交上来的数据
String sname = request.getParameter("sname");
String gender = request.getParameter("gender");
String phone = request.getParameter("phone");
String birthday = request.getParameter("birthday");
String info = request.getParameter("info");
//因为从add.jsp中获取的爱好有多个值,所以要放在数组中
String[] h = request.getParameterValues("hobby");
//此时的hobby是[篮球,足球,写字],两边有中括号,要把中括号消除掉
String hobby = Arrays.toString(h);
//消除两边的中括号,因为字符串末尾是“#”,所以最后要减1
hobby = hobby.substring(1,hobby.length()-1);
//2.添加到数据库中
//要把birthday从Strng类型变为Date类型
Date date = new SimpleDateFormat("yyyy-MM-dd").parse(birthday);
Student student = new Student(sname,gender,phone,date,hobby,info);
StudentService service = new StudentServiceImpl();
service.insert(student);
//3.跳转到列表页
//这里是直接跳转到页面上,页面的话,不会触发servlet,所以不会显示数据,
//request.getRequestDispatcher("stu_list.jsp").forward(request, response);
System.out.println("我来了啊");
//再查一次数据库,然后再装到作用域中,然后再跳转,servlet除了能跳jsp之外,还能跳servlet
request.getRequestDispatcher("StudentListServlet").forward(request, response);
System.out.println("我走了啊");
} catch (Exception e) {
e.printStackTrace();
}
}
}
3.再写service,做service的实现。(前面是service接口[StudentService],后面是实现[StudentServiceImpl])
4.先写dao,做dao实现。(前面的图是dao接口[StuDao],后面的图是dao实现[StuDaoImpl])
5.完成了这些存储工作后,需要跳转到列表页面,这里不能直接跳转到列表页面,否则没有什么内容显示,应该先跳转到查询所有学生信息的那个servlet[StudentListServlet],有那个Servlet再去跳转到列表页面。
该步骤出现了问题:
request.getRequestDispatcher("StudentListServlet").forward(request, response);
我用以上代码在AddServlet结尾打算跳到StudentListServlet,但是失败了,数据可以添加到数据库中,但是添加后跳转的是一个空白页,编译器也都没有报错,但好像就是该句语言没有起作用。没有显示所有的数据。
6.需要注意的地方:
###删除
1.在stu_list.jsp中书写添加链接
<a href="#" onclick="doDelete(${stu.sid})">删除</a>
接着写函数doDelete(),依然是在stu_list.jsp中
<script type="text/javascript">
function doDelete(sid){
/*如果这里弹出的对话框,用户点击的是确定,就马上去请求servlet
如何知道用户点击的是确定。
如何在js的方法中情请求servlet。*/
var flag = confirm("是否确定删除?");
if(flag){
// 表明点了确定,访问servlet,在当前标签页上打开超链接
window.location.href = "DeleteServlet?sid="+sid;
//location.href = "DeleteServlet?sid="+sid;
}
}
</script>
点击超链接,弹出一个询问是否删除的对话框,如果点击了确定,那么就真的删除。
2.在js访问里面判断惦记的选项,然后跳转到servlet[DeleteServlet]。
@WebServlet(name = "DeleteServlet")
public class DeleteServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int id = Integer.parseInt(request.getParameter("sid"));
StudentService service = new StudentServiceImpl();
service.delete(id);
request.getRequestDispatcher("StudentListServlet").forward(request,response);
}
}
3.再写service,做service的实现。(前面是service接口[StudentService],后面是实现[StudentServiceImpl])
4.先写dao,做dao实现。(前面的图是dao接口[StuDao],后面的图是dao实现[StuDaoImpl])
5.注意:对应上面发现的问题。在该功能中,同样需要在删除之后,跳转到StudentListServlet中去,而且是利用相同的语句。
request.getRequestDispatcher("StudentListServlet").forward(request, response);
但是在该功能中该句语言起作用了,删除后重新显示了所有列表数据。
###更新
1.在stu_list.jsp中书写添加链接
<a href="EditServlet?sid=${stu.sid}">更新</a>
点击列表中的更新链接,先跳转到一个EditServlet,在这个Servlet里面,显现根据ID去查询这个学生的所有信息出来。
@WebServlet(name = "EditServlet")
public class EditServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
//获取到需要更改的数据ID,因为从jsp中获取到的ID是String类型的,所以需要转为Int类型
int id = Integer.parseInt(request.getParameter("sid"));
//在数据库中根据ID找到这个数据
StudentService service = new StudentServiceImpl();
Student student = service.find(id);
//存放在作用域中
request.setAttribute("stu",student);
//跳转到edit.jsp中,用以显示该数据
request.getRequestDispatcher("edit.jsp").forward(request,response);
}
}
2.跳转到更新的页面【edit.jsp】,然后在页面上显示数据
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>更新学生信息</title>
</head>
<body>
<h3><b>更新学生页面</b></h3>
<form method="post" action="UpdateServlet">
<input type="hidden" name="sid" value="${stu.sid}">
<table border="1" width="500">
<tr>
<td>姓名</td>
<td><input type="text" name="sname" value="${stu.sname}"></td>
</tr>
<tr>
<td>性别</td>
<td>
<%--如果性别是男的,可以在男的性别input标签里面,出现checked,反之在女的input标签中出现checked--%>
<input type="radio" name="gender" value="男" <c:if test="${stu.gender == '男'}">checked</c:if> >男
<input type="radio" name="gender" value="男" <c:if test="${stu.gender == '女'}">checked</c:if> >女
</td>
</tr>
<tr>
<td>电话</td>
<td><input type="text" name="phone" value="${stu.phone}"></td>
</tr>
<tr>
<td>生日</td>
<td><input type="text" name="birthday" value="${stu.birthday}"></td>
</tr>
<tr>
<td>爱好</td>
<td>
<!-- 爱好: 篮球 , 足球 , 看书 因为爱好有很多个, 里面存在包含的关系 ,所以需要导入jstl中的functions
,用fn:contains查看包含关系-->
<input type="checkbox" name="hobby" value="游泳"<c:if test="${fn:contains(stu.hobby,'游泳')}">checked</c:if> >游泳
<input type="checkbox" name="hobby" value="篮球"<c:if test="${fn:contains(stu.hobby,'篮球')}">checked</c:if> >篮球
<input type="checkbox" name="hobby" value="足球"<c:if test="${fn:contains(stu.hobby,'足球')}">checked</c:if> >足球
<input type="checkbox" name="hobby" value="看书"<c:if test="${fn:contains(stu.hobby,'看书')}">checked</c:if> >看书
<input type="checkbox" name="hobby" value="写字"<c:if test="${fn:contains(stu.hobby,'写字')}">checked</c:if> >写字
</td>
</tr>
<tr>
<td>简介</td>
<td>
<textarea name="info" rows="3" cols="20" >${stu.info}</textarea>
</td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="更新" ></td>
</tr>
</table>
</form>
</body>
</html>
3.修改完毕后,提交数据到UpdateServlet,提交上来的数据是没带id的,所以我们要在edit.jsp手动创建一个隐藏的输入框,在这里面给定id的值,以便提交表单,带上id,否则在sql语句中没有id,更新不了该数据。
<form method="post" action="UpdateServlet">
<input type="hidden" name="sid" value="${stu.sid }">
...
</form>
@WebServlet(name = "UpdateServlet")
public class UpdateServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
try {
//1. 获取客户端提交上来的数据
int sid = Integer.parseInt(request.getParameter("sid"));
String sname = request.getParameter("sname"); //sname:zhangsan
String gender = request.getParameter("gender");
String phone = request.getParameter("phone");
String birthday = request.getParameter("birthday"); // 1989-10-18
String info = request.getParameter("info");
//String hobby = request.getParameter("hobby");//hobby : 游泳,写字, 足球。
String[] h = request.getParameterValues("hobby");
// [篮球,足球,写字] --- 篮球,足球,写字
String hobby = Arrays.toString(h);
hobby = hobby.substring(1, hobby.length() - 1);
//2. 添加到数据库
//string -- date
Date date = new SimpleDateFormat("yyyy-MM-dd").parse(birthday);
Student student = new Student(sid ,sname, gender, phone, date,hobby, info);
//2. 更新数据库数据
StudentService service = new StudentServiceImpl();
service.update(student);
//3. 跳转界面
request.getRequestDispatcher("StudentListServlet").forward(request, response);
} catch (Exception e) {
e.printStackTrace();
}
}
}
4.再写service,做service的实现。(前面是service接口[StudentService],后面是实现[StudentServiceImpl])
5.先写dao,做dao实现。(前面的图是dao接口[StuDao],后面的图是dao实现[StuDaoImpl])
###模糊查询
1.在stu_list.jsp中的列表里添加一行代码
<form action="SearchStudentServlet" method="post"> <table border="1" width="700"> <tr> <td colspan="8"> 按姓名查询:<input type="text" name="sname"/> 按性别查询: <select name="sgender"> <option value="">--请选择--</option> <option value="男">男</option> <option value="女">女</option> </select> <input type="submit" value="查询"> <a href="add.jsp">添加</a></td> </td> </tr> ... </table> </form>
2.按照姓名和 性别查询,输入姓名或者性别后,提交到SearchStudentServlet。
@WebServlet(name = "SearchStudentServlet")
public class SearchStudentServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
String sname = request.getParameter("sname");
String sgender = request.getParameter("sgender");
StudentService service = new StudentServiceImpl();
List<Student> list = service.searchStudent(sname,sgender);
request.setAttribute("list",list);
request.getRequestDispatcher("stu_list.jsp").forward(request,response);
}
}
3.再写service,做service的实现。(前面是service接口[StudentService],后面是实现[StudentServiceImpl])
5.先写dao,做dao实现,需要说明一下,实现里面在sname那两边加了个“%”,百分号是通配符,意思是,搜索名字中带有sname字样的数据。在runner.query()中的最后一个参数list.toArray(),是将列表list转化为数组。(前面的图是dao接口[StuDao],后面的图是dao实现[StuDaoImpl])
6.在SearchStudentServlet中,将返回的查询数据放在一个数组里面,然后将该数组放在作用域中,显示在跳转到的stu_list.jsp中。就是重新使用了一遍stu_list.jsp文件。
###分页功能
分页的两种方式
* 物理分页 (真分页)
> 来数据库查询的时候,只查一页的数据就返回了。
优点 内存中的数据量不会太大
缺点:对数据库的访问频繁了一点。SELECT * FROM stu LIMIT 5 OFFSET 2
* 逻辑分页 (假分页)
> 一口气把所有的数据全部查询出来,然后放置在内存中。
优点: 访问速度快。
缺点: 数据库量过大,内存溢出。
在该功能中,需要用到PageBean类,该类中有如下变量,是需要显示在分页中的。
1.在listPage.jsp中写一个链接。
2.点击该链接,跳转到StudentListPageServlet,并且将当前页设置为1.
@WebServlet(name = "StudentListPageServlet")
public class StudentListPageServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.获取需要显示的页码数
int currentPage = Integer.parseInt(request.getParameter("currentPage"));
//2.根据指定的页数,去获取该页的数据回来
StudentService service = new StudentServiceImpl();
PageBean pageBean = service.findStudentByPage(currentPage);
request.setAttribute("pageBean",pageBean);
//3.跳转界面
request.getRequestDispatcher("stu_list_page.jsp").forward(request,response);
}
}
3.再写service,做service的实现,在实现中,设置了PageBean对象的各种属性值,其中数据的总记录数是需要用到dao中的一个findCount()方法,用于查询数据库中当前共有多少条数据。(前面是service接口[StudentService],后面是实现[StudentServiceImpl])
4.先写dao,做dao实现。该实现中的findCount()方法用于查询数据库中当前共有多少条数据(前面的图是dao接口[StuDao],后面的图是dao实现[StuDaoImpl])
5.在StudentListPageServlet获取到了PageBean对象后,将会跳转到stu_list_page.jsp中。
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>分页显示学生列表</title>
</head>
<body>
<form action="SearchStudentServlet" method="post">
<table border="1" width="700">
<tr>
<td colspan="8">
按姓名查询:<input type="text" name="sname"/>
按性别查询:<select name="sgender">
<option value="">--请选择--</option>
<option value="男">男</option>
<option value="女">女</option>
</select>
<input type="submit" value="查询">
<a href="add.jsp">添加</a>
</td>
</tr>
<tr align="center">
<td>编号</td>
<td>姓名</td>
<td>性别</td>
<td>电话</td>
<td>生日</td>
<td>爱好</td>
<td>简介</td>
<td>操作</td>
</tr>
<c:forEach items="${pageBean.list}" var="stu">
<tr align="center">
<td>${stu.sid}</td>
<td>${stu.sname}</td>
<td>${stu.gender}</td>
<td>${stu.phone}</td>
<td>${stu.birthday}</td>
<td>${stu.hobby}</td>
<td>${stu.info}</td>
<td><a href="EditServlet?sid=${stu.sid}">更新</a></td>
</tr>
</c:forEach>
<tr>
<td colspan="8">
第${pageBean.currentPage}/${pageBean.totalPage}
每页显示${pageBean.pageSize}条
总的记录数${pageBean.totalSize}
<c:if test="${pageBean.currentPage != 1}">
<a href="StudentListPageServlet?currentPage=1">首页</a>
<a href="StudentListPageServlet?currentPage=${pageBean.currentPage-1 }">上一页</a>
</c:if>
<c:forEach begin="1" end="${pageBean.totalPage}" var="i">
<c:if test="${pageBean.currentPage == i }">
${i}
</c:if>
<c:if test="${pageBean.currentPage != i}">
<a href="StudentListPageServlet?currentPage=${i}">${i}</a>
</c:if>
</c:forEach>
<c:if test="${pageBean.currentPage != pageBean.totalPage}">
<a href="StudentListPageServlet?currentPage=${pageBean.currentPage+1}">下一页</a>
<a href="StudentListPageServlet?currentPage=${pageBean.totalPage}">尾页</a>
</c:if>
</td>
</tr>
</table>
</form>
</body>
</html>
###目录
###总结
在该系统中,除了上面所说的空白页问题之外,还有一个问题,就是当服务器运行一段时间后,再点击各种功能,就会一直加载,而不会有所反应,目前尚未解决,查阅百度疑似tomcat内存不够。
###功能展示(效果图,所以没有空白页问题)
###分页功能
###更新功能(我的有空白页问题,就是添加后无法显示全部数据,而是一个空白页)
###模糊查询功能
###删除功能
###添加功能(我的有空白页问题,就是添加后无法显示全部数据,而是一个空白页)