当前位置:网站首页>通用分页实现
通用分页实现
2022-07-23 13:56:00 【Bugxiu_fu】
为什么要通用分页?
1) 为了提高查询性能及节约网络流量,每次只查询指定的记录数,而不是全部,在数量比较大时很有用
2)当点击下一页或指定页面的数据时,将带着所有的查询条件,再次执行查询
最终效果展示:

图解

效果展示

实现思路:(理解)
怎么封装一个通用分页查询方法,先编写一个查询sql语句,将查询条件与分页实体放入做为方法的参数。
判断是否需要分页
1.不分页,直接查询,先遍历,然后返回结果集
2.分页,查询总页数,如果总记录为0,直接返回空的结果集,如果不为0,先编写需要显示分页条数的sql语句,然后查询当前页的数据,返回当前页的结果集(1~10页)。
封装一个分页信息实体,因为我们后面需要用它的属性
package com.zking.utils;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import com.mysql.jdbc.StringUtils;
public class PageBean {
/**
* 页码
*/
private int page = 1;
/**
* 每页显示的记录数
*/
private int rows = 10;
/**
* 总记录数
*/
private int total = 0;
/**
* 是否分页
*/
private boolean pagination = false;
/**
* 记录查询的url,以便于点击分页时再次使用
*/
private String url;
/**
* 存放请求参数,用于生成隐藏域中的元素
*/
private Map<String,String[]> parameterMap;
/**
* 根据传入的Request初始化分页对象
* @param request
*/
public void setRequest(HttpServletRequest request) {
if(!StringUtils.isNullOrEmpty(request.getParameter("page"))) {
this.page = Integer.valueOf(request.getParameter("page"));
}
if(!StringUtils.isNullOrEmpty(request.getParameter("rows"))) {
this.rows = Integer.valueOf(request.getParameter("rows"));
}
if(!StringUtils.isNullOrEmpty(request.getParameter("pagination"))) {
this.pagination = Boolean.valueOf(request.getParameter("pagination"));
}
this.url = request.getRequestURI();
this.parameterMap = request.getParameterMap();
request.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;
}
//计算起始行号
public int getStartIndex() {
if(this.page > this.getTotalPage()) {
this.page = this.getTotalPage();
}
if(this.page < 1) {
this.page = 1;
}
return (this.page - 1) * this.rows;
}
//获取总页数
public int getTotalPage() {
if (this.getTotal() % this.rows == 0) {
return this.getTotal() / this.rows;
} else {
return this.getTotal() / this.rows + 1;
}
}
//上一页
public int getPreviousPage() {
return this.page - 1 > 0 ? this.page - 1 : 1;
}
//下一页
public int getNextPage() {
return this.page + 1 > getTotalPage() ? getTotalPage() : this.page + 1;
}
}
版本一
public List<Book> queryBook(String bname,PageBean pb){
String sql="select * from t_book";
if(!StringUtils.isNullOrEmpty(bname)) {
sql+=" where bname like ?";
}
List<Book> list=new ArrayList<>();
Connection con=null;
PreparedStatement ps=null;
ResultSet rs=null;
//false || true 或者,一个为真即为真,后续不再计算,一个为假再计算右边的表达式。
//true && true 与,先计算左边的,如果左边的不满足,后续将不再计算;如果满足,必须要满足两个才行
if(pb ==null || !pb.isPagination()) {//不分页
try {
con=DBUtil.getConection();
ps=con.prepareStatement(sql);
/**
* 由于mysql数据库自动添加成以下sql
* select * from t_book where bname like '%strName%';
* 所以这里不用转义"%";
*/
if(!StringUtils.isNullOrEmpty(bname)) {
ps.setObject(1, "%"+bname+"%");
}
rs=ps.executeQuery();
while (rs.next()) {
Book b=new Book();
b.setBid(rs.getInt(1));
b.setBname(rs.getString(2));
b.setPrice(rs.getDouble(3));
list.add(b);
}
return list;
} catch (Exception e) {
e.printStackTrace();
}
}else {
try{//需要分页
//总页面
String countsql="select count(*) from ("+sql+") p";
con=DBUtil.getConection();
ps=con.prepareStatement(countsql);
if(!StringUtils.isNullOrEmpty(bname)) {
ps.setObject(1, bname+"%");
}
rs=ps.executeQuery();
if(rs.next()) {
pb.setTotal(rs.getInt(1));
}
if(pb.getTotal()<=0) {//无记录
return list;
}
//查询当前页的数据
String pageql=sql+" limit "+pb.getStartIndex()+","+pb.getRows();
ps=con.prepareStatement(pageql);
if(!StringUtils.isNullOrEmpty(bname)) {
ps.setObject(1, bname+"%");
}
rs=ps.executeQuery();
while (rs.next()) {
Book b=new Book();
b.setBid(rs.getInt(1));
b.setBname(rs.getString(2));
b.setPrice(rs.getDouble(3));
list.add(b);
}
}catch(Exception e){
e.printStackTrace();
}finally {
DBUtil.closeDB(rs, ps, con);
}
}
return list;
}版本二:
通用查询思路
将sql语句,参数,分页对象,转换器做为参数传入该方法,判断是否需要分页,
如果需要,编写sql(显示条数)查询当前页的数据,将数据结果集转换成对象,显示当前页面;
如果不需要,执行查询,直接返回结果集。
public class BaseDao {
/*
* 转换接口:
* 我不知道怎么将数据库结果集转换成对象,我需要covert该接口帮我进行转换。
*
*/
public interface IConvert<T>{
public List<T> convert(ResultSet rs) throws SQLException;
}
public final <T> List<T> query(
String sql,//sql
Object[] params,//参数
PageBean pb,//分页对象
IConvert<T> convert//转换器
){
List<T> list=new ArrayList<>();
Connection con=null;
PreparedStatement ps=null;
ResultSet rs=null;
/**
* ||条件或 只要满足第一个条件,后面的条件就不再判断
* && 条件与 要满足第一个条件与第二条件
*/
if(pb ==null || !pb.isPagination()) {//不分页
try {
con=DBUtil.getConection();
ps=con.prepareStatement(sql);
/*
* 循环Object[]数组,将参数一个个放入sql
*/
int i=1;
for (Object param : params) {
ps.setObject(i, param);
i++;
}
rs=ps.executeQuery();
//将查询到数据库结果集转换成对象
list=convert.convert(rs);
return list;
} catch (Exception e) {
e.printStackTrace();
}finally {
DBUtil.closeDB(rs, ps, con);
}
}else {
try{//需要分页
//总页面
String countsql="select count(*) from ("+sql+") p";
con=DBUtil.getConection();
ps=con.prepareStatement(countsql);
int i=1;
for (Object param : params) {
ps.setObject(i, param);
i++;
}
rs=ps.executeQuery();
if(rs.next()) {
pb.setTotal(rs.getInt(1));
}
if(pb.getTotal()<=0) {//无记录
return list;
}
//查询当前页的数据
String pageql=sql+" limit "+pb.getStartIndex()+","+pb.getRows();
ps=con.prepareStatement(pageql);
int j=1;
for (Object param : params) {
ps.setObject(j, param);
j++;
}
rs=ps.executeQuery();
list=convert.convert(rs);
}catch(Exception e){
e.printStackTrace();
}finally {
DBUtil.closeDB(rs, ps, con);
}
}
return list;
}
}测试类
public class Bookdao extends BaseDao{
/**
* @param bname 查询关键字
* @param pb 分页对象
* @return
*/
public List<Book> getbook(String bname,PageBean pb){
String sql="select * from t_book";
List<Object> params=new ArrayList<>();
if(!StringUtils.isNullOrEmpty(bname)) {//判断字符串是否为空引用或者值为空的方法
sql+=" where bname like ?";
params.add(bname+"%");//添加查询条件
}
//params.toArray()当使用Arraylist数组,可以获取一个实际的数组
/**
* 子类继承父类后,this对象表达的意思,主要看this调用的是那个类的方法。如果指定父类方法,就表示调用父类方法
* 如果指定子类方法,就表示调用子类方法
*/
List<Book> list=this.query(sql, params.toArray(), pb, new IConvert<Book>() {
@Override
public List<Book> convert(ResultSet rs) throws SQLException {
List<Book> list = new ArrayList<>();
while (rs.next()) {
Book b=new Book();
b.setBid(rs.getInt(1));
b.setBname(rs.getString(2));
b.setPrice(rs.getDouble(3));
list.add(b);
}
return list;
}
});
return list;
}
public static void main(String[] args) {
Bookdao bs=new Bookdao();
PageBean pageBean = new PageBean();
System.out.println(pageBean.isPagination());//结果:flase
pageBean.setPagination(true);
List<Book> queryBook = bs.getbook("",pageBean );
System.out.println(queryBook);
}
}注意事项:
||条件或 只要满足第一个条件,后面的条件就不再判断
&& 条件与 要满足第一个条件与第二条件转换接口:
作用:我不知道怎么将数据库结果集转换成对象,我需要covert该接口帮我进行转换。
代码展示
public interface IConvert<T>{ public List<T> convert(ResultSet rs) throws SQLException; } public final <T> List<T> query( String sql,//sql Object[] params,//参数 PageBean pb,//分页对象 IConvert<T> convert//转换器 ){ //将查询到数据库结果集转换成对象 list=convert.convert(rs); }this对象
public class Bookdao extends BaseDao{ /** * * @param bname 查询关键字 * @param pb 分页对象 * @return */ public List<Book> getbook(String bname,PageBean pb){ String sql="select * from t_book"; List<Object> params=new ArrayList<>(); if(!StringUtils.isNullOrEmpty(bname)) {//判断字符串是否为空引用或者值为空的方法 sql+=" where bname like ?"; params.add(bname+"%");//添加查询条件 } //params.toArray()当使用Arraylist数组,可以获取一个实际的数组 List<Book> list=this.query(sql, params.toArray(), pb, new IConvert<Book>() { @Override public List<Book> convert(ResultSet rs) throws SQLException { return list; } }); return list; }this子类继承父类后,this对象表达的意思,主要看this调用的是那个类的方法。如果指定父类方法,就表示调用父类方法;如果指定子类方法,就表示调用子类方法。
公用代码
只要是分页,就会统计总记录数,而总记录数的统计是在业务sql外封装了一个select count(*)是有规律可循的,可以通用
只要是分页,则封装分页sql也是有规律可循的(在业务sql后加limit子句即可),可以通用
Book页面
<h2>学生信息</h2>
<form action="<%=request.getContextPath()%>/BookServlet" method="post">
<input type="text" name="bname"> <input type="submit"
value="查询">
</form>
<!--如果该集合为空,就将servlet数据加载到页面 -->
<c:if test="${empty list }">
<jsp:forward page="/BookServlet"></jsp:forward>
</c:if>
<table border="1" style="width: 100%" >
<tr>
<td>编号</td>
<td>书名</td>
<td>价格</td>
</tr>
<c:forEach items="${list }" var="b">
<tr>
<td>${b.bid }</td>
<td>${b.bname }</td>
<td>${b.price }</td>
</tr>
</c:forEach>
</table>
<div style="text-align: right; width:98%;">
第${pageBean.page}页
共${pageBean.totalPage}条记录
<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" size="2" id="pageNumber" onkeyup="toPage(event,this.value)" />
<a href="#">GO</a>
</div>
<!-- 用于分页的隐藏表单 -->
<form action="${pageBean.url}" id="pagingForm" method="post">
<input type="hidden" name="page" value="${pageBean.page}"/>
<!-- 先只考虑本功能的查询参数,没有考虑公用性(不同功能的参数不同) -->
<input type="hidden" name="bname" value="<%=request.getParameter("bname")%>"/>
</form>
<script type="text/javascript">
function goPage(pageNum){
let form=document.getElementById("pagingForm");
form.page.value=pageNum;
form.submit();
}
/**
*键盘点击事件
*event事件对象
*/
function toPage(e,pageNumber){
if(e.keyCode == 13){//回车键的阿斯特吗值
goPage(pageNumber);
}
}
</script> 与数据库交互的BookServlet
@WebServlet("/BookServlet")
public class BookServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PageBean pb=new PageBean();
pb.setRows(5);
pb.setPagination(true);
pb.setRequest(request);//PageBean保存的
String bname=request.getParameter("bname");
Bookdao b=new Bookdao();
List<Book> list = b.query1Book(bname,pb);
request.setAttribute("list", list);
request.getRequestDispatcher("Book.jsp").forward(request, response);
}
}
边栏推荐
- PIP reports an error could not find a version that satisfies the... No matching distribution
- Squeeze and incentive networks
- Leetcode-168.excel table column name
- Compose Canvas饼图效果绘制
- Liupeng, vice president of copu: China's open source has approached or reached the world's advanced level in some areas
- 使用“soup.h1.text”爬虫提取标题会多一个\
- 面试官:生成订单30分钟未支付,则自动取消,该怎么实现?
- 软件配置 | Anaconda下载、安装及环境配置和卸载
- pinia(菠萝)
- C语言基础篇 —— 2-6 指针、数组与sizeof运算符
猜你喜欢

Acquisition of positional reliability in accurate target detection

Using "soup.h1.text" crawler to extract the title will be one more\

二十四节气之大暑

【Flutter -- 布局】线性布局(Row 和 Column)

通用分页功能

The first stage of basic knowledge of numpy data analysis (numpy Foundation)

低代码搭建校园信息化管理系统案例分析

Eureka notes

AXI interconnect IP核的说明及用法

YOLOV7
随机推荐
Ie box model and standard box model
Four cores of browser
浏览器四大内核
Nodejs implements token login registration (koa2)
[30. N-queen problem]
Direct exchange
Eureka笔记
【Flutter -- 布局】弹性布局(Flex 和 Expanded)
leetcode-67.二进制求和
VMware虚拟机的三种网络模式
银河证券网上开户,手机上开户安不安全
Scale Match for Tiny Person Detection
JMeter之函数二次开发/插件开发(细版)
Heartless sword English Chinese bilingual poem 006. to my wife
MySQL 啥时候用表锁,啥时候用行锁?
考过PMP对实际工作帮助大吗?
英特尔nuc能代替主机吗_终于圆满了!最新款的Intel NUC迷你主机上线
Using "soup.h1.text" crawler to extract the title will be one more\
How does MySQL query data that is not in the database?
泰山OFFICE技术讲座:段落边框的布局绘制分析