目录
我们为什么要制作通用分页?🤔
简单而言就是方便我们查询数据。
在制作自定义标签之前,我们先想一下分页是神马样子?
是不是酱紫?

好了,了解完分页标签是啥样之后就容易制作了。
- package com.ljq.mymvc.util;
-
- import java.util.Map;
-
- import javax.servlet.http.HttpServletRequest;
-
- import com.mysql.jdbc.StringUtils;
-
- /**
- * 分页实体类
- *
- * @author 一麟
- *
- */
- public class PageBean {
-
- private int page = 1;// 定义初始页码
-
- private int rows = 6;// 定义每页数据
-
- private int total = 0;// 初始化总共页数
-
- private boolean pagination = true;// 判断是否分页
-
- private String url;// 记录查询的url
-
- private Map
parameterMap;// 用于存放请求参数,用于生成隐藏域中的元素 -
- /**
- * 初始化分页对象
- *
- * @param req
- */
- public void setRequest(HttpServletRequest req) {
- // 如果传送的数值没有发生变化就不让页面属性改变
- if (!StringUtils.isNullOrEmpty(req.getParameter("page")))
- this.page = Integer.valueOf(req.getParameter("page"));
-
- if (!StringUtils.isNullOrEmpty(req.getParameter("rows")))
- this.rows = Integer.valueOf(req.getParameter("rows"));
- if (!StringUtils.isNullOrEmpty(req.getParameter("pagination")))
- this.pagination = Boolean.valueOf(req.getParameter("pagination"));
- this.url = req.getRequestURI();// 將请求的路径赋值给页面对象的url
- this.parameterMap = req.getParameterMap();// 获得参数集合
- // 将分页对象存入req中
- req.setAttribute("pageBean", this);
-
- }
-
- public int getPage() {
- return page;
- }
-
- public void setPage(int page) {
- this.page = page;
- }
-
- public int getRows() {
- return rows;
- }
-
- public void setRows(int rows) {
- this.rows = rows;
- }
-
- public int getTotal() {
- return total;
- }
-
- public void setTotal(int total) {
- this.total = total;
- }
-
- public boolean isPagination() {
- return pagination;
- }
-
- public void setPagination(boolean pagination) {
- this.pagination = pagination;
- }
-
- public String getUrl() {
- return url;
- }
-
- public void setUrl(String url) {
- this.url = url;
- }
-
- public Map
getParameterMap() { - return parameterMap;
- }
-
- public void setParameterMap(Map
parameterMap) { - this.parameterMap = parameterMap;
- }
-
- /**
- * 获取初始位置
- * @return
- */
- public int getStartIndex() {
- return (this.page - 1) * this.rows;
- }
-
- /**
- * 获取总页数
- * @return
- */
- public int getTotalPage() {
- if (this.getTotal() % this.rows == 0) {// 刚好取整为0,那么总页数就是取整值
- return this.getTotal() / this.rows;
- } else {
- return this.getTotal() / this.rows + 1;// 取整值不为0,就说明有溢出则+1
- }
- }
-
- /**
- * 获取上一页
- * @return
- */
- public int getPreviousPage() {
- return this.page - 1 > 0 ? this.page - 1 : 1;
- }
-
- /**
- * 获取下一页
- * @return
- */
- public int getNextPage() {
- return this.page + 1 > getTotalPage() ? getTotalPage() : this.page + 1;
- }
- }
下面呢,就是分页查询的流程:
当然,在编写查询语句之前少不了一件东西:
就是数据库工具类了DBHepler:
- package com.ljq.mymvc.util;
-
- import java.io.InputStream;
- import java.sql.Connection;
- import java.sql.DriverManager;
- import java.sql.ResultSet;
- import java.sql.SQLException;
- import java.sql.Statement;
- import java.util.Properties;
-
- /**
- * 数据操作工具类
- *
- * @author 一麟
- *
- */
- public class DBHelper {
-
- // 驱动路径
- private static String DRIVER_NAME;
-
- //连接语句
- private static String DB_URL;
-
- // 用户名
- private static String DB_USER;
-
- // 密码
- private static String DB_PASSWORD;
-
- static {
- try {
- InputStream in = DBHelper.class.getResourceAsStream("/jdbc.properties");
- Properties pro = new Properties();
- pro.load(in);
- DRIVER_NAME = pro.getProperty("driver.name");
- DB_URL = pro.getProperty("db.url");
- DB_USER = pro.getProperty("db.user");
- DB_PASSWORD = pro.getProperty("db.password");
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- // 私有化构造
- private DBHelper() {
- }
-
- /**
- * 加载驱动
- */
- static {
- try {
- Class.forName(DRIVER_NAME);
-
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- }
- }
-
- /**
- * 获得连接
- *
- * @return
- * @throws SQLException
- */
- public static Connection getConection() throws SQLException {
- Connection connection = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
- return connection;
- }
-
- /**
- * 关闭资源
- *
- * @param rs
- * @param ps
- * @param con
- */
- public static void closeDB(ResultSet rs, Statement ps, Connection con) {
-
- try {
- if (rs != null && !rs.isClosed()) {
- rs.close();
- }
-
- if (ps != null && !ps.isClosed()) {
- ps.close();
- }
-
- if (con != null && !con.isClosed()) {
- con.close();
- }
-
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
-
- /**
- * 关闭资源
- *
- * @param rs
- * @param ps
- */
- public static void closeDB(ResultSet rs, Statement ps) {
-
- try {
- if (rs != null && !rs.isClosed()) {
- rs.close();
- }
-
- if (ps != null && !ps.isClosed()) {
- ps.close();
- }
-
- } catch (SQLException e) {
- e.printStackTrace();
- }
-
- }
-
- public static void main(String[] args) throws SQLException {
- System.out.println(DBHelper.getConection());
- }
- }
我们发现啊:以往我们编写的这个工具类里面的属性值都是定死的,但是我这边却不是定死的,而是通过读取一个文件中的属性值获得具体对应的属性值。为什么呢?
是这样的,因为刚好我在准备自己编写MVC框架了,所以才通过从外部文件中读取的方式获得具体的属性值。
就像这里我的项目:

是有准备一个叫做jdbc.properties的文件用于读取具体的属性值。提高了我们开发的便捷性。
文件内容如下:
- driver.name = com.mysql.jdbc.Driver
- db.url=jdbc:mysql://localhost:3306/good??useUnicode=true&characterEncoding=utf-8&useSSL=false
- db.user=root
- db.password=jiang
最后我们再通过main方法测试得到控制台输出的结果为:

就已经表示我们的连接已经建立完毕了。
好了,前面的这些都是准备工作。
1)为了进行公共方法的抽取,需要找出上面实习中的可通用部分,和差异化部分。
- 只要是分页,就会统计总记录数,而总记录数的统计是在业务sql外封装了一个select count(*)是有规律可循的,可以通用
- 只要是分页,则封装分页sql也是有规律可循的(在业务sql后加limit子句即可),可以通用
- 因为每个查询对应的业务实体(即模型)不同,所以ORM映射部分不能通用
2)公用方法封装思路
- 将可通用的部分封装到模板中
- 差异化部分(即不可通用部分),可以定义一个处理接口,以便于通过参数传入个性化的实现部分
具体实现如下所示:
- package com.ljq.mymvc.util;
-
- import java.sql.Connection;
- import java.sql.PreparedStatement;
- import java.sql.ResultSet;
- import java.sql.SQLException;
- import java.util.ArrayList;
- import java.util.List;
-
- /**
- *
- * @author 一麟
- *
- */
- /**
- * 分页查询工具类
- *
- * @author 一麟
- *
- */
- public class BaseDao {
-
- /**
- * 私有化构造
- */
- private BaseDao() {
- }
-
- /**
- * 回调函数接口
- *
- * @author 一麟
- *
- * @param
- */
- public static interface ICovent
{ - List
convent(ResultSet rs) throws SQLException; - }
-
- /**
- * 查询封装方法
- *
- * @param
任意类型 - * @param sql传入的SQL查询语句
- * @param params参数数组
- * @param pageBean分页对象
- * @param covent转换器
- * @return 返回查询的结果集合
- */
- public static
List query(String sql, Object[] params, PageBean pageBean, ICovent covent) { -
- // 定义装载容器
- List
students = new ArrayList(); -
- // 初始化查询工具
- Connection con = null;
- PreparedStatement ps = null;
- ResultSet rs = null;
-
- // 分页判断(如果传入的分页对象为空值或者是不需要查询)
- if (pageBean == null || !pageBean.isPagination()) {// 不需要分页的情况下
- try {
- con = DBHelper.getConection();// 连接
- ps = con.prepareStatement(sql);// 资源对象
-
- // 记录查询参数个数
- if(params!=null) {
- int i = 1;
- for (Object param : params) {
- ps.setObject(i, param);
- i++;
- }
- }
-
- // 结果集
- rs = ps.executeQuery();
-
- // 通过传入的回调函数进行转换
- students = covent.convent(rs);// 将结果集转换为我们需要的类型
- } catch (SQLException e) {
- e.printStackTrace();
- } finally {
- DBHelper.closeDB(rs, ps, con);
- }
- } else {// 需要分页的情况
- String countSql = "select COUNT(*) from (" + sql + ") tmp";// 注意:这个地方一定要给传入的SQL查询结果指定别名
- try {
- // 获得连接、对象资源
- con = DBHelper.getConection();
- ps = con.prepareStatement(countSql);
- // 记录参数个数
- int i = 1;
- for (Object param : params) {
- ps.setObject(i, param);
- i++;
- }
- // 结果集
- rs = ps.executeQuery();
- if (rs.next()) {// 遍历并查询总共的数据条数
- Integer total = rs.getInt(1);
- pageBean.setTotal(total);// 赋值给分页对象(刷新总数据条)
- }
- // 判断(如果分页对象中的总数据条刷新至0或者0以下就表示已经没有数据可查询了,就返回学生集合)
- if (pageBean.getTotal() <= 0) {
- return students;
- }
-
- // 查询当前页的数据
- String pagingSql = sql + " limit " + pageBean.getStartIndex() + ", " + pageBean.getRows();
- ps = con.prepareStatement(pagingSql);
- // 记录查询参数个数
- int j = 1;
- for (Object param : params) {
- ps.setObject(j, param);
- j++;
- }
- rs = ps.executeQuery();
-
- // 转换
- students = covent.convent(rs);
-
- } catch (SQLException e) {
- e.printStackTrace();
- } finally {
- DBHelper.closeDB(rs, ps, con);
- }
-
- }
-
- return students;
- }
- }
当然这个实现其实还不够完善,为什么呢?我们发现里面的student类都是定死的,后期我们会通过spring注入的方式更加晚上这个地方。
接下来就是我们分页查询学生的dao方了:
- package com.ljq.mymvc.util;
-
- import java.sql.ResultSet;
- import java.sql.SQLException;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Objects;
-
- import com.ljq.mymvc.model.Student;
- import com.ljq.mymvc.util.BaseDao.ICovent;
-
- /**
- * 学生分页查询dao方
- *
- * @author 一麟
- *
- */
- public class StudentDao {
-
- public List
getStudents(String sname, PageBean pageBean) { - // 构造sql语句 变化部分
- String sql = "select * from t_student t ";
- List
- if (!Objects.isNull(sname) && sname.length() > 0) {
- sql += " where s_sname like ?";
- param.add(sname);
- }
- // 调用封装的代码进行查询
- List
list = BaseDao.query(sql, param.toArray(), pageBean, new ICovent() { -
- public List
convent(ResultSet rs) throws SQLException { - List
students = new ArrayList<>(); - while (rs.next()) {
- Student stu = new Student();
- stu.setSid(rs.getInt(1));
- stu.setSname(rs.getString(2));
- stu.setScore(rs.getInt(3));
- stu.setClazz(rs.getString(4));
- students.add(stu);
- }
- return students;
- }
-
- });
- return list;
- }
-
- }
好啦分页查询就先到这了。下期将带来分页查询02,将会带来通用分页的余下知识点!😂😂😂