MyBatis分页插件

来源:互联网 发布:链接跳转手机淘宝 编辑:程序博客网 时间:2024/05/01 18:59

本方法是通过拦截mybatis底层的数据库操作达到分页目的

  1. //分页实体类   
Java代码  收藏代码
  1. public   class  Page {    
  2.     private   int  showCount =  10 ;  //每页显示记录数     
  3.     private   int  totalPage;       //总页数     
  4.     private   int  totalResult;     //总记录数     
  5.     private   int  currentPage;     //当前页     
  6.     private   int  currentResult;   //当前记录起始索引     
  7.     private   boolean  entityOrField;   //true:需要分页的地方,传入的参数就是Page实体;false:需要分页的地方,传入的参数所代表的实体拥有Page属性     
  8.     private  String pageStr;      //最终页面显示的底部翻页导航,详细见:getPageStr();     
  9.     public   int  getTotalPage() {    
  10.         if (totalResult%showCount== 0 )    
  11.             totalPage = totalResult/showCount;    
  12.         else     
  13.             totalPage = totalResult/showCount+1 ;    
  14.         return  totalPage;    
  15.     }    
  16.     public   void  setTotalPage( int  totalPage) {    
  17.         this .totalPage = totalPage;    
  18.     }    
  19.     public   int  getTotalResult() {    
  20.         return  totalResult;    
  21.     }    
  22.     public   void  setTotalResult( int  totalResult) {    
  23.         this .totalResult = totalResult;    
  24.     }    
  25.     public   int  getCurrentPage() {    
  26.         if (currentPage<= 0 )    
  27.             currentPage = 1 ;    
  28.         if (currentPage>getTotalPage())    
  29.             currentPage = getTotalPage();    
  30.         return  currentPage;    
  31.     }    
  32.     public   void  setCurrentPage( int  currentPage) {    
  33.         this .currentPage = currentPage;    
  34.     }    
  35.     public  String getPageStr() {    
  36.         StringBuffer sb = new  StringBuffer();    
  37.         if (totalResult> 0 ){    
  38.             sb.append(" <ul>\n" );    
  39.             if (currentPage== 1 ){    
  40.                 sb.append(" <li class=\"pageinfo\">首页</li>\n" );    
  41.                 sb.append(" <li class=\"pageinfo\">上页</li>\n" );    
  42.             }else {      
  43.                 sb.append(" <li><a href=\"#@\" onclick=\"nextPage(1)\">首页</a></li>\n" );    
  44.                 sb.append(" <li><a href=\"#@\" onclick=\"nextPage(" +(currentPage- 1 )+ ")\">上页</a></li>\n" );    
  45.             }    
  46.             int  showTag =  3 ;     //分页标签显示数量     
  47.             int  startTag =  1 ;    
  48.             if (currentPage>showTag){    
  49.                 startTag = currentPage-1 ;    
  50.             }    
  51.             int  endTag = startTag+showTag- 1 ;    
  52.             for ( int  i=startTag; i<=totalPage && i<=endTag; i++){    
  53.                 if (currentPage==i)    
  54.                     sb.append("<li class=\"current\">" +i+ "</li>\n" );    
  55.                 else     
  56.                     sb.append(" <li><a href=\"#@\" onclick=\"nextPage(" +i+ ")\">" +i+ "</a></li>\n" );    
  57.             }    
  58.             if (currentPage==totalPage){    
  59.                 sb.append(" <li class=\"pageinfo\">下页</li>\n" );    
  60.                 sb.append(" <li class=\"pageinfo\">尾页</li>\n" );    
  61.             }else {    
  62.                 sb.append(" <li><a href=\"#@\" onclick=\"nextPage(" +(currentPage+ 1 )+ ")\">下页</a></li>\n" );    
  63.                 sb.append(" <li><a href=\"#@\" onclick=\"nextPage(" +totalPage+ ")\">尾页</a></li>\n" );    
  64.             }    
  65.             sb.append(" <li class=\"pageinfo\">第" +currentPage+ "页</li>\n" );    
  66.             sb.append(" <li class=\"pageinfo\">共" +totalPage+ "页</li>\n" );    
  67.             sb.append("</ul>\n" );    
  68.             sb.append("<script type=\"text/javascript\">\n" );    
  69.             sb.append("function nextPage(page){" );    
  70.             sb.append(" if(true && document.forms[0]){\n" );    
  71.             sb.append("     var url = document.forms[0].getAttribute(\"action\");\n" );    
  72.             sb.append("     if(url.indexOf('?')>-1){url += \"&" +(entityOrField? "currentPage" : "page.currentPage" )+ "=\";}\n" );    
  73.             sb.append("     else{url += \"?" +(entityOrField? "currentPage" : "page.currentPage" )+ "=\";}\n" );    
  74.             sb.append("     document.forms[0].action = url+page;\n" );    
  75.             sb.append("     document.forms[0].submit();\n" );    
  76.             sb.append(" }else{\n" );    
  77.             sb.append("     var url = document.location+';\n" );    
  78.             sb.append("     if(url.indexOf('?')>-1){\n" );    
  79.             sb.append("         if(url.indexOf('currentPage')>-1){\n" );    
  80.             sb.append("             var reg = /currentPage=\\d*/g;\n" );    
  81.             sb.append("             url = url.replace(reg,'currentPage=');\n" );    
  82.             sb.append("         }else{\n" );    
  83.             sb.append("             url += \"&" +(entityOrField? "currentPage" : "page.currentPage" )+ "=\";\n" );    
  84.             sb.append("         }\n" );    
  85.             sb.append("     }else{url += \"?" +(entityOrField? "currentPage" : "page.currentPage" )+ "=\";}\n" );    
  86.             sb.append("     document.location = url + page;\n" );    
  87.             sb.append(" }\n" );    
  88.             sb.append("}\n" );    
  89.             sb.append("</script>\n" );    
  90.         }    
  91.         pageStr = sb.toString();    
  92.         return  pageStr;    
  93.     }    
  94.     public   void  setPageStr(String pageStr) {    
  95.         this .pageStr = pageStr;    
  96.     }    
  97.     public   int  getShowCount() {    
  98.         return  showCount;    
  99.     }    
  100.     public   void  setShowCount( int  showCount) {    
  101.         this .showCount = showCount;    
  102.     }    
  103.     public   int  getCurrentResult() {    
  104.         currentResult = (getCurrentPage()-1 )*getShowCount();    
  105.         if (currentResult< 0 )    
  106.             currentResult = 0 ;    
  107.         return  currentResult;    
  108.     }    
  109.     public   void  setCurrentResult( int  currentResult) {    
  110.         this .currentResult = currentResult;    
  111.     }    
  112.     public   boolean  isEntityOrField() {    
  113.         return  entityOrField;    
  114.     }    
  115.     public   void  setEntityOrField( boolean  entityOrField) {    
  116.         this .entityOrField = entityOrField;    
  117.     }    
  118. }  
    

通过拦截StatementHandler的prepare方法的分页插件类


Java代码  收藏代码
  1. @Intercepts ({ @Signature (type=StatementHandler. class ,method= "prepare" ,args={Connection. class })})    
  2. public   class  PagePlugin  implements  Interceptor {    
  3.     
  4.     private   static  String dialect =  "" ;  //数据库方言     
  5.     private   static  String pageSqlId =  "" ;  //mapper.xml中需要拦截的ID(正则匹配)     
  6.         
  7.     public  Object intercept(Invocation ivk)  throws  Throwable {    
  8.         // TODO Auto-generated method stub     
  9.         if (ivk.getTarget()  instanceof  RoutingStatementHandler){    
  10.             RoutingStatementHandler statementHandler = (RoutingStatementHandler)ivk.getTarget();    
  11.             BaseStatementHandler delegate = (BaseStatementHandler) ReflectHelper.getValueByFieldName(statementHandler, "delegate" );    
  12.             MappedStatement mappedStatement = (MappedStatement) ReflectHelper.getValueByFieldName(delegate, "mappedStatement" );    
  13.                 
  14.             if (mappedStatement.getId().matches(pageSqlId)){  //拦截需要分页的SQL     
  15.                 BoundSql boundSql = delegate.getBoundSql();    
  16.                 Object parameterObject = boundSql.getParameterObject();//分页SQL<select>中parameterType属性对应的实体参数,即Mapper接口中执行分页方法的参数,该参数不得为空     
  17.                 if (parameterObject== null ){    
  18.                     throw   new  NullPointerException( "parameterObject尚未实例化!" );    
  19.                 }else {    
  20.                     Connection connection = (Connection) ivk.getArgs()[0 ];    
  21.                     String sql = boundSql.getSql();    
  22.                     String countSql = "select count(0) from ("  + sql+  ") as tmp_count" ;  //记录统计     
  23.                     PreparedStatement countStmt = connection.prepareStatement(countSql);    
  24.                     //BoundSql countBS = new  BoundSql(mappedStatement.getConfiguration(),countSql,boundSql.getParameterMappings(),parameterObject);    
  25.                     setParameters(countStmt,mappedStatement,boundSql,parameterObject);    
  26.                     ResultSet rs = countStmt.executeQuery();    
  27.                     int  count =  0 ;    
  28.                     if  (rs.next()) {    
  29.                         count = rs.getInt(1 );    
  30.                     }    
  31.                     rs.close();    
  32.                     countStmt.close();    
  33.                     //System.out.println(count);     
  34.                     Page page = null ;    
  35.                     if (parameterObject  instanceof  Page){     //参数就是Page实体     
  36.                          page = (Page) parameterObject;    
  37.                          page.setEntityOrField(true );     //见com.flf.entity.Page.entityOrField 注释     
  38.                         page.setTotalResult(count);    
  39.                     }else {   //参数为某个实体,该实体拥有Page属性     
  40.                         Field pageField = ReflectHelper.getFieldByFieldName(parameterObject,"page" );    
  41.                         if (pageField!= null ){    
  42.                             page = (Page) ReflectHelper.getValueByFieldName(parameterObject,"page" );    
  43.                             if (page== null )    
  44.                                 page = new  Page();    
  45.                             page.setEntityOrField(false );  //见com.flf.entity.Page.entityOrField 注释     
  46.                             page.setTotalResult(count);    
  47.                             ReflectHelper.setValueByFieldName(parameterObject,"page" , page);  //通过反射,对实体对象设置分页对象     
  48.                         }else {    
  49.                             throw   new  NoSuchFieldException(parameterObject.getClass().getName()+ "不存在 page 属性!" );    
  50.                         }    
  51.                     }    
  52.                     String pageSql = generatePageSql(sql,page);    
  53.                     ReflectHelper.setValueByFieldName(boundSql, "sql" , pageSql);  //将分页sql语句反射回BoundSql.     
  54.                 }    
  55.             }    
  56.         }    
  57.         return  ivk.proceed();    
  58.     }    
  59.     
  60.         
  61.     /**   
  62.      * 对SQL参数(?)设值,参考org.apache.ibatis.executor.parameter.DefaultParameterHandler   
  63.      * @param ps   
  64.      * @param mappedStatement   
  65.      * @param boundSql   
  66.      * @param parameterObject   
  67.      * @throws SQLException   
  68.      */     
  69.     private   void  setParameters(PreparedStatement ps,MappedStatement mappedStatement,BoundSql boundSql,Object parameterObject)  throws  SQLException {    
  70.         ErrorContext.instance().activity("setting parameters" ).object(mappedStatement.getParameterMap().getId());    
  71.         List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();    
  72.         if  (parameterMappings !=  null ) {    
  73.             Configuration configuration = mappedStatement.getConfiguration();    
  74.             TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();    
  75.             MetaObject metaObject = parameterObject == null  ?  null : configuration.newMetaObject(parameterObject);    
  76.             for  ( int  i =  0 ; i < parameterMappings.size(); i++) {    
  77.                 ParameterMapping parameterMapping = parameterMappings.get(i);    
  78.                 if  (parameterMapping.getMode() != ParameterMode.OUT) {    
  79.                     Object value;    
  80.                     String propertyName = parameterMapping.getProperty();    
  81.                     PropertyTokenizer prop = new  PropertyTokenizer(propertyName);    
  82.                     if  (parameterObject ==  null ) {    
  83.                         value = null ;    
  84.                     } else   if  (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {    
  85.                         value = parameterObject;    
  86.                     } else   if  (boundSql.hasAdditionalParameter(propertyName)) {    
  87.                         value = boundSql.getAdditionalParameter(propertyName);    
  88.                     } else   if  (propertyName.startsWith(ForEachSqlNode.ITEM_PREFIX)&& boundSql.hasAdditionalParameter(prop.getName())) {    
  89.                         value = boundSql.getAdditionalParameter(prop.getName());    
  90.                         if  (value !=  null ) {    
  91.                             value = configuration.newMetaObject(value).getValue(propertyName.substring(prop.getName().length()));    
  92.                         }    
  93.                     } else  {    
  94.                         value = metaObject == null  ?  null  : metaObject.getValue(propertyName);    
  95.                     }    
  96.                     TypeHandler typeHandler = parameterMapping.getTypeHandler();    
  97.                     if  (typeHandler ==  null ) {    
  98.                         throw   new  ExecutorException( "There was no TypeHandler found for parameter " + propertyName +  " of statement " + mappedStatement.getId());    
  99.                     }    
  100.                     typeHandler.setParameter(ps, i + 1 , value, parameterMapping.getJdbcType());    
  101.                 }    
  102.             }    
  103.         }    
  104.     }    
  105.         
  106.     /**   
  107.      * 根据数据库方言,生成特定的分页sql   
  108.      * @param sql   
  109.      * @param page   
  110.      * @return   
  111.      */     
  112.     private  String generatePageSql(String sql,Page page){    
  113.         if (page!= null  && Tools.notEmpty(dialect)){    
  114.             StringBuffer pageSql = new  StringBuffer();    
  115.             if ( "mysql" .equals(dialect)){    
  116.                 pageSql.append(sql);    
  117.                 pageSql.append(" limit " +page.getCurrentResult()+ "," +page.getShowCount());    
  118.             }else   if ( "oracle" .equals(dialect)){    
  119.                 pageSql.append("select * from (select tmp_tb.*,ROWNUM row_id from (" );    
  120.                 pageSql.append(sql);    
  121.                 pageSql.append(") as tmp_tb where ROWNUM<=" );    
  122.                 pageSql.append(page.getCurrentResult()+page.getShowCount());    
  123.                 pageSql.append(") where row_id>" );    
  124.                 pageSql.append(page.getCurrentResult());    
  125.             }    
  126.             return  pageSql.toString();    
  127.         }else {    
  128.             return  sql;    
  129.         }    
  130.     }    
  131.         
  132.     public  Object plugin(Object arg0) {    
  133.         // TODO Auto-generated method stub     
  134.         return  Plugin.wrap(arg0,  this );    
  135.     }    
  136.     
  137.     public   void  setProperties(Properties p) {    
  138.         dialect = p.getProperty("dialect" );    
  139.         if  (Tools.isEmpty(dialect)) {    
  140.             try  {    
  141.                 throw   new  PropertyException( "dialect property is not found!" );    
  142.             } catch  (PropertyException e) {    
  143.                 // TODO Auto-generated catch block     
  144.                 e.printStackTrace();    
  145.             }    
  146.         }    
  147.         pageSqlId = p.getProperty("pageSqlId" );    
  148.         if  (Tools.isEmpty(pageSqlId)) {    
  149.             try  {    
  150.                 throw   new  PropertyException( "pageSqlId property is not found!" );    
  151.             } catch  (PropertyException e) {    
  152.                 // TODO Auto-generated catch block     
  153.                 e.printStackTrace();    
  154.             }    
  155.         }    
  156.     }    
  157.         
  158.   
  159. }    
 


该类中定义了两个私有静态变量:dialect、pageSqlId,这两个变量是在该类初始化时,即调用setProperties方法时初始化的,相关的值是在MyBatis配置文件中配置的,如下:


Xml代码  收藏代码
  1. < plugins >     
  2.     < plugin   interceptor = "com.flf.plugin.PagePlugin" >     
  3.         < property   name = "dialect"   value = "mysql" />     
  4.         < property   name = "pageSqlId"   value = ".*listPage.*" />     
  5.     </ plugin >     
  6.   
  7. </ plugins >     
 


上面的示例表明数据库方言为mysql,拦截所有mapper.xml映射文件中id包含有listPage的SQL。

反射帮助类:

Java代码  收藏代码
  1. /**   
  2.  * @author Administrator   
  3.  *  反射工具   
  4.  */     
  5. public   class  ReflectHelper {    
  6.     /**   
  7.      * 获取obj对象fieldName的Field   
  8.      * @param obj   
  9.      * @param fieldName   
  10.      * @return   
  11.      */     
  12.     public   static  Field getFieldByFieldName(Object obj, String fieldName) {    
  13.         for  (Class<?> superClass = obj.getClass(); superClass != Object. class ; superClass = superClass    
  14.                 .getSuperclass()) {    
  15.             try  {    
  16.                 return  superClass.getDeclaredField(fieldName);    
  17.             } catch  (NoSuchFieldException e) {    
  18.             }    
  19.         }    
  20.         return   null ;    
  21.     }    
  22.     
  23.     /**   
  24.      * 获取obj对象fieldName的属性值   
  25.      * @param obj   
  26.      * @param fieldName   
  27.      * @return   
  28.      * @throws SecurityException   
  29.      * @throws NoSuchFieldException   
  30.      * @throws IllegalArgumentException   
  31.      * @throws IllegalAccessException   
  32.      */     
  33.     public   static  Object getValueByFieldName(Object obj, String fieldName)    
  34.             throws  SecurityException, NoSuchFieldException,    
  35.             IllegalArgumentException, IllegalAccessException {    
  36.         Field field = getFieldByFieldName(obj, fieldName);    
  37.         Object value = null ;    
  38.         if (field!= null ){    
  39.             if  (field.isAccessible()) {    
  40.                 value = field.get(obj);    
  41.             } else  {    
  42.                 field.setAccessible(true );    
  43.                 value = field.get(obj);    
  44.                 field.setAccessible(false );    
  45.             }    
  46.         }    
  47.         return  value;    
  48.     }    
  49.     
  50.     /**   
  51.      * 设置obj对象fieldName的属性值   
  52.      * @param obj   
  53.      * @param fieldName   
  54.      * @param value   
  55.      * @throws SecurityException   
  56.      * @throws NoSuchFieldException   
  57.      * @throws IllegalArgumentException   
  58.      * @throws IllegalAccessException   
  59.      */     
  60.     public   static   void  setValueByFieldName(Object obj, String fieldName,    
  61.             Object value) throws  SecurityException, NoSuchFieldException,    
  62.             IllegalArgumentException, IllegalAccessException {    
  63.         Field field = obj.getClass().getDeclaredField(fieldName);    
  64.         if  (field.isAccessible()) {    
  65.             field.set(obj, value);    
  66.         } else  {    
  67.             field.setAccessible(true );    
  68.             field.set(obj, value);    
  69.             field.setAccessible(false );    
  70.         }    
  71.     }    
  72.   
  73. }    
 


PS:分页插件类PagePlugin只实现了mysql和oracle的分页,至于其他的数据库,可以修改该类的generatePageSql方法。

0 0
原创粉丝点击