JSP标签实现分页功能(ORM-mybatis)

分页对象

package com.pcitc.modules.pagination;

import java.io.Serializable;
import java.util.Arrays;
import java.util.List;
/**
 * 通用分页类
 * @author mi
 *
 * @param <T>
 */
public class Pagination<T> implements Serializable{

    private static final long serialVersionUID = 1L;
    public static final int DEF_PAGE_SIZE = 3; //默认显示10条数据
    public static final int DEF_DISLAY_PAGENUM = 10; //默认显示十个页码

    protected int displayPageNum = DEF_DISLAY_PAGENUM; //默认显示10个页码
    protected int totalCount = 0; //总记录条数
    protected int pageSize = DEF_PAGE_SIZE; //页面中显示的数据多少
    protected int pageNo = 1; //当前页码
    protected List<T> pageData; //分页中显示的数据的集合

    protected int startRow = 0;//起始行
    protected int totalPageNo; //总的页码数
    protected int[] pageNums; //页面显示的页码集

    private String pageSizeName;
    private String pageNoName;
    private String totalCountName;

    public Pagination() {
    }

    /**
     * 构造器
     * 
     * @param pageNo
     *            页码
     * @param pageSize
     *            每页几条数据
     * @param totalCount
     *            总共几条数据
     */
    public Pagination(int pageNo, int pageSize, int totalCount) {

        setPageSize(pageSize);
        setTotalCount(totalCount);
        setPageNo(pageNo);

        calculateTotalPageNo(); //计算总的页码数
        adjustPageNo(); //调整页码
        caculateStartRow(); //进行startRow的计算
        calculateDisNum(); //进行页码显示计算

    }


    /**
     * 进行总的参数的调整,适合setter所有参数后,进行参数的调整
     */
    public void adjustAllProcess(){
        calculateTotalPageNo(); //计算总的页码数
        adjustPageNo(); //调整页码
        caculateStartRow(); //进行startRow的计算
        calculateDisNum(); //进行页码显示计算
    }

    /**
     * 调整传入的请求页码
     */
    public void adjustPageNo() {

        if(this.totalPageNo < this.pageNo && this.totalPageNo > 0){
            this.pageNo = this.totalPageNo;
        }
    }

    /**
     * 进行startRow的计算
     */
    public void caculateStartRow() {
        this.startRow = (this.pageNo -1) * this.pageSize;
    }

    /**
     * 计算总的页码数,注意这样一定要先注入pageSize和totalCount
     */
    public void calculateTotalPageNo() {
        this.totalPageNo = this.totalCount%this.pageSize == 0?this.totalCount/this.pageSize:this.totalCount/this.pageSize+1;
    }

    /**
     * 获得页码
     */
    public int getPageNo() {
        return pageNo;
    }

    /**
     * 每页几条数据
     */
    public int getPageSize() {
        return pageSize;
    }

    /**
     * 总共几条数据
     */
    public int getTotalCount() {
        return totalCount;
    }



    /**
     * 是否第一页
     */
    public boolean isFirstPage() {
        return pageNo <= 1;
    }

    /**
     * 是否最后一页
     */
    public boolean isLastPage() {
        return pageNo >= this.totalPageNo;
    }

    /**
     * 下一页页码
     */
    public int getNextPage() {
        if (isLastPage()) {
            return pageNo;
        } else {
            return pageNo + 1;
        }
    }

    /**
     * 上一页页码
     */
    public int getPrePage() {
        if (isFirstPage()) {
            return pageNo;
        } else {
            return pageNo - 1;
        }
    }

    /**
     * if totalCount<0 then totalCount=0
     * 
     * @param totalCount
     */
    public void setTotalCount(int totalCount) {
        if (totalCount < 0) {
            this.totalCount = 0;
        } else {
            this.totalCount = totalCount;
        }
    }

    /**
     * if pageSize< 1 then pageSize=DEF_COUNT
     * 
     * @param pageSize
     */
    public void setPageSize(int pageSize) {
        if (pageSize < 1) {
            this.pageSize = DEF_PAGE_SIZE;
        } else {
            this.pageSize = pageSize;
        }
    }

    /**
     * if pageNo < 1 then pageNo=1
     * 
     * @param pageNo
     */
    public void setPageNo(int pageNo) {
        if (pageNo < 1) {
            this.pageNo = 1;
        } else {
            this.pageNo = pageNo;
        }
    }



    /**
     * 进行显示页码的计算
     */
    public void calculateDisNum(){

        if(this.totalPageNo > this.displayPageNum){
            this.pageNums = new int[this.displayPageNum];

            int bet = (this.displayPageNum % 2 == 0 ? this.displayPageNum /2 : (this.displayPageNum /2+1));
            if(this.pageNo <= bet){

                for(int i=1;i<=this.displayPageNum;i++){
                    pageNums[i-1] = i;
                }

            }else{
                //后面没有那么多
                if((this.pageNo + bet) > this.totalPageNo){

                    for(int i=(this.totalPageNo-this.displayPageNum+1),j=0;i<=this.totalPageNo;i++,j++){
                        this.pageNums[j] = i;
                    }

                }else{
                    //偶数
                    if(this.displayPageNum % 2 == 0){

                        for(int i=(this.pageNo-bet),j=0;i<=(this.pageNo+bet-1);i++){

                            this.pageNums[j] = i;
                            j++;
                        }
                    }else{
                        for(int i=(this.pageNo-bet+1),j=0;i<=(this.pageNo+bet-1);i++){
                            System.out.println(i);
                            this.pageNums[j] = i;
                            j++;
                        }
                    }
                }
            }

        }else{
            this.pageNums = new int[this.totalPageNo];
            for(int i=1;i<=this.totalPageNo;i++){
                this.pageNums[i-1] = i;
            }
        }

    }
    public List<T> getPageData() {
        return pageData;
    }

    public void setPageData(List<T> pageData) {
        this.pageData = pageData;
    }

    public int getStartRow() {

        return startRow;
    }

    public void setStartRow(int startRow) {
        this.startRow = startRow;
    }

    public int getTotalPageNo() {
        return totalPageNo;
    }

    public void setTotalPageNo(int totalPageNo) {
        this.totalPageNo = totalPageNo;
    }

    public int getDisplayPageNum() {
        return displayPageNum;
    }

    public void setDisplayPageNum(int displayPageNum) {

        if(displayPageNum <= 1){
            this.displayPageNum = DEF_DISLAY_PAGENUM;
        }else{
            this.displayPageNum = displayPageNum;
        }
    }

    @Override
    public String toString() {
        return "Pagination [displayPageNum=" + displayPageNum + ", totalCount="
                + totalCount + ", pageSize=" + pageSize + ", pageNo=" + pageNo
                + ", pageData=" + pageData + ", startRow=" + startRow
                + ", totalPageNo=" + totalPageNo + ", pageNums="
                + Arrays.toString(pageNums) + "]";
    }

    public int[] getPageNums() {
        return pageNums;
    }

    public String getPageSizeName() {
        return pageSizeName;
    }

    public void setPageSizeName(String pageSizeName) {
        this.pageSizeName = pageSizeName;
    }

    public String getPageNoName() {
        return pageNoName;
    }

    public void setPageNoName(String pageNoName) {
        this.pageNoName = pageNoName;
    }

    public String getTotalCountName() {
        return totalCountName;
    }

    public void setTotalCountName(String totalCountName) {
        this.totalCountName = totalCountName;
    }
}

Mybatis的plugin的实现

  • 我这里选择拦截StatementHandler的prepare方法,也就是基本的JDBC中在发出SQL语句之的拦截,这里我们使用根据用户的SQL语句来查出相应的记录的总条数,因为在分页对象中这个参数是很必不可少的。
  • 然后,进行分页(Pagination)参数的计算,当然这些计算已经封装在Pagination对象中。然后,根据计算的结果来进行重构Mybatis发出的SQL语句,也就是分页查询的最终SQL语句,对于Mysql和Orcale对于分页查询的语句是不同的,当然,这需要我们在配置插件的时候,进行指导数据库方言的属性。
  • 对于用户来讲,这一切都是透明的。对于插件,我们都知道,这是在搭建框架的时候,我们总是用抽象的接口来组织逻辑,然后通过配置的方式来增加接口的实现,从而达到了插件的效果。这里进行配置是至关重要的,这里似乎用到AOP的思想,Advice为通知接口为我们自定义接口实现的逻辑方法,配置就相当于Advisor,Pointcut就是切入点。
package com.pcitc.modules.pagination;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;

import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.ReflectorFactory;
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
import org.apache.ibatis.reflection.factory.ObjectFactory;
import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
import org.apache.ibatis.scripting.defaults.DefaultParameterHandler;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.RowBounds;


/**
 * 通过拦截<code>StatementHandler</code>的<code>prepare</code>方法,重写sql语句实现物理分页。
 * 老规矩,签名里要拦截的类型只能是接口。
 * 
 * @author 湖畔微风
 * 
 */
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class})})
public class PageInterceptor implements Interceptor {

    private static final Log logger = LogFactory.getLog(PageInterceptor.class);
    private static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();
    private static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();
    private static final ReflectorFactory DEFAULT_OBJECT_REFLECT_FACTORY = new DefaultReflectorFactory();

    private static String defaultDialect = "mysql"; // 数据库类型(默认为mysql)
    private static String dialect = ""; // 数据库类型(默认为mysql)


    @Override
    public Object intercept(Invocation invocation) throws Throwable {

        //只重写需要分页的sql语句。通过MappedStatement的ID匹配,默认重写以Page结尾的MappedStatement的sql
        //进行Threadlocal进行分页参数的提取
        Pagination<Object> page  =  PaginationManager.getPagination();
        //若不存在分页参数
        if(null == page){
             //将执行权交给下一个拦截器
            PaginationManager.remove();
            return invocation.proceed();
        }
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        MetaObject metaStatementHandler = MetaObject.forObject(statementHandler, DEFAULT_OBJECT_FACTORY,
                DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_OBJECT_REFLECT_FACTORY);
        // 分离代理对象链(由于目标类可能被多个拦截器拦截,从而形成多次代理,通过下面的两次循环可以分离出最原始的的目标类)
        while (metaStatementHandler.hasGetter("h")) {
            Object object = metaStatementHandler.getValue("h");
            metaStatementHandler = MetaObject.forObject(object, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_OBJECT_REFLECT_FACTORY);
        }
        // 分离最后一个代理对象的目标类
        while (metaStatementHandler.hasGetter("target")) {
            Object object = metaStatementHandler.getValue("target");
            metaStatementHandler = MetaObject.forObject(object, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_OBJECT_REFLECT_FACTORY);
        }
        Configuration configuration = (Configuration) metaStatementHandler.getValue("delegate.configuration");
        if(null != configuration.getVariables()){
            dialect = configuration.getVariables().getProperty("dialect"); //设置数据库方言,默认为mysql
        }

        if (null == dialect || "".equals(dialect)) {
            logger.warn("Property dialect is not setted,use default 'mysql' ");
            dialect = defaultDialect;
        }

       MappedStatement mappedStatement = (MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement");
       BoundSql boundSql = (BoundSql) metaStatementHandler.getValue("delegate.boundSql");
       String sql = boundSql.getSql();
       // 采用物理分页后,就不需要mybatis的内存分页了,所以重置下面的两个参数
       Connection connection = (Connection) invocation.getArgs()[0];
       // 重设分页参数里的总页数等,若没有totalCount的数值
       if(page.getTotalCount() <= 0){
           setPagination(sql, connection, mappedStatement, boundSql, page);
       }
       page.adjustAllProcess(); //进行参数的调整
       // 重写sql
       String pageSql = buildPageSql(sql, page);
       metaStatementHandler.setValue("delegate.boundSql.sql", pageSql);
       metaStatementHandler.setValue("delegate.rowBounds.offset", RowBounds.NO_ROW_OFFSET);
       metaStatementHandler.setValue("delegate.rowBounds.limit", RowBounds.NO_ROW_LIMIT);

       // 将执行权交给下一个拦截器
       return invocation.proceed();
    }

    /**
     * 从数据库里查询总的记录数并计算总页数,回写进分页参数<code>Pagination</code>,这样调用者就可用通过 分页参数
     * <code>Pagination</code>获得相关信息。
     * 
     * @param sql
     * @param connection
     * @param mappedStatement
     * @param boundSql
     * @param page
     */
    private void setPagination(String sql, Connection connection, MappedStatement mappedStatement,
            BoundSql boundSql, Pagination<Object> page) {
        // 记录总记录数
        String countSql = "select count(0) from (" + sql + ") as total";
        PreparedStatement countStmt = null;
        ResultSet rs = null;
        try {
            countStmt = connection.prepareStatement(countSql);
            BoundSql countBS = new BoundSql(mappedStatement.getConfiguration(), countSql,
                    boundSql.getParameterMappings(), boundSql.getParameterObject());
            setParameters(countStmt, mappedStatement, countBS, boundSql.getParameterObject());
            rs = countStmt.executeQuery();
            int totalCount = 0;
            if (rs.next()) {
                totalCount = rs.getInt(1);
            }

            page.setTotalCount(totalCount);


        } catch (SQLException e) {
            logger.error("Ignore this exception", e);
        } finally {
            try {
                rs.close();
            } catch (SQLException e) {
                logger.error("Ignore this exception", e);
            }
            try {
                countStmt.close();
            } catch (SQLException e) {
                logger.error("Ignore this exception", e);
            }
        }

    }

    /**
     * 对SQL参数(?)设值
     * 
     * @param ps
     * @param mappedStatement
     * @param boundSql
     * @param parameterObject
     * @throws SQLException
     */
    private void setParameters(PreparedStatement ps, MappedStatement mappedStatement, BoundSql boundSql,
            Object parameterObject) throws SQLException {
        ParameterHandler parameterHandler = new DefaultParameterHandler(mappedStatement, parameterObject, boundSql);
        parameterHandler.setParameters(ps);
    }

    /**
     * 根据数据库类型,生成特定的分页sql
     * 
     * @param sql
     * @param page
     * @return
     */
    private String buildPageSql(String sql, Pagination<Object> page) {
        if (page != null) {
            StringBuilder pageSql = new StringBuilder();
            if ("mysql".equals(dialect)) {
                pageSql = buildPageSqlForMysql(sql, page);
            } else if ("oracle".equals(dialect)) {
                pageSql = buildPageSqlForOracle(sql, page);
            } else {
                return sql;
            }
            return pageSql.toString();
        } else {
            return sql;
        }
    }

    /**
     * mysql的分页语句
     * 
     * @param sql
     * @param page
     * @return String
     */
    public StringBuilder buildPageSqlForMysql(String sql, Pagination<Object> page) {
        StringBuilder pageSql = new StringBuilder(100);
        String beginrow = String.valueOf(page.getStartRow());
        pageSql.append(sql);
        pageSql.append(" limit " + beginrow + "," + page.getPageSize());
        return pageSql;
    }

    /**
     * 参考hibernate的实现完成oracle的分页
     * 
     * @param sql
     * @param page
     * @return String
     */
    public StringBuilder buildPageSqlForOracle(String sql, Pagination<Object> page) {
        StringBuilder pageSql = new StringBuilder(100);
        pageSql.append("select * from ( select temp.*, rownum row_id from ( ");
        pageSql.append(sql);
        pageSql.append(" ) temp where rownum <= ").append(page.getPageNo() * page.getPageSize());
        pageSql.append(") where row_id > ").append(page.getStartRow());
        return pageSql;
    }

    @Override
    public Object plugin(Object target) {
        // 当目标类是StatementHandler类型时,才包装目标类,否者直接返回目标本身,减少目标被代理的次数
        if (target instanceof StatementHandler) {
            return Plugin.wrap(target, this);
        } else {
            return target;
        }
    }

    @Override
    public void setProperties(Properties properties) {
    }

}

Filter的实现

  • 这里通过Filter的配置来进行,需要分页的URL的定位,因为对于分页来讲我们需要进入同一个URL来进行取出数据库中不同位置的数据而已,只是需要传递不同的参数,如页码。
  • 在Filter方法中,我们首先进行分页对象的初建立,并将其放入到ThreadLocal中,这样是为了mybatis中分页插件,能够拿到分页的部分参数,通过判断是否是用户第一次进入分页页码,来判断是否需要发出来统计分页总的记录数的语句。如需要发出总记录数相应的SQL语句,然后进行重构分页对象。
  • 而且在doFilterChain方法后面需要释放,ThreadLocal中的线程变量,这里是至关重要的。
  • 为什么要释放线程变量?(大坑)
    因为我们知道Tomcat的架构,对于不同的请求是不同的线程来进行处理的,会给我们一个实现的接口servlet或者Filter来进行业务的处理。这里,tomcat的线程不是进行new出来的,因为对于new的操作需要耗费资源,这里采用的是线程池的方式,同样的思想体现于Datasource中。假如,一个线程池中有20个线程(这里可通过tomcat配置文件进行配置),时间上不同的请求可能用的是同一个线程池中某一个线程。那么,上一个线程存放的线程变量就可能被下一个线程取到相应的数据,所以我们需要在一个线程结束的时候,进行线程变量的清楚。
package com.pcitc.modules.pagination;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class PaginationFilter implements Filter {

      public static String PAGE_SIZE = "pageSize";
       public static String PAGE_NO = "pageNo";
       public static String TOTAL_COUNT = "totalCount";

       private String pageSizeName = PAGE_SIZE;
       private String pageNoName = PAGE_NO;
       private String totalCountName = TOTAL_COUNT;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void destroy() {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain filterChain) throws IOException, ServletException {
          System.out.println("分页插件,过滤器开始");
          Integer pageSize = Integer.valueOf((request.getParameter(pageSizeName) == null)?"0":request.getParameter(pageSizeName));
          Integer pageNo = Integer.valueOf(request.getParameter(pageNoName) == null?"0":request.getParameter(pageNoName));
          Integer totalCount = Integer.valueOf(request.getParameter(totalCountName)== null?"0":request.getParameter(totalCountName));

          Pagination<Object> pagination = new Pagination<Object>();
          pagination.setPageNoName(pageNoName);
          pagination.setPageSizeName(pageSizeName);
          pagination.setTotalCountName(totalCountName);
          pagination.setPageSize(pageSize);
          pagination.setPageNo(pageNo);
          pagination.setTotalCount(totalCount);
          PaginationManager.setPagination(pagination);
          filterChain.doFilter(request, response);
          System.out.println("释放ThreadLoca中的值");
          PaginationManager.remove();
    }


}

自定义JSP标签的实现

  • 因为分页的HTML和CSS我们不能控制,为了减少代码侵入性,我们采用给标签中提供相应的分页信息,来让前端人员来自己对样式和dom结构的定义。
package com.pcitc.modules.pagination;

import java.io.IOException;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;

public class PaginationTag extends SimpleTagSupport{

    public static String COMMON = "common"; //页码组信息
    public static String PREPAGE = "prePage"; //前一页信息
    public static String POSTPAGE = "postPage"; //后一页信息

    private String searchUrl;
    private String pageType = COMMON; //判断是否是首页或者尾页

    @Override
    public void doTag() throws JspException, IOException{  

        //循环遍历页面显示页码数
        Pagination<Object> pagination = PaginationManager.getPagination();

        if(pagination != null){
            int[] pageNums = pagination.getPageNums();
            if("common".equals(pageType)){

                for(int i=0;i<pageNums.length;i++){

                    String url = this.searchUrl;
                    if(!searchUrl.contains("?")){
                        url = url + "?";
                    }

                    url = url + "&" + pagination.getPageSizeName() + "=" + pagination.getPageSize()
                            + "&" + pagination.getPageNoName() + "=" + pageNums[i]
                            + "&" + pagination.getTotalCountName() + "=" + pagination.getTotalCount();

                    //将分页的URL和pageNum设置到page 范围
                    getJspContext().setAttribute("pageUrl",url); 
                    getJspContext().setAttribute("pageNum", pageNums[i]);
                     getJspContext().setAttribute("pageInfo", pagination);
                    //输出标签体  

                    getJspBody().invoke(null);


                }
            }else{
                if(pageNums.length > 1){
                    if(PREPAGE.equals(pageType)){
                        String url = this.searchUrl;
                        if(!searchUrl.contains("?")){
                            url = url + "?";
                        }

                        url = url + "&" + pagination.getPageSizeName() + "=" + pagination.getPageSize()
                                + "&" + pagination.getPageNoName() + "=" + pagination.getPrePage()
                                + "&" + pagination.getTotalCountName() + "=" + pagination.getTotalCount();
                        //将分页的URL和pageNum设置到page 范围
                        getJspContext().setAttribute("pageUrl",url); 
                        getJspContext().setAttribute("pageNum", pagination.getPrePage());
                        getJspContext().setAttribute("pageInfo", pagination);
                        //输出标签体  

                        getJspBody().invoke(null);  

                    }else if(POSTPAGE.equals(pageType)){
                        String url = this.searchUrl;
                        if(!searchUrl.contains("?")){
                            url = url + "?";
                        }

                        url = url + "&" + pagination.getPageSizeName() + "=" + pagination.getPageSize()
                                + "&" + pagination.getPageNoName() + "=" + pagination.getNextPage()
                                + "&" + pagination.getTotalCountName() + "=" + pagination.getTotalCount();
                        //将分页的URL和pageNum设置到page 范围
                        getJspContext().setAttribute("pageUrl",url); 
                        getJspContext().setAttribute("pageNum", pagination.getNextPage());
                         getJspContext().setAttribute("pageInfo", pagination);
                        //输出标签体  

                        getJspBody().invoke(null);    
                    }else{
                        String url = this.searchUrl;
                        if(!searchUrl.contains("?")){
                            url = url + "?";
                        }

                        url = url + "&" + pagination.getPageSizeName() + "=" + pagination.getPageSize()
                                + "&" + pagination.getTotalCountName() + "=" + pagination.getTotalCount()
                                + "&" + pagination.getPageNoName() + "=";
                        //将分页的URL的元素设置到page 范围
                         getJspContext().setAttribute("pageUrl",url); 
                         getJspContext().setAttribute("pageInfo", pagination);
                          //输出标签体  
                         getJspBody().invoke(null);  
                    }


                }
            }


        }

     }  


    public String getSearchUrl() {
        return searchUrl;
    }

    public void setSearchUrl(String searchUrl) {
        this.searchUrl = searchUrl;
    }

    public String getPageType() {
        return pageType;
    }


    public void setPageType(String pageType) {
        this.pageType = pageType;
    }


}

tld文件:

<?xml version="1.0" encoding="UTF-8" ?>
<taglib xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
    version="2.1">

  <description>JSTL 1.1 core library</description>
  <display-name>JSTL core</display-name>
  <tlib-version>1.1</tlib-version>
  <short-name>util</short-name>
  <uri>http://ctbu.com/liumi</uri>
  <!-- 标签展示通用类 -->
  <tag>
    <name>page</name>
    <tag-class>com.pcitc.web.controller.common.PaginationTag</tag-class>
    <body-content>scriptless</body-content>
    <!-- 标签体中可以取出pageUrl,pageNum,pageInfo对象用来页面的展示和判断 -->
    <attribute>
      <name>searchUrl</name>
      <required>true</required>
      <rtexprvalue>true</rtexprvalue>
      <type>java.lang.String</type>
    </attribute>
    <attribute>
      <name>pageType</name>
      <required>false</required>
      <rtexprvalue>true</rtexprvalue>
      <type>java.lang.String</type>
      <description>common--代表显示的页码,prePage代表上一页信息,postPage代表下一页信息</description>
    </attribute>
  </tag>
</taglib>

JSP使用标签的简单实例:

<!--这里需要web.xml文件中引入相应utl文件位置-->
<%@ taglib  uri="http://ctbu.com/liumi" prefix="util"%>
<util:page searchUrl="${ctx}/news/list" pageType="other">
这里相当于通过pageType属性来获取相应的分页的信息:
other:则是获取分页的信息
common:会进行所有显示在页面页码的迭代出不同URL,
        通过${pageUrl}来获取
prePage和postPage:进行前页和后页信息的获取
        显示第 ${pageInfo.startRow+1} 至     
        ${pageInfo.startRow+listSize} 项结果,共 
        ${pageInfo.totalCount} 项
</util:page>    
<--上一页-->     
<util:page searchUrl="${ctx}/news/list" pageType="prePage">
  <c:if test="${pageInfo.totalCount > pageInfo.pageSize}">
    <li id="" class="paginate_button previous"> 
        <a href="${pageUrl}">上页</a>
        </li>
 </c:if>
</util:page>

<!--所有页码-->
<util:page searchUrl="${ctx}/news/list" pageType="common"> 
 <c:if test="${pageInfo.totalCount > pageInfo.pageSize}">
   <li class="paginate_button <c:if test='${pageInfo.pageNo == pageNum}'>active</c:if>">
        <a href="${pageUrl}">${pageNum}</a>
  </li>
 </c:if>
</util:page>

<!--后一页-->
<util:page searchUrl="${ctx}/news/list" pageType="postPage">
<c:if test="${pageInfo.totalCount > pageInfo.pageSize}">
    <li id="" class="paginate_button next">
    <a tabindex="0" data-dt-idx="8" aria-controls="userTabel" href="${pageUrl}">下页</a>
    </li>                   
</c:if>
</util:page>

ThreadLocal来进行Filter到JSP中分页对象传递

package com.pcitc.modules.pagination;


/**
 * 将分页数据进行线程级别传递
 * @author mi
 *
 */
public class PaginationManager {

     //使用ThreadLocal保存Connection变量  
    private static final ThreadLocal<Pagination<Object>> pageHolder = new ThreadLocal<Pagination<Object>>(); 

    public static Pagination<Object> getPagination(){
        //ThreadLocal取得当前线程的分页数据
        return pageHolder.get();
    }

    public static void setPagination(Pagination<Object> pagination){
        pageHolder.set(pagination);
    }

    public static void remove(){
        pageHolder.remove();
    }

}

使用说明

  • 在web.xml中进行对Filter的配置,主要是对那个URL进行分页的
    拦截,和对tld文件的引入(jar包中meta文件中tld文件不用引入):
<filter>
        <filter-name>paginationFilter</filter-name>
        <filter-class>
            com.pcitc.modules.pagination.PaginationFilter
        </filter-class>
    </filter>
    <filter-mapping>
        <filter-name>paginationFilter</filter-name>
        <url-pattern>/news/list</url-pattern>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
    </filter-mapping>
  <jsp-config>
    <taglib>
          <taglib-uri>http://ctbu.com/liumi</taglib-uri>
          <taglib-location>/WEB-INF/util.tld</taglib-location>
    </taglib>
    </jsp-config>
  • 配置mybatis拦截器
<plugins>
<plugin interceptor="com.pcitc.modules.pagination.PageInterceptor">
   <!-- 或者mysql -->
   <property name="dialect" value="oracle"/>
</plugin>
</plugins>
  • 在JSP表中引入:
<%@ taglib  uri="http://ctbu.com/liumi" prefix="util"%>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值