分页版本
版本参考链接
分页一 | https://blog.csdn.net/licmi/article/details/106441305 |
---|---|
分页二 | https://blog.csdn.net/licmi/article/details/106461125 |
概念
将上一次查询请求再发一次,只不过页码变了
通用思路
相信大家跟我一样,刚开始了解通用分页时不懂,不知道哪里通用了,还是感觉代码很多。
我举个例子,假如我有4张表需要实现分页,那么我需要在每个方法类都写分页查询方法是可以实现的,那如果我有上百个表呢,那么重复的代码就很多。
所以想一个办法把共性的代码部分,构成通用性的代码。(baseDao)
package com.liuchunming.dao;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import com.liuchunming.entity.Book;
import com.liuchunming.util.DBAccess;
import com.liuchunming.util.PageBean;
import com.liuchunming.util.StringUtils;
public class BaseDao<T> {
public List<T> executeQuery(String sql, Class clz,PageBean pageBean) throws SQLException, InstantiationException, IllegalAccessException{
List<T> list =new ArrayList<T>();
Connection con = DBAccess.getConnection();
PreparedStatement ps = null;
ResultSet rs = null;
if(pageBean !=null&&pageBean.isPagination()) {
//分页
//查询满足条件的总记录数
String countSql =getCountSql(sql);
ps = con.prepareStatement(countSql);
rs = ps.executeQuery();
if(rs.next()) {
pageBean.setTotal(rs.getObject(1)+"");
}
//查询满足条件需要显示的记录
String pageSql =getPageSql(sql,pageBean);
ps = con.prepareStatement(pageSql);
rs = ps.executeQuery();
}else {
//不分页
ps = con.prepareStatement(sql);
rs = ps.executeQuery();
}
while(rs.next()) {
T t = (T) clz.newInstance();
//获取对象的所有属性
for (Field f : clz.getDeclaredFields()) {
f.setAccessible(true);//打开权限
f.set(t, rs.getObject(f.getName()));//给属性赋值
}
//添加到集合
list.add(t);
}
DBAccess.close(con, ps, rs);
return list;
}
/**
* 查询第几页的数据
* @param sql
* @param pageBean
* @return
*/
private String getPageSql(String sql, PageBean pageBean) {
return sql+" limit "+pageBean.getStartIndex()+","+pageBean.getRows()+"";
}
/**
* 根据原生sql带有的条件查询总记录数
* @param sql
* @return
*/
private String getCountSql(String sql) {
return "select count(1) from ("+sql+") t";
}
}
通用baseDao讲解
首先是泛型。为什么要用泛型,因为我不知道谁要使用我的方法,使用泛型的话,只要继承把类带上就能使用里面的方法了。
public class BaseDao<T> {
public List<T> executeQuery(String sql, Class clz,PageBean pageBean) throws
列如book类继承
public class BookDao extends BaseDao<Book>{
通用方法三个参数
sql就是谁继承谁传sql语句
clz指对象
pagebean是指分页的方法,获取和赋值
public List<T> executeQuery(String sql, Class clz,PageBean pageBean)
这里我们可以先写一个getCountSql
无论我们传什么Sql语句过来我们只需要进行拼接就可以获取到总记录数
private String getCountSql(String sql) {
return "select count(1) from ("+sql+") t";
}
用来获取到下标和 每页显示多少条
private String getPageSql(String sql, PageBean pageBean) {
return sql+" limit "+pageBean.getStartIndex()+","+pageBean.getRows()+"";
}
上面说到,谁继承就传谁的类,那么对象里的属性怎么赋值呢?
我们用到了反射
T t = (T) clz.newInstance();
//获取对象的所有属性
Field[] fa = clz.getDeclaredFields();
for (Field f : fa) {
f.setAccessible(true);//打开权限
f.set(t, rs.getObject(f.getName()));//给属性赋值
}
//添加到集合
list.add(t);
这里说一个容易错误的点
private static final long serialVersionUID = 1L;
使用反射获取属性,实体类里不要实现序列号接口(Serializable)。因为反射会获取对象的所有属性
子类实现方法
package com.liuchunming.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import com.liuchunming.entity.Book;
import com.liuchunming.util.DBAccess;
import com.liuchunming.util.PageBean;
import com.liuchunming.util.StringUtils;
public class BookDao extends BaseDao<Book>{
//改装后的
public List<Book> list(Book book,PageBean pageBean) throws SQLException, InstantiationException, IllegalAccessException{
String sql=" select * from t_mvc_book where true";
String bname = book.getBname();
if(StringUtils.isNotBlank(bname)) {
sql+=" and bname like '%"+bname+"%'";
}
return super.executeQuery(sql, Book.class, pageBean);
}
}
是不是感觉简单多了!!
然后就是分页工具类
package com.liuchunming.util;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
/**
* 分页工具类
*
*/
public class PageBean {
private int page = 1;// 页码
private int rows = 10;// 页大小
private int total = 0;// 总记录数
private boolean pagination = true;// 是否分页
//上一次查询的url
private String url;
//上一次查询所携带的查询条件
private Map<String, String[]> pageMap =new HashMap<String, String[]>();
public void setRequest(HttpServletRequest req) {
//页面传递过来的当前页
this.setPage(req.getParameter("page"));
//传递过来的页大小
this.setRows(req.getParameter("rows"));
//页面传递过来的是否分页
this.setPagination(req.getParameter("pagination"));
//将上一次的查询请求保留
this.setUrl(req.getRequestURL().toString());
//将上一次查询条件的请求进行保留
this.setPageMap(req.getParameterMap());
}
private void setPagination(String pagination) {
//只有填写了字符串false才能不分页
this.setPagination(!"false".equals(pagination));
}
//重载如果不为空转为int类型
private void setRows(String rows) {
if(StringUtils.isNotBlank(rows))
this.setRows(Integer.valueOf(rows));
}
private void setPage(String page) {
if(StringUtils.isNotBlank(page))
this.setPage(Integer.valueOf(page));
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public Map<String, String[]> getPageMap() {
return pageMap;
}
public void setPageMap(Map<String, String[]> pageMap) {
this.pageMap = pageMap;
}
public PageBean() {
super();
}
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 void setTotal(String total) {
this.total = Integer.parseInt(total);
}
public boolean isPagination() {
return pagination;
}
public void setPagination(boolean pagination) {
this.pagination = pagination;
}
/**
* 上一页
* @return
*/
public int getPrevPage() {
return this.page > 1 ? this.page-1 : this.page;
}
/**
* 下一页
* @return
*/
public int getNextPage() {
return this.page < getMaxPage() ? this.page +1 : this.page;
}
/**
* 最大页
* @return
*/
public int getMaxPage() {
return this.total % this.rows ==0 ? this.total/this.rows : (this.total/this.rows)+1;
}
/**
* 获得起始记录的下标
*
* @return
*/
public int getStartIndex() {
return (this.page - 1) * this.rows;
}
}
page助手类
package com.liuchunming.tag;
import java.io.IOException;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.BodyTagSupport;
import com.liuchunming.util.PageBean;
public class PageTag extends BodyTagSupport{
private static final long serialVersionUID = 1L;
private PageBean pageBean;
public PageBean getPageBean() {
return pageBean;
}
public void setPageBean(PageBean pageBean) {
this.pageBean = pageBean;
}
@Override
public int doStartTag() throws JspException {
JspWriter out = pageContext.getOut();
try {
out.print(toHTML());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return super.doStartTag();
}
private String toHTML() {
StringBuilder sb=new StringBuilder();
//拼接下一次发送请求所要提交的隐藏的form表单
sb.append("<form id='pageBeanForm' action='"+pageBean.getUrl()+"' method='post'>");
//差第几页的数据
sb.append("<input type='hidden' name='page'>");
Map<String, String[]> pageMap = pageBean.getPageMap();
if(pageMap.size()>0) {
Set<Entry<String,String[]>> entrySet = pageMap.entrySet();
for (Entry<String, String[]> entry : entrySet) {
if(!"page".equals(entry.getKey())) {
for(String val:entry.getValue()) {
sb.append("<input type='hidden' value='"+val+"' name='"+entry.getKey()+"'>");
}
}
}
}
sb.append("</form>");
//默认展示前面四页
int page =pageBean.getPage();//获取当前页
int max=pageBean.getMaxPage();//获取最大页
//当前页前面的页码是否大于4,大于就是4,小于前面页码-1
int before = page > 4 ? 4 : page-1;
//总共10页减去当前页,再减去当前页前面的页码
int after = 10 - 1 - before;
//最大页-当前页
after = max-page > after ? after : max-page;
//用来控制上一页点击按钮特效的
boolean startFlag = page > 1;
//用来控制下一页点击按钮特效的
boolean endFlag = max == page;
// 拼接分页条
sb.append("<ul class='pagination'>");
sb.append("<li class='page-item "+(startFlag ? "disabled" : "")+"'><a class='page-link' href='javascript:gotoPage(1)'>首页</a></li>");
sb.append("<li class='page-item "+(startFlag ? "disabled" : "")+"'><a class='page-link' href='javascript:gotoPage("+pageBean.getPrevPage()+")'><</a></li>");
// 代表了当前页的前4页
for (int i = before; i > 0 ; i--) {
sb.append("<li class='page-item'><a class='page-link' href='javascript:gotoPage("+(page-i)+")'>"+(page-i)+"</a></li>");
}
sb.append("<li class='page-item active'><a class='page-link' href='javascript:gotoPage("+pageBean.getPage()+")'>"+pageBean.getPage()+"</a></li>");
// 代表了当前页的后5页
for (int i = 1; i <= after; i++) {
sb.append("<li class='page-item'><a class='page-link' href='javascript:gotoPage("+(page+i)+")'>"+(page+i)+"</a></li>");
}
sb.append("<li class='page-item "+(endFlag ? "disabled" : "")+"'><a class='page-link' href='javascript:gotoPage("+pageBean.getNextPage()+")'>></a></li>");
sb.append("<li class='page-item "+(endFlag ? "disabled" : "")+"'><a class='page-link' href='javascript:gotoPage("+pageBean.getMaxPage()+")'>尾页</a></li>");
sb.append("<li class='page-item go-input'><b>到第</b><input class='page-link' type='text' id='skipPage' name='' /><b>页</b></li>");
sb.append("<li class='page-item go'><a class='page-link' href='javascript:skipPage()'>确定</a></li>");
sb.append("<li class='page-item'><b>共"+pageBean.getTotal()+"条</b></li>");
sb.append("</ul>");
// 拼接分页的js代码
sb.append("<script type='text/javascript'>");
sb.append("function gotoPage(page) {");
sb.append("document.getElementById('pageBeanForm').page.value = page;");
sb.append("document.getElementById('pageBeanForm').submit();");
sb.append("}");
sb.append("function skipPage() {");
sb.append("var page = document.getElementById('skipPage').value;");
sb.append("if (!page || isNaN(page) || parseInt(page) < 1 || parseInt(page) > "+max+") {");
sb.append("alert('请输入1~N的数字');");
sb.append("return;");
sb.append("}");
sb.append("gotoPage(page);");
sb.append("}");
sb.append("</script>");
return sb.toString();
}
}
实现规则:总共显示10个页码,当前页码前4个页码后5页码,再就是是否到达一个最大页最小页临界点禁用
int page =pageBean.getPage();//获取当前页
int max=pageBean.getMaxPage();//获取最大页
//当前页前面的页码是否大于4,大于就是4,小于前面页码-1
int before = page > 4 ? 4 : page-1;
//总共10页减去当前页,再减去当前页前面的页码
int after = 10 - 1 - before;
//最大页减当前页
after = max-page > after ? after : max-page;
//用来控制上一页点击按钮特效的
boolean startFlag = page > 1;
//用来控制下一页点击按钮特效的
boolean endFlag = max == page;
拼接完后就是写tld描述文件,写完后在jsp界面进行引用就行了
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@taglib prefix="l" uri="/liuchunming"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.5.0/css/bootstrap.css" rel="stylesheet">
<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.5.0/js/bootstrap.js"></script>
<style type="text/css">
.page-item input {
padding: 0;
width: 40px;
height: 100%;
text-align: center;
margin: 0 6px;
}
.page-item input,
.page-item b {
line-height: 38px;
float: left;
font-weight: 400;
}
.page-item.go-input {
margin: 0 10px;
}
</style>
</head>
<body>
<form class="form-inline" action="${pageContext.request.contextPath}/book.action">
<div class="form-group">
<div class="input-group">
<input type="text" class="form-control" name="bname" placeholder="请输入书籍名称">
</div>
</div>
<button type="submit" class="btn btn-primary">搜索</button>
</form>
<table class="table table-striped table table-bordered">
<tr>
<td class="active">书籍ID</td>
<td class="success">书籍名称</td>
<td class="warning">书籍价格</td>
</tr>
<c:forEach items="${bookList }" var="i">
<tr>
<td >${i.bid }</td>
<td >${i.bname }</td>
<td >${i.price }</td>
</tr>
</c:forEach>
</table>
<l:page pageBean="${pageBean }"></l:page>
</body>
</html>
这里是用到是bootstap在线的样式库,需要联网才能使用
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.5.0/css/bootstrap.css" rel="stylesheet">
<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.5.0/js/bootstrap.js"></script>
感兴趣的朋友可以去官网瞧瞧Boostrap中文网
jsp的样式也是在boostrap里找到
action处理层
package com.liuchunming.web;
import java.io.IOException;
import java.sql.SQLException;
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.liuchunming.dao.BookDao;
import com.liuchunming.entity.Book;
import com.liuchunming.util.PageBean;
@WebServlet(name="book",urlPatterns="/book.action" )
public class BookAction extends HttpServlet{
private static final long serialVersionUID = 1L;
private BookDao bookDao =new BookDao();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Book book=new Book();
book.setBname(req.getParameter("bname"));
PageBean pageBean =new PageBean();
pageBean.setRequest(req);
try {
List<Book> list = bookDao.list(book, pageBean);
req.setAttribute("bookList", list);
req.setAttribute("pageBean", pageBean);
//resp.sendRedirect("bookList.jsp");
req.getRequestDispatcher("bookList.jsp").forward(req, resp);
} catch (InstantiationException | IllegalAccessException | SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
效果图
总结
今天就到这里了如果有什么不对的地方欢迎大家在评论区留言交流改进!!