一:封装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();
//-------------------
//-------差异化
/*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"));
datas.add(stu);
}
*/
//--------
datas=convert.convert(rs);
return datas;
} catch(SQLException e) {
e.printStackTrace();
} finally {
DBUtil.closeDB(rs, ps, con);
}
}
return datas;
}
private static void setParams(Object[] args, PreparedStatement ps) throws SQLException {
if(args !=null) {
for(int i=1; i<=args.length; i++) {
ps.setObject(i, args[i]);
}
}
}
}
在写完封装类后,先经行一个测试,调用封装方法,继承转换接口,定义sql语句,查看结果,测试代码如下
package com.zking.mymvc.dao;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import com.zking.mymvc.model.Student;
import com.zking.mymvc.util.DaoTemplate;
import com.zking.mymvc.util.DaoTemplate.Convert;
import com.zking.mymvc.util.PageBean;
public class StudentDao02 {
public List<Student> getStudents(String sname, PageBean pageBean) {
//差异部分(每一个功能的sql语句都不一样)
String sql = "select * from t_student t ";
List<Object> param=new ArrayList<Object>();
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() {
StudentDao dao = new StudentDao();
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类,参考代码如下
package com.zking.mymvc.servlet;
import java.io.IOException;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.zking.mymvc.dao.StudentDao03;
import com.zking.mymvc.model.Student;
import com.zking.mymvc.util.PageBean;
@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 {
//new一个pageBean将他存储到request中
PageBean pageBean = new PageBean();
pageBean.setRequest(request);
//获取到查询的关键字,将擦寻的记过存储到集合中
String sname = request.getParameter("sname");
List<Student> students = studentDao.getStudents(sname, pageBean);
//将查询的结果存储到request中
request.setAttribute("students", students);
request.getRequestDispatcher("/students/stuList.jsp").forward(request, response);
}
}
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>,记住引用c标签的时候一定要进行导包,不然引用时代码会报错
最后写前端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 PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<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>
最后运行的结果,如下: