spring+mybatis 物理分页

新项目用的spring mvc 和 mybatis 分页。研究了一下,集众家之长然后形成现在的项目。我把分页部分剥离出来与大家分享。如有不妥的地方欢迎交流拍砖。

单独做了一个小项目,放到了下载区,如果有用到的朋友可以去下载。

本项目采用了拦截器,就是mybaits自带的plus功能。将每次select操作都进行拦截。

项目架构如下:

spring+mybatis 物理分页_第1张图片


1:首先从cotroller层出发,啥也不说,上代码。这个最实惠

[java] view plain copy print ?
  1. package com.flydreamer.controller;  
  2.   
  3. import java.util.HashMap;  
  4. import java.util.Map;  
  5.   
  6. import javax.servlet.http.HttpServletRequest;  
  7. import javax.servlet.http.HttpServletResponse;  
  8.   
  9. import org.springframework.beans.factory.annotation.Autowired;  
  10. import org.springframework.stereotype.Controller;  
  11. import org.springframework.web.bind.annotation.RequestMapping;  
  12. import org.springframework.web.servlet.ModelAndView;  
  13.   
  14. import com.flydreamer.logic.UserService;  
  15. import com.flydreamer.page.Page;  
  16. import com.flydreamer.page.PageContext;  
  17. import com.flydreamer.util.web.HandlerResult;  
  18.   
  19. @Controller  
  20. @RequestMapping("/user.do")  
  21. public class UserController {  
  22.       
  23.     @Autowired  
  24.     private UserService userService;  
  25.       
  26.     @RequestMapping(params = ("method=list"))  
  27.     public ModelAndView listAll(HttpServletRequest request,HttpServletResponse response) {  
  28.           
  29.         //可以将分页参数获取封装,已达到更好的复用效果。  
  30.         //page=2&pageSize=10&totalPages=19&totalRows=188  
  31.         String pagec = request.getParameter("page");   
  32.         String pageSize = request.getParameter("pageSize");   
  33.         String totalPages = request.getParameter("totalPages");   
  34.         String totalRows = request.getParameter("totalRows");   
  35.           
  36.         //方法1:将分页参数直接放到mapper接口函数参数中,也可在对象中定义名字为page的属性,反射一样可以得到  
  37.         //后台连接直接获取   
  38.         //Page page = new Page();   
  39.           
  40.         //方法2:不用进行map传参,用ThreadLocal进行传参,方便没有侵入性  
  41.         PageContext page = PageContext.getContext();  
  42.           
  43.         //请自行验证   
  44.         if(null == pagec)  
  45.         {  
  46.             page.setCurrentPage(1);  
  47.             page.setPageSize(10);  
  48.         }  
  49.         else{  
  50.             page.setCurrentPage(Integer.parseInt(pagec));  
  51.             page.setPageSize(Integer.parseInt(pageSize));  
  52.             page.setTotalPages(Integer.parseInt(totalPages));  
  53.             page.setTotalRows(Integer.parseInt(totalRows));  
  54.         }  
  55.         page.setPagination(true);  
  56.   
  57. //      方法1用   
  58. //      Map map = new HashMap();   
  59. //      map.put("page", page);  
  60. //      HandlerResult rs = userService.list(map);  
  61.           
  62.         //方法2用   
  63.         HandlerResult rs = userService.list();  
  64.           
  65.         ModelAndView mv = new ModelAndView("/views/show.jsp");  
  66.         mv.addObject("userList", rs.getResultObj());  
  67.         mv.addObject("page",page);  
  68.         return mv;  
  69.     }  
  70.   
  71. }  
简要说明:本文采用两种方式将page对象传入到拦截器中。第一种方式是采用参数传值,不管是用map还是在统一参数对象中名称为page的属性都可以在分页拦截器中得到page的值。第二种方式是用ThreadLocal,对service层没有侵入性。比较方便。


2:Service层代码。没啥可说的上代码

[java] view plain copy print ?
  1. package com.flydreamer.logic;  
  2.   
  3. import java.util.Map;  
  4.   
  5. import org.springframework.beans.factory.annotation.Autowired;  
  6. import org.springframework.stereotype.Service;  
  7.   
  8. import com.flydreamer.orm.mapper.UsersMapper;  
  9. import com.flydreamer.util.web.HandlerResult;  
  10.   
  11. @Service  
  12. public class UserService {  
  13.       
  14.     @Autowired  
  15.     private UsersMapper usersMappser;  
  16.   
  17.   
  18.     /** 
  19.      * 统一Service出口,方便管理 
  20.      * @param map 
  21.      * @return 
  22.      */  
  23.     public HandlerResult list(Map map){  
  24.           
  25.         HandlerResult rs = new HandlerResult();  
  26.           
  27.         rs.setResultObj(usersMappser.list(map));  
  28.           
  29.         return rs;  
  30.     }  
  31.       
  32.     /** 
  33.      * 采用本地线程的方式分页 
  34.      * @return 
  35.      */  
  36.     public HandlerResult list(){  
  37.           
  38.         HandlerResult rs = new HandlerResult();  
  39.           
  40.         rs.setResultObj(usersMappser.list2());  
  41.           
  42.         return rs;  
  43.     }  
  44.       
  45.   
  46.     public UsersMapper getUsersMappser() {  
  47.         return usersMappser;  
  48.     }  
  49.   
  50.     public void setUsersMappser(UsersMapper usersMappser) {  
  51.         this.usersMappser = usersMappser;  
  52.     }  
  53. }  

3:mybatis接口

[java] view plain copy print ?
  1. package com.flydreamer.orm.mapper;  
  2.   
  3. import java.util.List;  
  4. import java.util.Map;  
  5.   
  6. import com.flydreamer.orm.SqlMapper;  
  7.   
  8. public interface UsersMapper extends SqlMapper{  
  9.       
  10.     public List list(Map para);  
  11.       
  12.     public List list2();  
  13. }  

4:page的拦截器

[java] view plain copy print ?
  1. package com.flydreamer.interceptor;  
  2.   
  3. import java.sql.Connection;  
  4. import java.sql.PreparedStatement;  
  5. import java.sql.ResultSet;  
  6. import java.sql.SQLException;  
  7. import java.util.List;  
  8. import java.util.Properties;  
  9.   
  10. import org.apache.ibatis.builder.xml.dynamic.ForEachSqlNode;  
  11. import org.apache.ibatis.executor.ErrorContext;  
  12. import org.apache.ibatis.executor.Executor;  
  13. import org.apache.ibatis.executor.ExecutorException;  
  14. import org.apache.ibatis.logging.Log;  
  15. import org.apache.ibatis.logging.LogFactory;  
  16. import org.apache.ibatis.mapping.BoundSql;  
  17. import org.apache.ibatis.mapping.MappedStatement;  
  18. import org.apache.ibatis.mapping.ParameterMapping;  
  19. import org.apache.ibatis.mapping.ParameterMode;  
  20. import org.apache.ibatis.mapping.SqlSource;  
  21. import org.apache.ibatis.mapping.MappedStatement.Builder;  
  22. import org.apache.ibatis.plugin.Interceptor;  
  23. import org.apache.ibatis.plugin.Intercepts;  
  24. import org.apache.ibatis.plugin.Invocation;  
  25. import org.apache.ibatis.plugin.Plugin;  
  26. import org.apache.ibatis.plugin.Signature;  
  27. import org.apache.ibatis.reflection.MetaObject;  
  28. import org.apache.ibatis.reflection.property.PropertyTokenizer;  
  29. import org.apache.ibatis.session.Configuration;  
  30. import org.apache.ibatis.session.ResultHandler;  
  31. import org.apache.ibatis.session.RowBounds;  
  32. import org.apache.ibatis.type.TypeHandler;  
  33. import org.apache.ibatis.type.TypeHandlerRegistry;  
  34.   
  35. import com.flydreamer.page.Dialect;  
  36. import com.flydreamer.page.MySql5Dialect;  
  37. import com.flydreamer.page.OracleDialect;  
  38. import com.flydreamer.page.Page;  
  39. import com.flydreamer.page.PageContext;  
  40. import com.flydreamer.page.ReflectHelper;  
  41.   
  42. //只拦截select部分   
  43. @Intercepts({@Signature(type=Executor.class,method="query",args={ MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class })})  
  44. public class PaginationInterceptor implements Interceptor{  
  45.       
  46.     private final static Log log = LogFactory.getLog(PaginationInterceptor.class);     
  47.       
  48.     Dialect dialect = new MySql5Dialect();  
  49.        
  50.     public Object intercept(Invocation invocation) throws Throwable {  
  51.           
  52.         MappedStatement mappedStatement=(MappedStatement)invocation.getArgs()[0];         
  53.         Object parameter = invocation.getArgs()[1];   
  54.         BoundSql boundSql = mappedStatement.getBoundSql(parameter);   
  55.         String originalSql = boundSql.getSql().trim();     
  56.         RowBounds rowBounds = (RowBounds)invocation.getArgs()[2];  
  57.   
  58.         Object parameterObject = boundSql.getParameterObject();  
  59.         if(boundSql==null || boundSql.getSql()==null || "".equals(boundSql.getSql()))  
  60.             return null;  
  61.         //分页参数--上下文传参   
  62.         Page page = null;  
  63.         PageContext context=PageContext.getContext();  
  64.           
  65.         //map传参每次都将currentPage重置,先判读map再判断context  
  66.         if(parameterObject!=null)  
  67.             page = (Page)ReflectHelper.isPage(parameterObject,"page");  
  68.           
  69.         //分页参数--context参数里的Page传参  
  70.         if(page==null && context.isPagination()==true)  
  71.         {  
  72.             page = context;  
  73.         }  
  74.           
  75.         //后面用到了context的东东   
  76.         if(page!=null && page.isPagination()==true)               
  77.         {  
  78.           int totpage=page.getTotalRows();    
  79.           //得到总记录数   
  80.           if (totpage==0)  
  81.             {  
  82.                 StringBuffer countSql  = new StringBuffer(originalSql.length()+100 );  
  83.                 countSql.append("select count(1) from (").append(originalSql).append(") t");  
  84.                      Connection connection=mappedStatement.getConfiguration().getEnvironment().getDataSource().getConnection()  ;            
  85.                  PreparedStatement countStmt = connection.prepareStatement(countSql.toString());    
  86.                  BoundSql countBS = new BoundSql(mappedStatement.getConfiguration(),countSql.toString(),boundSql.getParameterMappings(),parameterObject);    
  87.                  setParameters(countStmt,mappedStatement,countBS,parameterObject);    
  88.                  ResultSet rs = countStmt.executeQuery();    
  89.                  if (rs.next()) {    
  90.                      totpage = rs.getInt(1);    
  91.                  }    
  92.                  rs.close();    
  93.                  countStmt.close();    
  94.                  connection.close();  
  95.             }  
  96.             
  97.             //分页计算   
  98.             page.init(totpage,page.getPageSize(),page.getCurrentPage());  
  99.             
  100.             if(rowBounds == null || rowBounds == RowBounds.DEFAULT){  
  101.                 rowBounds= new RowBounds(page.getPageSize()*(page.getCurrentPage()-1),page.getPageSize());  
  102.                   
  103.             }     
  104.   
  105.             //分页查询 本地化对象 修改数据库注意修改实现  
  106.             String pagesql=dialect.getLimitString(originalSql, rowBounds.getOffset(), rowBounds.getLimit());  
  107.             invocation.getArgs()[2] = new RowBounds(RowBounds.NO_ROW_OFFSET, RowBounds.NO_ROW_LIMIT);     
  108.             BoundSql newBoundSql = new BoundSql(mappedStatement.getConfiguration(), pagesql,boundSql.getParameterMappings(),boundSql.getParameterObject());     
  109.             MappedStatement newMs = copyFromMappedStatement(mappedStatement,new BoundSqlSqlSource(newBoundSql));    
  110.              
  111.             invocation.getArgs()[0]= newMs;    
  112.         }  
  113.               
  114.               
  115.            return invocation.proceed();  
  116.           
  117.     }  
  118.     public static class BoundSqlSqlSource implements SqlSource {    
  119.         BoundSql boundSql;    
  120.     
  121.         public BoundSqlSqlSource(BoundSql boundSql) {    
  122.             this.boundSql = boundSql;    
  123.         }    
  124.     
  125.         public BoundSql getBoundSql(Object parameterObject) {    
  126.             return boundSql;    
  127.         }    
  128.     }    
  129.     public Object plugin(Object arg0) {  
  130.          return Plugin.wrap(arg0, this);  
  131.     }  
  132.     public void setProperties(Properties arg0) {  
  133.               
  134.     }  
  135.       
  136.     /**  
  137.      * 对SQL参数(?)设值,参考org.apache.ibatis.executor.parameter.DefaultParameterHandler  
  138.      * @param ps  
  139.      * @param mappedStatement  
  140.      * @param boundSql  
  141.      * @param parameterObject  
  142.      * @throws SQLException  
  143.      */    
  144.     private void setParameters(PreparedStatement ps,MappedStatement mappedStatement,BoundSql boundSql,Object parameterObject) throws SQLException {    
  145.         ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());    
  146.         List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();    
  147.         if (parameterMappings != null) {    
  148.             Configuration configuration = mappedStatement.getConfiguration();    
  149.             TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();    
  150.             MetaObject metaObject = parameterObject == null ? null: configuration.newMetaObject(parameterObject);    
  151.             for (int i = 0; i < parameterMappings.size(); i++) {    
  152.                 ParameterMapping parameterMapping = parameterMappings.get(i);    
  153.                 if (parameterMapping.getMode() != ParameterMode.OUT) {    
  154.                     Object value;    
  155.                     String propertyName = parameterMapping.getProperty();    
  156.                     PropertyTokenizer prop = new PropertyTokenizer(propertyName);    
  157.                     if (parameterObject == null) {    
  158.                         value = null;    
  159.                     } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {    
  160.                         value = parameterObject;    
  161.                     } else if (boundSql.hasAdditionalParameter(propertyName)) {    
  162.                         value = boundSql.getAdditionalParameter(propertyName);    
  163.                     } else if (propertyName.startsWith(ForEachSqlNode.ITEM_PREFIX)&& boundSql.hasAdditionalParameter(prop.getName())) {    
  164.                         value = boundSql.getAdditionalParameter(prop.getName());    
  165.                         if (value != null) {    
  166.                             value = configuration.newMetaObject(value).getValue(propertyName.substring(prop.getName().length()));    
  167.                         }    
  168.                     } else {    
  169.                         value = metaObject == null ? null : metaObject.getValue(propertyName);    
  170.                     }    
  171.                     TypeHandler typeHandler = parameterMapping.getTypeHandler();    
  172.                     if (typeHandler == null) {    
  173.                         throw new ExecutorException("There was no TypeHandler found for parameter "+ propertyName + " of statement "+ mappedStatement.getId());    
  174.                     }    
  175.                     typeHandler.setParameter(ps, i + 1, value, parameterMapping.getJdbcType());    
  176.                 }    
  177.             }    
  178.         }    
  179.     }    
  180.       
  181.     private MappedStatement copyFromMappedStatement(MappedStatement ms,     
  182.              SqlSource newSqlSource) {     
  183.             Builder builder = new MappedStatement.Builder(ms.getConfiguration(),     
  184.             ms.getId(), newSqlSource, ms.getSqlCommandType());     
  185.             builder.resource(ms.getResource());     
  186.             builder.fetchSize(ms.getFetchSize());     
  187.             builder.statementType(ms.getStatementType());     
  188.             builder.keyGenerator(ms.getKeyGenerator());     
  189.             builder.keyProperty(ms.getKeyProperty());     
  190.             builder.timeout(ms.getTimeout());     
  191.              builder.parameterMap(ms.getParameterMap());     
  192.             builder.resultMaps(ms.getResultMaps());     
  193.             builder.cache(ms.getCache());     
  194.             MappedStatement newMs = builder.build();     
  195.             return newMs;     
  196.             }     
  197.            
  198.   
  199. }  
简要说明:刚刚忘记了,有一些查询操作是不需要分页的。可以自行修改拦截器中代码部分,加个判断啥的。

5:spring 配置

[html] view plain copy print ?
  1. <bean id="paginationInterceptor" class="com.flydreamer.interceptor.PaginationInterceptor"></bean>    

[html] view plain copy print ?
  1. <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">    
  2.         <property name="dataSource" ref="dataSource" />    
  3.           
  4.         <property name="plugins">  
  5.             <ref bean="paginationInterceptor"/>  
  6.         </property>  
  7.     </bean>    

大致就是这样了。完整的可运行项目已放到这里。最近CSDN没有分了,收1分,各位童鞋见谅了~

你可能感兴趣的:(java,数据库,mybatis)