当前位置:网站首页>自定义通用分页标签01
自定义通用分页标签01
2022-08-04 03:04:00 【一麟yl】
目录
我们为什么要制作通用分页?
简单而言就是方便我们查询数据。
在制作自定义标签之前,我们先想一下分页是神马样子?
是不是酱紫?
好了,了解完分页标签是啥样之后就容易制作了。
首先,我们需要准备一个pageBean对象:
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<String, String[]> 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<String, String[]> getParameterMap() {
return parameterMap;
}
public void setParameterMap(Map<String, String[]> 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 <T>
*/
public static interface ICovent<T> {
List<T> convent(ResultSet rs) throws SQLException;
}
/**
* 查询封装方法
*
* @param <T>任意类型
* @param sql传入的SQL查询语句
* @param params参数数组
* @param pageBean分页对象
* @param covent转换器
* @return 返回查询的结果集合
*/
public static <T> List<T> query(String sql, Object[] params, PageBean pageBean, ICovent<T> covent) {
// 定义装载容器
List<T> students = new ArrayList<T>();
// 初始化查询工具
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<Student> getStudents(String sname, PageBean pageBean) {
// 构造sql语句 变化部分
String sql = "select * from t_student t ";
List<Object> param = new ArrayList<>();
if (!Objects.isNull(sname) && sname.length() > 0) {
sql += " where s_sname like ?";
param.add(sname);
}
// 调用封装的代码进行查询
List<Student> list = BaseDao.query(sql, param.toArray(), pageBean, new ICovent<Student>() {
public List<Student> convent(ResultSet rs) throws SQLException {
List<Student> 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,将会带来通用分页的余下知识点!
边栏推荐
- STM8S105K4T6------Serial port sending and receiving
- 从图文展示到以云为核,第五代验证码独有的策略情报能力
- 如果禁用了安全启动,GNOME 就会发出警告
- C# 构造函数业务场景测试项目
- flinkcdc 消费 mysql binlog 没有 sqltype=delete 的数据是什么原
- 0.1 前言
- STM8S project creation (STVD creation) --- use COSMIC to create a C language project
- 一个属于程序员的七夕节!
- JVM内存和垃圾回收-07.堆
- 自制蓝牙手机app控制stm8/stm32/C51板载LED
猜你喜欢
Polygon zkEVM网络节点
There are n steps in total, and you can go up to 1 or 2 steps each time. How many ways are there?
基地址:环境变量
织梦响应式酒店民宿住宿类网站织梦模板(自适应手机端)
千兆2光8电管理型工业以太网交换机WEB管理X-Ring一键环网交换机
SQL注入中 #、 --+、 --%20、 %23是什么意思?
全网没有之一的JMeter 接口测试流程详解
2022年茶艺师(中级)考试试题模拟考试平台操作
tkmapper的crud示例:
2千兆光+6千兆电导轨式网管型工业级以太网交换机支持X-Ring冗余环网一键环网交换机
随机推荐
sudo 权限控制,简易
小程序+新零售,玩转行业新玩法!
Utilities of Ruineng Micrometer Chip RN2026
yum 仅下载包
Dong mingzhu live cold face away, when employees frequency low-level mistakes, no one can understand their products
4路双向HDMI综合业务高清视频光端机8路HDMI高清视频光端机
Architecture of the actual combat camp module three operations
融云「音视频架构实践」技术专场【内含完整PPT】
复制带随机指针的链表
【学习笔记之菜Dog学C】动态内存管理
异步编程解决方案 Generator生成器函数、iterator迭代器、async/await、Promise
Simple record of Flink principle flow chart
MySQL Query Exercise (1)
Homemade bluetooth mobile app to control stm8/stm32/C51 onboard LED
深度学习(三)分类 理论部分
2022年茶艺师(中级)考试试题模拟考试平台操作
MySQL 查询练习(1)
MySQL高级-读写分离-分库分表
如何读取 resources 目录下的文件路径?
MySQL查询优化与调优