基于mybatis 自定义标签分页的实现

Posted TT_DUL

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于mybatis 自定义标签分页的实现相关的知识,希望对你有一定的参考价值。

ssm框架 ,mybatis 分页一直以来都是一个难题,博主也是参考大神的代码,整合到项目中的,废话不多说,看代码

0、最最首先是把page 基础类加进来了

import java.util.List;  
import java.util.Map;  
import org.codehaus.jackson.map.ObjectMapper;  
import org.slf4j.Logger;  
import org.slf4j.LoggerFactory;  
import com.google.common.base.Joiner;  
import com.google.common.collect.Lists;  
import com.google.common.collect.Maps; 

public class Page 


    private static final Logger logger = LoggerFactory.getLogger(Page.class);  
      private static ObjectMapper mapper = new ObjectMapper();  

      public static String DEFAULT_PAGESIZE = "10";  
      private int pageNo;          //当前页码  
      private int pageSize;        //每页行数  
      private int totalRecord;      //总记录数  
      private int totalPage;        //总页数  
      private Map<String, String> params;  //查询条件  
      private Map<String, List<String>> paramLists;  //数组查询条件  
      private String searchUrl;      //Url地址  
      private String pageNoDisp;       //可以显示的页号(分隔符"|",总页数变更时更新)  
      private String tableName;         //查询语句的主表名



    private Page()   
        pageNo = 1;  
        pageSize = Integer.valueOf(DEFAULT_PAGESIZE);  
        totalRecord = 0;  
        totalPage = 0;  
        params = Maps.newHashMap();  
        paramLists = Maps.newHashMap();  
        searchUrl = "";  
        pageNoDisp = "";  
        

      public static Page newBuilder(int pageNo, int pageSize, String url)  
        Page page = new Page();  
        page.setPageNo(pageNo);  
        page.setPageSize(pageSize);  
        page.setSearchUrl(url);  
        return page;  
        

      /** 
       * 查询条件转JSON 
       */  
      public String getParaJson()  
        Map<String, Object> map = Maps.newHashMap();  
        for (String key : params.keySet())  
          if ( params.get(key) != null  )  
            map.put(key, params.get(key));  
            
          
        String json="";  
        try   
          json = mapper.writeValueAsString(map);  
         catch (Exception e)   
          logger.error("转换JSON失败", params, e);  
          
        return json;  
        

      /** 
       * 数组查询条件转JSON 
       */  
      public String getParaListJson()  
        Map<String, Object> map = Maps.newHashMap();  
        for (String key : paramLists.keySet())  
          List<String> lists = paramLists.get(key);  
          if ( lists != null && lists.size()>0 )  
            map.put(key, lists);  
            
          
        String json="";  
        try   
          json = mapper.writeValueAsString(map);  
         catch (Exception e)   
          logger.error("转换JSON失败", params, e);  
          
        return json;  
        

      /** 
       * 总件数变化时,更新总页数并计算显示样式 
       */  
      private void refreshPage()  
        //总页数计算  
        totalPage = totalRecord%pageSize==0 ? totalRecord/pageSize : (totalRecord/pageSize + 1);  
        //防止超出最末页(浏览途中数据被删除的情况)  
        if ( pageNo > totalPage && totalPage!=0)  
            pageNo = totalPage;  
          
        pageNoDisp = computeDisplayStyleAndPage();  
        

      /** 
       * 计算页号显示样式 
       *  这里实现以下的分页样式("[]"代表当前页号),可根据项目需求调整 
       *   [1],2,3,4,5,6,7,8..12,13 
       *   1,2..5,6,[7],8,9..12,13 
       *   1,2..6,7,8,9,10,11,12,[13] 
       */  
      private String computeDisplayStyleAndPage()  
        List<Integer> pageDisplays = Lists.newArrayList();  
        if ( totalPage <= 11 )  
          for (int i=1; i<=totalPage; i++)  
            pageDisplays.add(i);  
            
        else if ( pageNo < 7 )  
          for (int i=1; i<=8; i++)  
            pageDisplays.add(i);  
            
          pageDisplays.add(0);// 0 表示 省略部分(下同)  
          pageDisplays.add(totalPage-1);         
          pageDisplays.add(totalPage);  
        else if ( pageNo> totalPage-6 )  
          pageDisplays.add(1);  
          pageDisplays.add(2);  
          pageDisplays.add(0);  
          for (int i=totalPage-7; i<=totalPage; i++)  
            pageDisplays.add(i);  
                   
        else  
          pageDisplays.add(1);  
          pageDisplays.add(2);  
          pageDisplays.add(0);  
          for (int i=pageNo-2; i<=pageNo+2; i++)  
            pageDisplays.add(i);  
            
          pageDisplays.add(0);  
          pageDisplays.add(totalPage-1);  
          pageDisplays.add(totalPage);  
          
        return Joiner.on("|").join(pageDisplays.toArray());  
        

      public int getPageNo()   
         return pageNo;  
        

      public void setPageNo(int pageNo)   
         this.pageNo = pageNo;  
        

      public int getPageSize()   
         return pageSize;  
        

      public void setPageSize(int pageSize)   
         this.pageSize = pageSize;  
        

      public int getTotalRecord()   
         return totalRecord;  
        

      public void setTotalRecord(int totalRecord)   
        this.totalRecord = totalRecord;  
        refreshPage();       
        

      public int getTotalPage()   
         return totalPage;  
        

      public void setTotalPage(int totalPage)   
         this.totalPage = totalPage;  
        

      public Map<String, String> getParams()   
         return params;  
        

      public void setParams(Map<String, String> params)   
         this.params = params;  
        

      public Map<String, List<String>> getParamLists()   
        return paramLists;  
        

      public void setParamLists(Map<String, List<String>> paramLists)   
        this.paramLists = paramLists;  
        
      public String getSearchUrl()   
        return searchUrl;  
        
      public void setSearchUrl(String searchUrl)   
        this.searchUrl = searchUrl;  
        
      public String getPageNoDisp()   
        return pageNoDisp;  
        
      public void setPageNoDisp(String pageNoDisp)   
        this.pageNoDisp = pageNoDisp;  
       

      public String getTableName() 
        return tableName;
    

    public void setTableName(String tableName) 
        this.tableName = tableName;
    

1、首先当然是control 层了

    @RequestMapping("/addressList")
    public ModelAndView addressList(@RequestParam(required = false, defaultValue = "fhmange") String types ,
            @RequestParam(required = false, defaultValue = "1") int pageNo,  
            @RequestParam(required = false, defaultValue = "25") int pageSize,
            @ModelAttribute LogisticAddress logadd,HttpServletRequest request)


        Page page = Page.newBuilder(pageNo, pageSize, "/addressControl/addressList?types="+types);
        ModelAndView model = new ModelAndView();

        Map<String, String> params = new HashMap<String, String>();

        if(!StringUtils.isEmpty(logadd.getName()))
            params.put("name", logadd.getName());
        if(null !=logadd.getArea())
            params.put("area", logadd.getArea()+"");


        page.setParams(params);

        List<LogisticAddress> findAddress = addressService.selectByExampleLimit(logadd,page);

        model.setViewName("/address/addressList");
        model.addObject("findAddress", findAddress);
        model.addObject("page", page);

        return model;
    

2、然后当然是到service 层了

@Service
public class AddressService 

    @Autowired
    LogisticAddressMapper addressMapper;



    public List<LogisticAddress> selectByExampleLimit(LogisticAddress logisticAddress,Page page)
        Map<String, Object> map = Maps.newHashMap(); 
        map.put("page", page);
        return addressMapper.selectByExampleLimit(logisticAddress,map);
    


3、然后,mybatis 的mapper 文件是这样写的

public interface LogisticAddressMapper 

    List<LogisticAddress> selectByExampleLimit(@Param("logisticAddress")LogisticAddress logisticAddress,@Param("page")Map<String, Object> map);

4、最后呢,当然是最重要的了,就是在mybatis 拦截器中处理分页信息,取出分页的数据,在 mybatis-config.xml 中增加以下信息

<?xml version="1.0" encoding="UTF-8" ?>      
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <plugins>  
       <plugin interceptor="com.vshop.sys.paging.PageInterceptor">    
       </plugin>  
    </plugins>

</configuration>  

5、当然到这里,最最重要的就是 PageInterceptor 拦截器的实现了

import java.sql.Connection;  
import java.sql.PreparedStatement;  
import java.sql.ResultSet;  
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;  
import org.apache.commons.jxpath.JXPathContext;  
import org.apache.commons.jxpath.JXPathNotFoundException;  
import org.apache.ibatis.executor.Executor;  
import org.apache.ibatis.executor.parameter.DefaultParameterHandler;  
import org.apache.ibatis.mapping.BoundSql;  
import org.apache.ibatis.mapping.MappedStatement;  
import org.apache.ibatis.mapping.MappedStatement.Builder;  
import org.apache.ibatis.mapping.ParameterMapping;  
import org.apache.ibatis.mapping.SqlSource;  
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.session.ResultHandler;  
import org.apache.ibatis.session.RowBounds;  

@Intercepts(@Signature(type=Executor.class,method="query",args= MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class ))  
public class PageInterceptor implements Interceptor  

  public Object intercept(Invocation invocation) throws Throwable   

    //当前环境 MappedStatement,BoundSql,及sql取得  
    MappedStatement mappedStatement=(MappedStatement)invocation.getArgs()[0];      
    Object parameter = invocation.getArgs()[1];   
    BoundSql boundSql = mappedStatement.getBoundSql(parameter);   
    String originalSql = boundSql.getSql().trim();  
    Object parameterObject = boundSql.getParameterObject();  

    //Page对象获取,“信使”到达拦截器!  
    Page page =null;
    if(null !=searchPageWithXpath(boundSql.getParameterObject(),".","page","*/page"))

          page = searchPageWithXpath(boundSql.getParameterObject(),".","page","*/page");  
    


    if(page!=null )  
      //Page对象存在的场合,开始分页处理  
      String countSql = getCountSql(originalSql);  
      Connection connection=mappedStatement.getConfiguration().getEnvironment().getDataSource().getConnection()  ;            
      PreparedStatement countStmt = connection.prepareStatement(countSql);    
      BoundSql countBS = copyFromBoundSql(mappedStatement, boundSql, countSql);  
      DefaultParameterHandler parameterHandler = new DefaultParameterHandler(mappedStatement, parameterObject, countBS);  
      parameterHandler.setParameters(countStmt);  
      ResultSet rs = countStmt.executeQuery();  
      int totpage=0;  
      if (rs.next())     
        totpage = rs.getInt(1);    
        
      rs.close();    
      countStmt.close();    
      connection.close();  

      //分页计算  
      page.setTotalRecord(totpage);  

      //对原始Sql追加limit  
      int offset = (page.getPageNo() - 1) * page.getPageSize();  

      BoundSql newBoundSql=null;
      StringBuffer sb = new StringBuffer();  
      sb.append(originalSql).append(" limit ").append(offset).append(",").append(page.getPageSize());  
      newBoundSql = copyFromBoundSql(mappedStatement, boundSql, sb.toString());  


      MappedStatement newMs = copyFromMappedStatement(mappedStatement,new BoundSqlSqlSource(newBoundSql));    
      invocation.getArgs()[0]= newMs;    
      
    return invocation.proceed();  

    

  /** 
   * 根据给定的xpath查询Page对象 
   */  
  private Page searchPageWithXpath(Object o,String... xpaths)   
    JXPathContext context = JXPathContext.newContext(o);  
    Object result;  
    for(String xpath : xpaths)  
      try   
        result = context.selectNodes(xpath);

       catch (JXPathNotFoundException e)   
        continue;  
        
      if ( result instanceof List && ((List) result).size()>0)  
          if(((List) result).get(0) instanceof Page )
              return (Page)(((List) result).get(0));  
          

        
      
    return null;  
    

  /** 
   * 复制MappedStatement对象 
   */  
  private MappedStatement copyFromMappedStatement(MappedStatement ms,SqlSource newSqlSource)   
    Builder builder = new Builder(ms.getConfiguration(),ms.getId(),newSqlSource,ms.getSqlCommandType());  

    builder.resource(ms.getResource());  
    builder.fetchSize(ms.getFetchSize());  
    builder.statementType(ms.getStatementType());  
    builder.keyGenerator(ms.getKeyGenerator());  
    if(null !=ms.getKeyProperties())
        if(ms.getKeyProperties().length>0)
            builder.keyProperty(ms.getKeyProperties()[0]);
        
    

    builder.timeout(ms.getTimeout());  
    builder.parameterMap(ms.getParameterMap());  
    builder.resultMaps(ms.getResultMaps());  
    builder.resultSetType(ms.getResultSetType());  
    builder.cache(ms.getCache());  
    builder.flushCacheRequired(ms.isFlushCacheRequired());  
    builder.useCache(ms.isUseCache());  

    return builder.build();  
    

  /** 
   * 复制BoundSql对象 
   */  
  private BoundSql copyFromBoundSql(MappedStatement ms, BoundSql boundSql, String sql)   
    BoundSql newBoundSql = new BoundSql(ms.getConfiguration(),sql, boundSql.getParameterMappings(), boundSql.getParameterObject());  
    for (ParameterMapping mapping : boundSql.getParameterMappings())   
        String prop = mapping.getProperty();  
        if (boundSql.hasAdditionalParameter(prop))   
            newBoundSql.setAdditionalParameter(prop, boundSql.getAdditionalParameter(prop));  
          
      
    return newBoundSql;  
    

  /** 
   * 根据原Sql语句获取对应的查询总记录数的Sql语句 
   */  
  private String getCountSql(String sql)   
    return "SELECT COUNT(*) FROM (" + sql + ") aliasForPage";  
    

  public class BoundSqlSqlSource implements SqlSource     
      BoundSql boundSql;    
      public BoundSqlSqlSource(BoundSql boundSql)     
        this.boundSql = boundSql;    
          
      public BoundSql getBoundSql(Object parameterObject)     
        return boundSql;    
          
        
  public Object plugin(Object arg0)   
     return Plugin.wrap(arg0, this);  
    
  public void setProperties(Properties arg0)   
    

6、最后当然是得用自定义标签显示在页面了

首先是在WEB-INFO 中建立tags 目录 ,然后在其中建立page.tag 文件

<%@ tag language="java" pageEncoding="UTF-8"%>
<%@ attribute name="page" type="com.vshop.sys.paging.Page" required="true"%>  
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>  

<%  
int current =  page.getPageNo();  
int begin = 1;  
int end = page.getTotalPage();  

request.setAttribute("current", current);  
request.setAttribute("begin", begin);  
request.setAttribute("end", end);  
request.setAttribute("pList", page.getPageNoDisp());  

%>  
<script type="text/javascript">  
  var paras = '<%=page.getParaJson()%>';  
  var paraJson = eval('(' + paras + ')');

  //将提交参数转换为JSON  
  var paraLists = '<%=page.getParaListJson()%>';  
  var paraListJson = eval('(' + paraLists + ')');  
  function pageClick( pNo )  
    paraJson["pageNo"] = pNo;  

    var choosePageSize = $("#choosePageSize").find("option:selected").text(); 

    paraJson["pageSize"] = choosePageSize;  

    var jsPost = function(action, values, valueLists)   
      var id = Math.random();  
      document.write('<form id="post' + id + '" name="post'+ id +'" action="$pageContext.request.contextPath' + action + '" method="post">');  
      for (var key in values)   
        document.write('<input type="hidden" name="' + key + '" value="' + values[key] + '" />');  
        
      for (var key2 in valueLists)   
        for (var index in valueLists[key2])   
          document.write('<input type="hidden" name="' + key2 + '" value="' + valueLists[key2][index] + '" />');  
          
        
      document.write('</form>');      
      document.getElementById('post' + id).submit();  
      

    //发送POST  
    jsPost("<%=page.getSearchUrl()%>", paraJson, paraListJson);  
    


  function ChoosePage()
      var choosePage =document.getElementById("ChoosePage").value;
      pageClick(choosePage);

  

     //以下这个函数由小弟编写,可以简化到 html 代码中去
      function choosePageSizeFunction()
          var s2 = document.getElementById("choosePageSize");
             for(var c=0;c<s2.options.length;c++)
             
                if(s2.options[c].value=='$page.pageSize') 
                    
                       s2.options[c].selected=true;
                    
             
      

     if (window.addEventListener) 
            window.addEventListener('DOMContentLoaded', choosePageSizeFunction, false); //firefox
            window.addEventListener('load', choosePageSizeFunction, false);
         else if (window.attachEvent) 
            window.attachEvent('onload', choosePageSizeFunction); //IE
         
     function chPageSize(obj)
         /* alert(obj.value); */
         pageClick(1);

     

</script>  
<div class="row-fluid">
        <div class="fyhpagediv" style="float: right;">      
            <% if (current!=1 && end!=0)%>  
                <span class="fyhfybk"><a href="javascript:void(0);" onclick="pageClick($current-1)">上一页</a>
            <%else%>  
                <span class="fyhfybk"><a href="javascript:void(0);">上一页</a>
            <% %>  
            <%
                for(int i=0 ; i < page.getTotalPage(); i++)
                    if(i + 1 == current)
            %>  
                       <a href="#" class="pagebtn-red" ><%=i+1%></a>

            <%      
                    else
                        if(i == 0 || i == 1 || i == 2 || i == 3 

                                || i == current - 2 || i == current - 3 
                                || i == current || i == current + 1 

                                || i == page.getTotalPage() - 2 || i == page.getTotalPage() - 1)
            %>  

                           <a href="#" onclick="pageClick(<%=i+1%>)"><%=i+1%></a>

            <%
                        else
                            if(i == 4 && current > 7)
            %>
                                <a href="#">...</a>
            <% 
                            
                            if(i == page.getTotalPage() - 3  && current < page.getTotalPage() - 4)
            %>
                                <a href="#">...</a>
            <% 
                            
                        
                    

                
            %>

            <% if (current<end && end!=0)%>  
                <a href="javascript:void(0);" onclick="pageClick($current+1)">下一页</a></span>
            <%else%>  
                <a href="javascript:void(0);">下一页</a></span>
            <% %>  
         </div>     

        <div class="fyhpagenum" style="float: right;">
                <span>每页</span>
                <select id="choosePageSize" class="fyhpageselect" onchange="chPageSize(this)"><option>10</option><option>25</option><option>50</option></select>
                <span></span>
                <span>共$page.totalRecord条</span>
        </div>
</div>

7、最后当然是在页面引用了

在相应的页面中引入此tag 标签

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib prefix="tags" tagdir="/WEB-INF/tags"%>

然后在要显示分页信息的地方,加入此行代码即可

<tags:page page="$page"/> 

到最后让你的应用跑起来就可以看到好看的分页了

以上是关于基于mybatis 自定义标签分页的实现的主要内容,如果未能解决你的问题,请参考以下文章

Mybatis源码分析自定义缓存分页的实现

帝国cms——首页怎么分页??

Mybatis是如何进行分页的?

mybatis pagehelper 怎么求出总页数

MyBatis:分页的实现

Mybatis -- MyBatis核心配置文件深入: typeHandlers标签(自定义类型转换器)plugins标签(插件标签:扩展mybatis功能 分页助手)