通用分页超详细介绍(附带源代码解析&页面展示效果)

1.BookDao实现及测试

创建BookDao并定义实现书本查全部方法,最后完成Junit方法测试。

public class BookDao extends BaseDao<Book>{
    /**
     * 添加
     * @param book
     */
    public void addBook(Book book){
        Connection con = null;
        PreparedStatement ps = null;
        try{
            //获取连接对象
            con=DBHelper.getConnection();
            ps=con.prepareStatement("insert into t_book values(?,?,?,?)");
            ps.setString(1,book.getBookid());
            ps.setString(2,book.getBookname());
            ps.setFloat(3,book.getPrice());
            ps.setString(4,book.getBooktype());
            //执行SQL语句并返回影响行数
            int i=ps.executeUpdate();
            if(i<0)
                throw new Exception("执行失败,影响函数为0");
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            DBHelper.close(con,ps,null);
        }
    }

    /**
     * 模糊查询
     * @param book
     * @return
     */
    public List<Book> getByLike(Book book, PageBean pageBean) {
        String sql = "select * from t_book where 1=1";
        if (StringUtils.isNotBlank(book.getBookname()))
            sql += " and bookname like '%" + book.getBookname() + "%'";
        System.out.println(sql);
        return super.executeQuery(sql, pageBean, new CallBack<Book>() {
            @Override
            public List<Book> foreachRs(ResultSet rs) throws SQLException {
              return CommonUtils.toList(rs,Book.class);
            }
        });
    }
}

2.BookServlet实现及页面效果展示

创建BookServlet并调用BookDao中查全部方法实现书本查询。

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");
        //创建Book对象
        Book book=new Book();
        book.setBookname(bookname);
        //调用模糊查询方法
        PageBean pageBean=new PageBean();
        BookDao bookDao=new BookDao();
        //获取前端传入的请求参数集
        pageBean.setRequest(req);
        List<Book> books = bookDao.getByLike(book,pageBean);
        //将查询结果保存到request作用域中
        req.setAttribute("books",books);
        //将pageBean保存到request作用域中
        req.setAttribute("pageBean",pageBean);
        //转发
        req.getRequestDispatcher("index.jsp").forward(req,resp);
    }
}

1)打开web.xml,配置中文乱码过滤器EncodingFilter和书本查询Servlet控制器;

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <!--1、配置中文过滤器-->
    <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>com.zking.pagintation.uitl.EncodingFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <!--2、配置Servlet的servlet-->
    <servlet>
        <servlet-name>Servlet</servlet-name>
        <servlet-class>com.zking.pagintation.servlet.BookServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>Servlet</servlet-name>
        <url-pattern>/Servlet.do</url-pattern>
    </servlet-mapping>
    <!--3、配置欢迎页-->
    <welcome-file-list>
        <welcome-file>/index.jsp</welcome-file>
    </welcome-file-list>
</web-app>

2)创建BookServlet.jsp页面实现书本查询效果展示。

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="z" uri="/zking" %>
<html>
<head>
    <title>通用分页</title>
</head>
<body>
<h1>通用分页</h1>
<form method="post" action="Servlet.do">
    <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>
    </tr>
    <c:forEach var="b" items="${books}">
        <tr>
            <td>${b.bookid}</td>
            <td>${b.bookname}</td>
            <td>${b.price}</td>
            <td>${b.booktype}</td>
        </tr>
    </c:forEach>
</table>
<z:pagination pageBean="${pageBean}"/>
</body>
</html>

3.通用分页实现

3.1.MySQL分页

  • limit语法

select * from table_name limit [offset,] rows
  • 参数说明

参数说明
offset指定第一个返回记录行的偏移量(即从哪一行开始返回),注意:初始行的偏移量为0
rows返回具体行数

3.2.PageBean

创建PageBean分页标记类,用于定义分页相关要素。

/**
 * 分页工具类
 */
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[]> maps;

    public void setRequest(HttpServletRequest req){
        //1、获取前端传入的分页三要素(page,rows,pagination)
        String page = req.getParameter("page");
        String rows = req.getParameter("rows");
        String pagination = req.getParameter("pagination");

        this.setPage(page);
        this.setRows(rows);
        this.setPagination(pagination);
        //2、获取上一次请求的URL路径
        //req.getContextPath == 获取项目名
        //req.getServletPath() == 获取servlet请求路径名
        //req.getRequestURL == req.getContextPath+req.getServletPath()
        this.url=req.getRequestURI();
        //3、获取上一次请求的所有请求参数集合

        this.maps = req.getParameterMap();
    }



    /**
     * 返回limit分页查询的开始位置
     * @return
     */
    public int getStartIndex(){
        return (this.page-1)*this.rows;
    }

    //重载set方法
    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 setPagination(String pagination) {
        if(null!=pagination)
            this.pagination = Boolean.parseBoolean(pagination);
    }

    /**
     * //分页方法
     * //计算总分页
     * @return 总分页数
     */
    public int getMaxPager(){
        int max = this.total/this.rows;
        //除不尽有余数
        if(this.total%this.rows!=0)
            max++;
            return max;
    }

    /**
     * 上一页方法
     * @return 上一页页数
     */
    public int getPrevPager(){
        int prev = this.page-1;
        if(prev<=1)
            prev=1;
        return prev;
    }

    /**
     * 下一页方法
     * @return 下一页页数
     */
    public int getNextPager(){
        int next=this.page+1;
        if(next>=getMaxPager())
            next=getMaxPager();
        return next;
    }

    public String getUrl() {
        return url;
    }

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

    public Map<String, String[]> getMaps() {
        return maps;
    }

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

    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;
    }

    @Override
    public String toString() {
        return "PageBean{" +
                "page=" + page +
                ", rows=" + rows +
                ", total=" + total +
                ", pagination=" + pagination +
                ", url='" + url + '\'' +
                ", maps=" + maps +
                '}';
    }
}

3.3.BaseDao

创建BaseDao通用分页类并定义相关分页方法。

3.3.1分页查询方法

public class BaseDao<T> {
/**
     * 通用分页方法 (分页或不分页)
     * @param sql 普通SQL语句
     * @param pageBean 分页标记对象
     * @return 返回分页结果集
     */
    public List<T> executeQuery(String sql, PageBean pageBean,CallBack<T> callBack){
        Connection con=null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        try{
            con= DBHelper.getConnection();
            if(null!=pageBean&&pageBean.isPagination()){
                //分页
                //1)根据满足的条件查询分页总记录数
                String countSQL = this.getCountSQL(sql);
                ps=con.prepareStatement(countSQL);
                rs=ps.executeQuery();
                if(rs.next()){
                    int total = rs.getInt(1);
                    //将查询得到的总记录数存入Page Bean对象中的total属性
                    pageBean.setTotal(total);
                }
                //2)根据满足的条件查询分页结果集
                sql = this.getPagerSQL(sql, pageBean);
            }
                ps=con.prepareStatement(sql);
                rs=ps.executeQuery();
                return callBack.foreachRs(rs);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            DBHelper.close(con,ps,rs);
        }
        return null;
    }
}

在executeQuery方法中根据PageBean对象及对象属性pagination识别是否分页。

  • 分页:查询分页结果、集查询总记录数

  • 将普通的SQL语句转换成分页查询的SQL语句

/**
     * 将普通的SQL语句转换成分页查询的SQL语句
     * @param sql 普通SQL语句
     * @param pageBean 分页标记对象
     * @return 分页查询的SQL语句
     */
    private String getPagerSQL(String sql,PageBean pageBean){
        return sql+" limit "+pageBean.getStartIndex()+","+pageBean.getRows();
    }
  •  将普通sql语句转换成查总记录数的sql
    /**
     * 将普通sql语句转换成查总记录数的sql
     * @param sql
     * @return 查询总记录数的SQL语句
     */
    private String getCountSQL(String sql){
        return "select count(*) from ("+sql+") temp";
    }
 
  • 不分页:只查询数据结果集(不查询分页记录和总记录数)

3.3.2.匿名内部接口

在BaseDao类中定义匿名内部接口,该接口中的forEach方法只用于循环遍历ResultSet查询结果集并返回List<T>

/**
* 用于遍历结果集数据的回调接口
* @author Administrator
* @param <T>
*/

public static interface CallBack<T>{
        public List<T> foreachRs(ResultSet rs) throws SQLException;
    }

修改executeQuery方法,将匿名内部接口CallBack当做入参传入方法中。

public List<T> executeQuery(String sql, PageBean pageBean,CallBack<T> callBack){
        Connection con=null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        try{
            con= DBHelper.getConnection();
            if(null!=pageBean&&pageBean.isPagination()){
                //分页
                //1)根据满足的条件查询分页总记录数
                String countSQL = this.getCountSQL(sql);
                ps=con.prepareStatement(countSQL);
                rs=ps.executeQuery();
                if(rs.next()){
                    int total = rs.getInt(1);
                    //将查询得到的总记录数存入Page Bean对象中的total属性
                    pageBean.setTotal(total);
                }
                //2)根据满足的条件查询分页结果集
                sql = this.getPagerSQL(sql, pageBean);
            }
                ps=con.prepareStatement(sql);
                rs=ps.executeQuery();
                return callBack.foreachRs(rs);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            DBHelper.close(con,ps,rs);
        }
        return null;
    }

3.3.3.Junit单元测试

Junit是一个Java测试框架,使编写可靠和高效的测试变得容易。它可以用于大多数语言制作的应用程序,但特别适合于测试Java应用程序。Junit也可以用来创建自动测试。

Junit框架是最流行的Java测试框架之一。它提供了一些功能,使编写测试变得容易,包括支持多个测试用例、断言和报告。Junit也是多功能的,允许用各种语言编写测试。

setUp():在方法之前执行

tearDown:在方法之后执行

public class BookDaoTest {
​
    @Before
    public void setUp() throws Exception {
    }
​
    @After
    public void tearDown() throws Exception {
    }
​
    @Test
    public void testQueryBookPager() {
        fail("Not yet implemented");
    }
​
}

Junit中的setUp和tearDown方法是根据方法数量来决定的

4.增强PageBean

package com.zking.pagintation.uitl;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

/**
 * 分页工具类
 */
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[]> maps;

    public void setRequest(HttpServletRequest req){
        //1、获取前端传入的分页三要素(page,rows,pagination)
        String page = req.getParameter("page");
        String rows = req.getParameter("rows");
        String pagination = req.getParameter("pagination");

        this.setPage(page);
        this.setRows(rows);
        this.setPagination(pagination);
        //2、获取上一次请求的URL路径
        //req.getContextPath == 获取项目名
        //req.getServletPath() == 获取servlet请求路径名
        //req.getRequestURL == req.getContextPath+req.getServletPath()
        this.url=req.getRequestURI();
        //3、获取上一次请求的所有请求参数集合
        this.maps = req.getParameterMap();
    }



    /**
     * 返回limit分页查询的开始位置
     * @return
     */
    public int getStartIndex(){
        return (this.page-1)*this.rows;
    }

    //重载set方法
    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 setPagination(String pagination) {
        if(null!=pagination)
            this.pagination = Boolean.parseBoolean(pagination);
    }

    /**
     * //分页方法
     * //计算总分页
     * @return 总分页数
     */
    public int getMaxPager(){
        int max = this.total/this.rows;
        //除不尽有余数
        if(this.total%this.rows!=0)
            max++;
            return max;
    }

    /**
     * 上一页方法
     * @return 上一页页数
     */
    public int getPrevPager(){
        int prev = this.page-1;
        if(prev<=1)
            prev=1;
        return prev;
    }

    /**
     * 下一页方法
     * @return 下一页页数
     */
    public int getNextPager(){
        int next=this.page+1;
        if(next>=getMaxPager())
            next=getMaxPager();
        return next;
    }

    public String getUrl() {
        return url;
    }

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

    public Map<String, String[]> getMaps() {
        return maps;
    }

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

    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;
    }

    @Override
    public String toString() {
        return "PageBean{" +
                "page=" + page +
                ", rows=" + rows +
                ", total=" + total +
                ", pagination=" + pagination +
                ", url='" + url + '\'' +
                ", maps=" + maps +
                '}';
    }
}

5.创建自定义分页标签

5.1.创建自定义分页标签助手类

package com.zking.pagintation.tag;

import com.zking.pagintation.uitl.PageBean;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.BodyTagSupport;
import java.util.Map;
import java.util.Set;

public class PaginationTag extends BodyTagSupport {

    private PageBean pageBean;

    public PageBean getPageBean() {
        return pageBean;
    }

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

    @Override
    public int doStartTag() throws JspException {
        try{
            JspWriter out = pageContext.getOut();
            out.print(toHtml());
        }catch (Exception e){
            e.printStackTrace();
        }
        return SKIP_BODY;
    }

    private String toHtml(){
        //判断PageBean是否为空
        if(null!=pageBean&&pageBean.isPagination()){
            //定义StringBuffer可变字符串
            //面试题:String/StringBuffer/StringBuilder/的区别
            StringBuffer sb=new StringBuffer();
            //拼接div跟标签
            sb.append("<div style=\"float: right;\">");
            //拼接form标签对象
            sb.append("<form id=\"pageForm\" method=\"post\" action="+pageBean.getUrl()+">");
            //拼接page隐藏域
            sb.append(" <input type=\"hidden\" name=\"page\"/>");
            //获取请求参数集合
            Map<String,String[]> maps=pageBean.getMaps();
            //获取请求参数集合的键值对
            Set<Map.Entry<String, String[]>> entries = maps.entrySet();
            //循环遍历请求参数键值对
            for (Map.Entry<String, String[]> entry : entries) {
                //判断请求参数是否是page,如果是 则continue
                if(entry.getKey().equalsIgnoreCase("page"))
                    continue;
                //获取请求参数的value值(类型为String[])
                String[] values = entry.getValue();
                //循环遍历value值
                for(String value : values){
                    sb.append("<input type='hidden' name='"+entry.getKey()+"' value='"+value+"'>");
                }
            }
            sb.append("</form>");
            //拼接分页信息
            sb.append("第"+pageBean.getPage()+"页/总"+pageBean.getMaxPager()+"页数");
            //拼接首页、上一页、下一页、末页
            if(pageBean.getPage()==1)
                sb.append("首页&nbsp;上一页");
            else {
                sb.append("<a onclick=\"gotoPage(1)\" href=\"javascript:void(0);\">首页</a>");
                sb.append("<a onclick=\"gotoPage("+pageBean.getPrevPager()+")\" href=\"javascript:void(0);\">上一页</a>");
            }

            if(pageBean.getPage()==pageBean.getMaxPager())
                sb.append("下一页&nbsp;末页");
            else {
                sb.append("<a onclick=\"gotoPage("+pageBean.getNextPager()+")\" href=\"javascript:void(0);\">下一页</a>");
                sb.append("<a onclick=\"gotoPage("+pageBean.getMaxPager()+")\" href=\"javascript:void(0);\">末页</a>");
            }
            //拼接javascpit
            sb.append("<script>\n" +
                    "    function gotoPage(page){\n" +
                    "        document.getElementById('pageForm').page.value=page;\n" +
                    "        document.getElementById('pageForm').submit();\n" +
                    "    }\n" +
                    "</script>");
            sb.append("</div>");
            return sb.toString();
        }
        return "";
    }

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

5.2.导入标签描述文件

详见课件"z.tld"文件

 

5.3.自定义分页标签实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值