一:封装StudentDao中的代码
将我们复用中相同的代码进行封装,找出代码中相同的部分经行封装,并减少代码量,提高性能,减少资源的消耗,这个类不需要被继承,不需要被实例化只能调用相应的方法
在封装中sql语句和结果转化是差异化的,在复用中不同的代码也就是差异化代码就不进行封装,在异化代码中需要把出查询出来的数据经行转换,写一个接口,在使用封装代码时因为并不知道使用者会使用什么方法所以我们使用泛型来接收
具体的封装代码如下:
//是一个工具类,不用继承
public final class DaoTemplate {
private DaoTemplate() {}
//转换接口
public static interface Convert<T> {
List<T> convert(ResultSet rs) throws SQLException;
}
/**
* 执行查询
* @param sql sql语句
* @param args 查询参数
* @param pageBean 分页参数
* @param convert 转化器
* @return
*/
public static <T> List<T> query(String sql,
Object[] args,
PageBean pageBean,
Convert<T> convert) {
//查询之前的准备, 相同的
List<T> datas = new ArrayList<>();
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
//如果不需要分页,直接查询
if(pageBean == null || !pageBean.isPagination()) {
try {
//------- 相同的部分
con = DBUtil.getConection();
ps = con.prepareStatement(sql);
setParams(args, ps);
rs = ps.executeQuery();
//-------
//回调业务类传入的转换器执行转换
datas = convert.convert(rs);
return datas;
} catch(SQLException e) {
e.printStackTrace();
} finally {
DBUtil.closeDB(rs, ps, con);
}
} else {
//如果需要分页
//-------- 相同的
//1. 总记录数
String countSql = "select COUNT(*) from ("+sql+") t";
try {
con = DBUtil.getConection();
ps = con.prepareStatement(countSql);
//设置查询参数
setParams(args, ps);
rs = ps.executeQuery();
//为总记录数赋值
while(rs.next()) {
pageBean.setTotal(rs.getInt(1));
}
//如果总记录为0, 则直接返回一个空的结果集
if(pageBean.getTotal() == 0) {
return datas;
}
// ----------
//----------- 相同
//查询当前页数据的sql
String pagingSql = sql + " limit " + pageBean.getStartIndex() + ", " + pageBean.getRows();
ps = con.prepareStatement(pagingSql);
//设置查询参数
setParams(args, ps);
rs = ps.executeQuery();
//-----------
datas = convert.convert(rs);
return datas;
} catch(SQLException e) {
e.printStackTrace();
} finally {
DBUtil.closeDB(rs, ps, con);
}
}
return datas;
}
在写完封装类后,先经行一个测试,调用封装方法,继承转换接口,定义sql语句,查看结果,测试代码如下:
public List<Student> getStudents(String sname, PageBean pageBean){
String sql = "select * from t_student t ";
List<Object> param = new ArrayList<>();
if(sname != null && !"".equals(sname)) {
sql += " where t.sname like ?";
param.add("%"+sname+"%");
}
List<Student> students = DaoTemplate.query(sql, param.toArray(), pageBean, new StudentConvert());
return students;
}
class StudentConvert implements Convert<Student> {
@Override
public List<Student> convert(ResultSet rs) throws SQLException {
List<Student> lst = new ArrayList<>();
while(rs.next()) {
Student stu = new Student();
stu.setSid(rs.getInt("sid"));
stu.setSname(rs.getString("sname"));
stu.setAge(rs.getInt("age"));
stu.setRemark(rs.getString("remark"));
lst.add(stu);
}
return lst;
}
}
@Test
public void testStudentDao02() {
StudentDao02 dao = new StudentDao02();
PageBean pageBean = new PageBean();
pageBean.setRows(10);
List<Student> students = dao.getStudents(null, pageBean);
students.forEach(t->System.out.println(t));
System.out.println(pageBean.getTotal());
System.out.println(pageBean.getTotalPage());
}
}
测试成功以后我们的后端代码就已经基本完成了,在完善的model类和jdbc后便可以开始着手前端代码,首先完成servlet类,参考代码如下:
@WebServlet("/students")
public class StudentServlet extends HttpServlet {
private StudentDao03 studentDao = new StudentDao03();
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
PageBean pageBean = new PageBean();
pageBean.setRequest(request);
String sname = request.getParameter("sname");
List<Student> students = studentDao.getStudents(sname, pageBean);
request.setAttribute("students", students);
request.getRequestDispatcher("/students/stuList.jsp").forward(request, response);
}
}
最后写前端jsp界面,详细代码如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!-- 目前没有定义自定义的标签库 -->
<%-- <%@taglib prefix="z" uri="/zking" %> --%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>学生信息</h1>
<!-- 查询条件 -->
<form action="<%=request.getContextPath()%>/students" method="post">
<input type="text" name="sname">
<input type="submit" value="查询">
</form>
<table border="1" style="width: 98%;">
<tr>
<td>学号</td>
<td>姓名</td>
<td>年龄</td>
<td>备注</td>
</tr>
<c:forEach items="${students}" var="student">
<tr>
<td>${student.sid}</td>
<td>${student.sname}</td>
<td>${student.age}</td>
<td>${student.remark}</td>
</tr>
</c:forEach>
</table>
<!-- 分页工具条 -->
<div style="text-align: right; width:98%;">
第${pageBean.page}页
共${pageBean.total}条记录
<a href="javascript: goPage(1)">首页</a>
<a href="javascript: goPage(${pageBean.previousPage})">上页</a>
<a href="javascript: goPage(${pageBean.nextPage})">下页</a>
<a href="javascript: goPage(${pageBean.totalPage})">尾页</a>
第<input type="text" id="specifiedPageNum" size="2" onkeypress="goSpecifiedPage(event);"/>
<a href="javascript: goPage(document.getElementById('specifiedPageNum').value)">GO</a>
</div>
<!-- 隐藏表单,用来翻页时保存查询参数 -->
<form action="${pageBean.url}" id="pagingForm" method="post">
<input type="hidden" name="page" value="${pageBean.page}"/>
<!-- 先只考虑本功能的查询参数,没有考虑公用性(不同功能的参数不同) -->
<input type="hidden" name="sname" value="<%=request.getParameter("sname")%>"/>
</form>
<script>
function goPage(page) {
//获取隐藏的表单
var form = document.getElementById("pagingForm");
form.page.value = page;
form.submit();
}
function goSpecifiedPage(event) {
if(event.keyCode == 13) {
let pageNum = document.getElementById("specifiedPageNum").value;
var form = document.getElementById("pagingForm");
form.page.value = pageNum;
form.submit();
}
}
</script>
</body>
</html>
运行结果为: