1、通用分页概述(基于MySql数据库的通用分页)

通用分页就是把我们经常使用的分页方法进行封装,然后用泛型传递对象,利用反射获取对象的所有属性并且赋值。

2、为何要使用通用分页?

一般在实际项目的开发过程中我们会有很多数据的展示,并且数据量大,展示的数据种类繁多,这意味着我们要写很多重复的代码,我们可将重复相同的代码提取出来进行封装,后期进行调用即可。

3、通用分页核心思路:将上一次查询请求再发一次,只不过页码变了

4、环境配置(如何实现分页)

1、明确我们的需求是什么?
2、在实际项目开发中分页需要哪些参数?

页码(每页所展示的数据)、总记录数、是否分页、点击下一页或者上一页所需地址

PageBean 分页三要素 page 页码 视图层传递过来 rows 页大小 视图层传递过来 total 总记录数 后台查出来 pagination 是否分页 视图层传递过来 getStartIndex() 基于MySql数据库分页,获取分页开始标记

4.1.以书籍为例,创建一个书籍表,同时再创建一个书籍项目

create table t_book(
	book_id int not null primary key auto_increment comment '书本编号',
	book_name varchar(30) not null comment '书本名称',
	book_name_pinyin varchar(30) null comment '书本拼音',
	book_price float default 0 comment '书本价格',
	book_type varchar(10) not null comment '书本类型'
)comment '书本信息表';


#分页(limit)
#limit 参数1,参数2				(page-1)*rows
#参数1:从第几条数据开始	
#参数2:每次返回多少条数据	rows
#第一页:从0开始,返回2条
#第二页:从2开始,返回2条

 4.2.项目中的相关配置以及导入必要的依赖

MySQL语句分页 mysql分页怎么实现_java

MySQL语句分页 mysql分页怎么实现_java_02

依赖:
mysql-connector-java-5.1.44-bin.jar        MySQL的驱动类
pinyin4j-2.5.0.jar        拼音的jar,作用是可以快速的将中文转变成英文,只提取拼音首字母

standard-1.1.2.jar        jstl标签
jstl-1.2.jar
工具类:
CommonUtils.java        反射封装ResultSet结果集
DBHelper.java        连接数据库
config.properties        资源文件 
 EncodingFiter.java        中文乱码过滤器
 StringUtils.java        判断字符串是否存在(为空)
 PageTag.java        自定义标签的助手类
 PageBean.java        分页工具类PinYinUtil.java         拼音工具类

4.3.先写一个分页工具类,用于实现分页效果。

package com.zking.pagination.util;

import java.io.Serializable;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

/**
 * 	分页工具类
 * @author gss
 *
 */
public class PageBean implements Serializable{
	//当前页码,默认1
	private int page=1;
	//页面显示条数,默认10
	private int rows=10;
	//总记录数,默认0
	private int total=0;
	//是否分页标记,默认分页
	private boolean pageination=true;
	
	//http://localhost:8080/pagination/BookServlet.action
	///pagination/BookServlet.action
	//获取上一次请求路径
	private String url;
	
	//获取上一次请求的请求参数集合
	// Map<String,String[]> params=req.getParameterMap();
	//	<input type="text" name="bookname" value="1"/>
	private Map<String,String[]> params;
	
	public PageBean() {
		super();
	}
	
	/**
	 * 获取起始记录的下标(基于Mysql分页,计算limit分页开始位置)
	 * @return
	 */
	public int getStartIndex() {
		return (this.page-1)*this.rows;
	}
	
	public void setRequest(HttpServletRequest req) {
		//获取前端提交的请求参数(分页三要素:页码、页大小、总记录数 )
		String page = req.getParameter("page");
		String rows = req.getParameter("rows");
		String pagination = req.getParameter("pagination");
		
		//赋值
		this.setPage(page);
		this.setRows(rows);
		this.setPageination(pagination);
		
		//获取上一次请求的请求路径
		//http://localhost:8080/pagination/BookServlet.action
		//	req.getRequestURI()==等同于/pagination/BookServlet.action
		//	req.getContextPath()==项目名/pagination
		//	req.getServletPath()==请求路径/BookServlet.action
		//当前路径
		this.url = req.getRequestURI();
		//获取上一次请求的请求参数集合
		//Map<String,String[]>-->params.put("bookname",new String[]{"",""})
		this.params = req.getParameterMap();
	}
	/**
	 * 	获取最大页码
	 * @return
	 */
	public int getMaxPager() {
		int p = this.total/this.rows;
		//判断是否有余数,如果有余数,则最大页码+1
		if(this.total%this.rows!=0)
			p++;
		return p;
	}
	/**
	 * 	获取上一页
	 * @return
	 */
	public int getProviousPager() {
		int p = this.page-1;
		if(p<1)
			p=1;
		return p;
	}
	/**
	 * 	获取下一页
	 * @return
	 */
	public int getNextPager() {
		int p = this.page+1;
		if(this.page>=this.getMaxPager())
			p=this.getMaxPager();
		return p;
	}
	
	public void setPage(String page) {
		if(null!=page)
			this.page = Integer.parseInt(page);
	}
	public void setRows(String rows) {
		if(null!=rows)
			this.rows = Integer.parseInt(rows);
	}
	public void setPageination(String pageination) {
		if(null!=pageination)
		this.pageination = Boolean.parseBoolean(pageination);
	}
	
	
	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 isPageination() {
		return pageination;
	}

	public void setPageination(boolean pageination) {
		this.pageination = pageination;
	}

	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	public Map<String, String[]> getParams() {
		return params;
	}

	public void setParams(Map<String, String[]> params) {
		this.params = params;
	}

	@Override
	public String toString() {
		return "PageBean [page=" + page + ", rows=" + rows + ", total=" + total + ", pageination=" + pageination
				+ ", url=" + url + ", params=" + params + "]";
	}

}

BaseDao.java(是一个通用的父类方法,来帮助我们实现通用的分类)

package com.zking.pagination.dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import com.zking.pagination.util.DBHelper;
import com.zking.pagination.util.PageBean;

public class BaseDao<T> {
	public static interface CallBack<K>{
		//只用于遍历ResultSet结果集
		public List<K> foreachRs(ResultSet rs) throws SQLException;
	}
	
	/**
	 * 	通用分页方法(既支持分页,也支持不分页)
	 * @param sql	普通的sql
	 * @param pageBean	pageBean 分页对象
	 * @return	查询结果集
	 */
	public List<T> excuteQuery(String sql,PageBean pageBean,CallBack<T> callBack){
		//声明对象
		Connection conn = null;
		PreparedStatement stmt = null;
		ResultSet rs = null;
		try {
			//获取连接对象
			conn = DBHelper.getConnection();
			//根据pageBean分页对象判断是否分页
			if(null!=pageBean&&pageBean.isPageination()) {
				//1.分页
				//1)根据满足条件查询总记录数
				String countSQL = this.getCountSQL(sql);
				//创建执行对象
				stmt = conn.prepareStatement(countSQL);
				//执行sql语句并返回总记录数
				rs = stmt.executeQuery();
				//获取总记录数
				if(rs.next()) {
					pageBean.setTotal(rs.getInt(1));
				}
				//2)根据满足条件查询分页结果集
				sql = this.getPagerSQL(sql, pageBean);//覆盖
			}
			//创建执行对象
			stmt = conn.prepareStatement(sql);
			//查询结果集
			rs = stmt.executeQuery();
			
			return callBack.foreachRs(rs);
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			DBHelper.close(conn, stmt, rs);
		}
		return null;
	}
		
		/**
		 * 将普通的sql语句转换成查询总记录条数的sql语句
		 * 	select * from t_book
		 * 	select * from t_book where ...
		 * 	select book_id,book_name from t_book
		 * 	select book_id,book_name from t_book where ...
		 * 	------------>
		 * 	select count(0) from t_book where ...
		 * @param sql	普通的sql
		 * @return 查询总记录数的sql
		 */
		private String getCountSQL(String sql) {
			return "select count(0) from ("+sql+") temp";
		}
		
		/**
		 * 将普通的sql语句转换成查询分页结果集的sql语句
		 * 	select * from t_book
		 * 	select * from t_book where ...
		 * 	select book_id,book_name from t_book
		 * 	select book_id,book_name from t_book where ...
		 * 	------------>
		 * 	select * from t_book limit
		 * 	select * from t_book where 1=1 limit 
		 * @param sql	普通的sql
		 * @param pageBean	分页对象(包含当前页码和每页条数,用于计算分页的关键数据)
		 * @return	查询分页结果集的sql
		 */
		private String getPagerSQL(String sql,PageBean pageBean) {
			return sql+" limit "+pageBean.getStartIndex()+","+pageBean.getRows();
		}
		
}

BookDao.java(dao类继承了BaseDao 父类,代码简洁,通用的方法都在父类中)

package com.zking.pagination.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 javax.management.RuntimeErrorException;
import com.zking.pagination.entity.Book;
import com.zking.pagination.util.DBHelper;
import com.zking.pagination.util.PageBean;
import com.zking.pagination.util.StringUtils;

public class BookDao extends BaseDao<Book>{
	//1、书本新增
	public void addBook(Book book) {
		//声明对象
		Connection conn = null;
		PreparedStatement stmt = null;
		try {
			//获取连接对象
			conn= DBHelper.getConnection();
			//定义sql语句
			String sql = "insert into t_book(book_name,book_name_pinyin,book_price,book_type) values(?,?,?,?)";
			//创建执行对象
			stmt = conn.prepareStatement(sql);
			//参数赋值
			stmt.setString(1, book.getBook_name());
			stmt.setString(2, book.getBook_name_pinyin());
			stmt.setFloat(3, book.getBook_price());
			stmt.setString(4, book.getBook_type());
			//执行sql语句并返回影响行数
			int i = stmt.executeUpdate();
			if(i<1) {
				throw new RuntimeException("影响行数为0,添加失败");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			DBHelper.close(conn, stmt, null);
		}
	}
	
	/**
	 * 2、书本分页查询 	query/find/select/get
	 * @param book 要查询的对象
	 * @return	返回结果集
	 */
	public List<Book> queryBookPager(Book book,PageBean pageBean){
		//定义sql语句
		String sql = "select book_id,book_name,book_name_pinyin,book_price,book_type from t_book where 1=1";
		//拼接查询条件,按照书本名称模糊查询
		if(StringUtils.isNotBlank(book.getBook_name()))
			sql+=" and book_name like '%"+book.getBook_name()+"%'";
		//按照书本编号降序排序
		sql+=" order by book_id desc";
		System.out.println(sql);
		
		 return super.excuteQuery(sql, pageBean, new CallBack<Book>() {
			
			@Override
			public List<Book> foreachRs(ResultSet rs) throws SQLException {
				List<Book> blist = new ArrayList<>();
				//定义Book对象
				Book b = null;
				//循环遍历结果集
				while(rs.next()) {
					//创建Book对象
					b = new Book();
					b.setBook_id(rs.getInt("book_id"));
					b.setBook_name(rs.getString("book_name"));
					b.setBook_name_pinyin(rs.getString("book_name_pinyin"));
					b.setBook_price(rs.getFloat("book_price"));
					b.setBook_type(rs.getString("book_type"));
					//将对象添加到集合中
					blist.add(b);
				}
				return blist;
			}
		});
		
		//以下为查询原生态代码
	/*	List<Book> blist = new ArrayList<>();
		Connection conn = null;
		PreparedStatement stmt = null;
		ResultSet rs = null;
		try {
			//获取连接对象
			conn= DBHelper.getConnection();
			//定义sql语句
			String sql = "select book_id,book_name,book_name_pinyin,book_price,book_type from t_book where 1=1";
			//拼接查询条件,按照书本名称模糊查询
			if(StringUtils.isNotBlank(book.getBook_name()))
				sql+=" and book_name like '%"+book.getBook_name()+"%'";
			//按照书本编号降序排序
			sql+=" order by book_id desc";
			System.out.println(sql);
			//创建执行对象
			stmt = conn.prepareStatement(sql);
			//执行sql语句并返回查询结果集
			rs = stmt.executeQuery();
			//定义Book对象
			Book b = null;
			//循环遍历结果集
			while(rs.next()) {
				//创建Book对象
				b = new Book();
				b.setBook_id(rs.getInt("book_id"));
				b.setBook_name(rs.getString("book_name"));
				b.setBook_name_pinyin(rs.getString("book_name_pinyin"));
				b.setBook_price(rs.getFloat("book_price"));
				b.setBook_type(rs.getString("book_type"));
				//将对象添加到集合中
				blist.add(b);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			DBHelper.close(conn, stmt, rs);
		}
		return blist;*/
	}
}

 BookDaoTest.java        使用Junit测试

package com.zking.pagination.dao;

import static org.junit.Assert.*;
import java.util.List;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.zking.pagination.entity.Book;
import com.zking.pagination.util.PageBean;
import com.zking.pagination.util.PinYinUtil;

public class BookDaoTest {
	Book book = null;
	BookDao bd = new BookDao();

	@Before
	public void setUp() throws Exception {
		//初始化一次
		book = new Book();
		//System.out.println("setUp");
	}

	@After
	public void tearDown() throws Exception {
		//System.out.println("tearDown");
	}

	@Test
	public void testAddBook() {
		for (int i = 0; i < 64; i++) {
			book = new Book();
			book.setBook_name("红楼梦第"+(i+1)+"章");
			book.setBook_name_pinyin(PinYinUtil.toPinyin("红楼梦第"+(i+1)+"章").toLowerCase());
			book.setBook_price(128f);
			book.setBook_type("文学");
			//调用dao类添加方法
			bd.addBook(book);
		}
		//System.out.println("testAddBook");
	}

	@Test
	public void testQueryBookPager() {
		//模糊查询
		book.setBook_name("2");
		PageBean pageBean = new PageBean();
		pageBean.setPage(2);//第二页
		pageBean.setRows(8);//每页条数
		//pageBean.setPageination(false);//不分页
		//调用dao类查询方法
		List<Book> books = bd.queryBookPager(book,pageBean);
		System.out.println("总记录数:"+pageBean.getTotal());
		books.forEach(System.out::println);
	}
}

MySQL语句分页 mysql分页怎么实现_数据库_03

BookServlet.java

package com.zking.pagination.action;

import java.io.IOException;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.zking.pagination.dao.BookDao;
import com.zking.pagination.entity.Book;
import com.zking.pagination.util.PageBean;

public class BookServlet extends HttpServlet {

	@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 {
		//获取请求查询参数
		String bookname = req.getParameter("bookname");
		//实例化BookDao
		BookDao bd = new BookDao();
		//实例化Book
		Book book = new Book();
		book.setBook_name(bookname);
		//创建PageBean
		PageBean pageBean = new PageBean();
		//必须在查询之前完成请求参数赋值
		pageBean.setRequest(req);
		//实现书本查询
		List<Book> books = bd.queryBookPager(book,pageBean);
		//将查询的结果books保存到request作用域中
		req.setAttribute("books", books);
		//将pageBean对象存入到request作用域中
		req.setAttribute("pageBean", pageBean);
		//转发到指定页面并显示查询结果
		req.getRequestDispatcher("/bookList.jsp").forward(req, resp);;
	}

}

      配置web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <display-name>pagination</display-name>
  
  <!-- 配置中文乱码过滤器 -->
  <filter>
  	<filter-name>encodingFilter</filter-name>
  	<filter-class>com.zking.pagination.util.EncodingFilter</filter-class>
  </filter>
  <filter-mapping>
  	<filter-name>encodingFilter</filter-name>
  	<url-pattern>/*</url-pattern>
  </filter-mapping>
  
  <!-- 配置servlet -->
  <servlet>
  	<servlet-name>BookServlet</servlet-name>
  	<servlet-class>com.zking.pagination.action.BookServlet</servlet-class>
  </servlet>
  <servlet-mapping>
  	<servlet-name>BookServlet</servlet-name>
  	<url-pattern>/BookServlet.action</url-pattern>
  </servlet-mapping>

</web-app>

z标签:是我们的分页标签它还有一个主要的类-----PaginationTag助手类,是整个分页的灵魂所在。 

package com.zking.pagination.tag;

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.zking.pagination.util.PageBean;

public class PaginationTag extends BodyTagSupport {

	private PageBean pageBean;
	
	@Override
	public int doEndTag() throws JspException {
		return EVAL_PAGE;
	}

	@Override
	public int doStartTag() throws JspException {
		JspWriter out = pageContext.getOut();
		try {
			out.write(toHtml());
		} catch (Exception e) {
			e.printStackTrace();
		}
		return SKIP_BODY;
	}
	
	private String toHtml() {
		//判断是否分页
		if(null==pageBean||!pageBean.isPageination())
			return "";
		else {
			StringBuilder sb=new StringBuilder();
			//TODO
			sb.append("<div style=\"float:right\">");
			
			//拼接Form表单
			sb.append("<form id=\"pageBeanForm\" action=\""+pageBean.getUrl()+"\" method=\"post\">");
			
			//设置page隐藏域
			sb.append("<input type=\"hidden\" name=\"page\"/>");
			
			//拼接请求参数集合
			Map<String, String[]> map = pageBean.getParams();
			//获取请求参数集合键值对
			Set<Entry<String,String[]>> entrySet = map.entrySet();
			//遍历请求参数键值对
			for (Entry<String, String[]> entry : entrySet) {
				//获取请求参数名,也就是来自于表单中的name属性名称
				String name=entry.getKey();
				//如果参数为page,则continue跳过
				if(name.equals("page"))
					continue;
				//获取请求参数对应的值,String[]
				String[] values=entry.getValue();
				//遍历value值
				for (String value : values) {
					//拼接请求参数
					sb.append("<input type='hidden' name='"+name+"' value='"+value+"'/>");
				}
			}
			
			sb.append("</form>");
			
			//拼接共几页/第几页
			sb.append("[第"+pageBean.getPage()+"页/共"+pageBean.getMaxPager()+"页]");
			
			//拼接首页、上一页、下一页、末页
			if(pageBean.getPage()==1)
				sb.append("首页 上一页 ");
			else {
				sb.append("<a href=\"javascript:gotoPage(1)\">首页</a> ");
				sb.append("<a href=\"javascript:gotoPage("+pageBean.getProviousPager()+")\">上一页</a> ");
			}
			if(pageBean.getPage()==pageBean.getMaxPager())
				sb.append("下一页 末页 ");
			else {
				sb.append("<a href=\"javascript:gotoPage("+pageBean.getNextPager()+")\">下一页</a> ");
				sb.append("<a href=\"javascript:gotoPage("+pageBean.getMaxPager()+")\">末页</a> ");
			}
			
			//拼接跳转页码
			sb.append("<input type=\"text\" id=\"p\" style=\"width:20px;\"/>");
			sb.append("<input type=\"button\" value=\"GO\" onclick=\"javascript:skipPage();\"/>");
			
			//拼接javascript跳转方法
			sb.append("<script type=\"text/javascript\">\r\n" + 
					"function gotoPage(page){\r\n" + 
					"	document.getElementById(\"pageBeanForm\").page.value=page;\r\n" + 
					"	document.getElementById(\"pageBeanForm\").submit();\r\n" + 
					"}");
			
			sb.append("function skipPage(){\r\n" + 
					"	var page=document.getElementById(\"p\").value;\r\n" + 
					"	if(isNaN(page)||page<1||page>="+pageBean.getMaxPager()+"){\r\n" + 
					"		alert('请输入1~"+pageBean.getMaxPager()+"之间数字!');\r\n" + 
					"		return false;\r\n" + 
					"	}\r\n" + 
					"	gotoPage(page);\r\n" + 
					"}\r\n" + 
					"</script>");
			
			sb.append("</div>");
			return sb.toString();
		}
	}

	public PageBean getPageBean() {
		return pageBean;
	}

	public void setPageBean(PageBean pageBean) {
		this.pageBean = pageBean;
	}
	
}

启动Tomcat 

bookList.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@taglib uri="/zking" prefix="z" %>
<!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>
<!-- <script type="text/javascript">
	function gotoPage(p) {
		document.getElementById('ff').page.value=p;
		//javascript的表单提交
		document.getElementById('ff').submit();
	}
	
	function skipPage(max) {
		var page=document.getElementById('go').value;
		if(isNaN(page)||page<1||page>max){//判断非数字
			alert('请输入1~'+max+'之间的数字!');
			return false;
		}
		gotoPage(page);
	}
</script> -->
</head>
<body>
<form action="BookServlet.action" method="post" align="center">
	<label>书本名称:</label><input type="text" name="bookname"/>
	<input type="submit" value="查询"/>
</form>

<table width="100%" border="1" cellpadding="0" cellspacing="0">
	<tr>
		<th>书本编号</th>
		<th>书本名称</th>
		<th>书本拼音</th>
		<th>书本价格</th>
		<th>书本类型</th>
	</tr>
	<c:forEach items="${books }" var="b">
		<tr>
			<th>${b.book_id }</th>
			<th>${b.book_name }</th>
			<th>${b.book_name_pinyin }</th>
			<th>${b.book_price }</th>
			<th>${b.book_type }</th>
		</tr>
	</c:forEach>
</table>
<z:pagination pageBean="${pageBean }"/>
<%-- <div style="float: right;">
	<form id="ff" action="${pageBean.getUrl()}" method="post">
		<input type="hidden" name="page"/>
		<!-- 在此处应该将pageBean中的params属性获取并遍历到当前位置,动态生成input="hidden" -->
		Map<String,String[]> maps = ${pageBean.getParams() }
		<!--循环遍历 -->
		<input type="hidden" name="bookname" value="1"/>
	</form>
	[第${pageBean.getPage()}页/共${pageBean.getMaxPager()}页]
	<a href="javascript:gotoPage(1);">首页</a>
	<a href="javascript:gotoPage(${pageBean.getProviousPager()});">上一页</a>
	<a href="javascript:gotoPage(${pageBean.getNextPager()});">下一页</a>
	<a href="javascript:gotoPage(${pageBean.getMaxPager()});">末页</a>
	<input type="text" id="go" style="width:18px"/>
	<input type="button" value="GO" onclick="skipPage(${pageBean.getMaxPager()})" />
</div> --%>
</body>
</html>

效果图:

MySQL语句分页 mysql分页怎么实现_java_04

MySQL语句分页 mysql分页怎么实现_java_05