1. 程式人生 > >Springmvc+mybatis+maven查詢分頁完美封裝版

Springmvc+mybatis+maven查詢分頁完美封裝版

新專案用的spring mvc 和 mybatis 分頁。研究了一下,集眾家之長然後形成現在的專案。我把分頁部分剝離出來與大家分享。如有不妥的地方歡迎交流拍磚。

單獨做了一個小專案,放到了下載區,如果有用到的朋友可以去下載。

本專案採用了攔截器,就是mybaits自帶的plus功能。將每次select操作都進行攔截。

專案架構如下:

1:首先從cotroller層出發,啥也不說,上程式碼。這個最實惠

[java] view plaincopy

  1. package com.flydreamer.controller;  
  2. import java.util.HashMap;  
  3. import java.util.Map;  
  4. import javax.servlet.http.HttpServletRequest;  
  5. import javax.servlet.http.HttpServletResponse;  
  6. import org.springframework.beans.factory.annotation.Autowired;  
  7. import org.springframework.stereotype.Controller;  
  8. import org.springframework.web.bind.annotation.RequestMapping;  
  9. import org.springframework.web.servlet.ModelAndView;  
  10. import com.flydreamer.logic.UserService;  
  11. import com.flydreamer.page.Page;  
  12. import com.flydreamer.page.PageContext;  
  13. import com.flydreamer.util.web.HandlerResult;  
  14. @Controller
  15. @RequestMapping("/user.do")  
  16. publicclass UserController {  
  17. @Autowired
  18. private UserService userService;  
  19. @RequestMapping(params = (
    "method=list"))  
  20. public ModelAndView listAll(HttpServletRequest request,HttpServletResponse response) {  
  21. //可以將分頁引數獲取封裝,已達到更好的複用效果。
  22. //page=2&pageSize=10&totalPages=19&totalRows=188
  23.         String pagec = request.getParameter("page");   
  24.         String pageSize = request.getParameter("pageSize");   
  25.         String totalPages = request.getParameter("totalPages");   
  26.         String totalRows = request.getParameter("totalRows");   
  27. //方法1:將分頁引數直接放到mapper介面函式引數中,也可在物件中定義名字為page的屬性,反射一樣可以得到
  28. //後臺連線直接獲取
  29. //Page page = new Page();
  30. //方法2:不用進行map傳參,用ThreadLocal進行傳參,方便沒有侵入性
  31.         PageContext page = PageContext.getContext();  
  32. //請自行驗證
  33. if(null == pagec)  
  34.         {  
  35.             page.setCurrentPage(1);  
  36.             page.setPageSize(10);  
  37.         }  
  38. else{  
  39.             page.setCurrentPage(Integer.parseInt(pagec));  
  40.             page.setPageSize(Integer.parseInt(pageSize));  
  41.             page.setTotalPages(Integer.parseInt(totalPages));  
  42.             page.setTotalRows(Integer.parseInt(totalRows));  
  43.         }  
  44.         page.setPagination(true);  
  45. //      方法1用
  46. //      Map map = new HashMap();
  47. //      map.put("page", page);
  48. //      HandlerResult rs = userService.list(map);
  49. //方法2用
  50.         HandlerResult rs = userService.list();  
  51.         ModelAndView mv = new ModelAndView("/views/show.jsp");  
  52.         mv.addObject("userList", rs.getResultObj());  
  53.         mv.addObject("page",page);  
  54. return mv;  
  55.     }  
  56. }  

簡要說明:本文采用兩種方式將page物件傳入到攔截器中。第一種方式是採用引數傳值,不管是用map還是在統一引數物件中名稱為page的屬性都可以在分頁攔截器中得到page的值。第二種方式是用ThreadLocal,對service層沒有侵入性。比較方便。

2:Service層程式碼。沒啥可說的上程式碼

[java] view plaincopy

  1. package com.flydreamer.logic;  
  2. import java.util.Map;  
  3. import org.springframework.beans.factory.annotation.Autowired;  
  4. import org.springframework.stereotype.Service;  
  5. import com.flydreamer.orm.mapper.UsersMapper;  
  6. import com.flydreamer.util.web.HandlerResult;  
  7. @Service
  8. publicclass UserService {  
  9. @Autowired
  10. private UsersMapper usersMappser;  
  11. /**
  12.      * 統一Service出口,方便管理
  13.      * @param map
  14.      * @return
  15.      */
  16. public HandlerResult list(Map map){  
  17.         HandlerResult rs = new HandlerResult();  
  18.         rs.setResultObj(usersMappser.list(map));  
  19. return rs;  
  20.     }  
  21. /**
  22.      * 採用本地執行緒的方式分頁
  23.      * @return
  24.      */
  25. public HandlerResult list(){  
  26.         HandlerResult rs = new HandlerResult();  
  27.         rs.setResultObj(usersMappser.list2());  
  28. return rs;  
  29.     }  
  30. public UsersMapper getUsersMappser() {  
  31. return usersMappser;  
  32.     }  
  33. publicvoid setUsersMappser(UsersMapper usersMappser) {  
  34. this.usersMappser = usersMappser;  
  35.     }  
  36. }  

3:mybatis介面

[java] view plaincopy

  1. package com.flydreamer.orm.mapper;  
  2. import java.util.List;  
  3. import java.util.Map;  
  4. import com.flydreamer.orm.SqlMapper;  
  5. publicinterface UsersMapper extends SqlMapper{  
  6. public List list(Map para);  
  7. public List list2();  
  8. }  

4:page的攔截器

[java] view plaincopy

  1. package com.flydreamer.interceptor;  
  2. import java.sql.Connection;  
  3. import java.sql.PreparedStatement;  
  4. import java.sql.ResultSet;  
  5. import java.sql.SQLException;  
  6. import java.util.List;  
  7. import java.util.Properties;  
  8. import org.apache.ibatis.builder.xml.dynamic.ForEachSqlNode;  
  9. import org.apache.ibatis.executor.ErrorContext;  
  10. import org.apache.ibatis.executor.Executor;  
  11. import org.apache.ibatis.executor.ExecutorException;  
  12. import org.apache.ibatis.logging.Log;  
  13. import org.apache.ibatis.logging.LogFactory;  
  14. import org.apache.ibatis.mapping.BoundSql;  
  15. import org.apache.ibatis.mapping.MappedStatement;  
  16. import org.apache.ibatis.mapping.ParameterMapping;  
  17. import org.apache.ibatis.mapping.ParameterMode;  
  18. import org.apache.ibatis.mapping.SqlSource;  
  19. import org.apache.ibatis.mapping.MappedStatement.Builder;  
  20. import org.apache.ibatis.plugin.Interceptor;  
  21. import org.apache.ibatis.plugin.Intercepts;  
  22. import org.apache.ibatis.plugin.Invocation;  
  23. import org.apache.ibatis.plugin.Plugin;  
  24. import org.apache.ibatis.plugin.Signature;  
  25. import org.apache.ibatis.reflection.MetaObject;  
  26. import org.apache.ibatis.reflection.property.PropertyTokenizer;  
  27. import org.apache.ibatis.session.Configuration;  
  28. import org.apache.ibatis.session.ResultHandler;  
  29. import org.apache.ibatis.session.RowBounds;  
  30. import org.apache.ibatis.type.TypeHandler;  
  31. import org.apache.ibatis.type.TypeHandlerRegistry;  
  32. import com.flydreamer.page.Dialect;  
  33. import com.flydreamer.page.MySql5Dialect;  
  34. import com.flydreamer.page.OracleDialect;  
  35. import com.flydreamer.page.Page;  
  36. import com.flydreamer.page.PageContext;  
  37. import com.flydreamer.page.ReflectHelper;  
  38. //只攔截select部分
  39. @Intercepts({@Signature(type=Executor.class,method="query",args={ MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class })})  
  40. publicclass PaginationInterceptor implements Interceptor{  
  41. privatefinalstatic Log log = LogFactory.getLog(PaginationInterceptor.class);     
  42.     Dialect dialect = new MySql5Dialect();  
  43. public Object intercept(Invocation invocation) throws Throwable {  
  44.         MappedStatement mappedStatement=(MappedStatement)invocation.getArgs()[0];         
  45.         Object parameter = invocation.getArgs()[1];   
  46.         BoundSql boundSql = mappedStatement.getBoundSql(parameter);   
  47.         String originalSql = boundSql.getSql().trim();     
  48.         RowBounds rowBounds = (RowBounds)invocation.getArgs()[2];  
  49.         Object parameterObject = boundSql.getParameterObject();  
  50. if(boundSql==null || boundSql.getSql()==null || "".equals(boundSql.getSql()))  
  51. returnnull;  
  52. //分頁引數--上下文傳參
  53.         Page page = null;  
  54.         PageContext context=PageContext.getContext();  
  55. //map傳參每次都將currentPage重置,先判讀map再判斷context
  56. if(parameterObject!=null)  
  57.             page = (Page)ReflectHelper.isPage(parameterObject,"page");  
  58. //分頁引數--context引數裡的Page傳參
  59. if(page==null && context.isPagination()==true)  
  60.         {  
  61.             page = context;  
  62.         }  
  63. //後面用到了context的東東
  64. if(page!=null && page.isPagination()==true)               
  65.         {  
  66. int totpage=page.getTotalRows();    
  67. //得到總記錄數
  68. if (totpage==0)  
  69.             {  
  70.                 StringBuffer countSql  = new StringBuffer(originalSql.length()+100 );  
  71.                 countSql.append("select count(1) from (").append(originalSql).append(") t");  
  72.                      Connection connection=mappedStatement.getConfiguration().getEnvironment().getDataSource().getConnection()  ;            
  73.                  PreparedStatement countStmt = connection.prepareStatement(countSql.toString());    
  74.                  BoundSql countBS = new BoundSql(mappedStatement.getConfiguration(),countSql.toString(),boundSql.getParameterMappings(),parameterObject);    
  75.                  setParameters(countStmt,mappedStatement,countBS,parameterObject);    
  76.                  ResultSet rs = countStmt.executeQuery();    
  77. if (rs.next()) {    
  78.                      totpage = rs.getInt(1);    
  79.                  }    
  80.                  rs.close();    
  81.                  countStmt.close();    
  82.                  connection.close();  
  83.             }  
  84. //分頁計算
  85.             page.init(totpage,page.getPageSize(),page.getCurrentPage());  
  86. if(rowBounds == null || rowBounds == RowBounds.DEFAULT){  
  87.                 rowBounds= new RowBounds(page.getPageSize()*(page.getCurrentPage()-1),page.getPageSize());  
  88.             }     
  89. //分頁查詢 本地化物件 修改資料庫注意修改實現
  90.             String pagesql=dialect.getLimitString(originalSql, rowBounds.getOffset(), rowBounds.getLimit());  
  91.             invocation.getArgs()[2] = new RowBounds(RowBounds.NO_ROW_OFFSET, RowBounds.NO_ROW_LIMIT);     
  92.             BoundSql newBoundSql = new BoundSql(mappedStatement.getConfiguration(), pagesql,boundSql.getParameterMappings(),boundSql.getParameterObject());     
  93.             MappedStatement newMs = copyFromMappedStatement(mappedStatement,new BoundSqlSqlSource(newBoundSql));    
  94.             invocation.getArgs()[0]= newMs;    
  95.         }  
  96. return invocation.proceed();  
  97.     }  
  98. publicstaticclass BoundSqlSqlSource implements SqlSource {    
  99.         BoundSql boundSql;    
  100. public BoundSqlSqlSource(BoundSql boundSql) {    
  101. this.boundSql = boundSql;    
  102.         }    
  103. public BoundSql getBoundSql(Object parameterObject) {    
  104. return boundSql;    
  105.         }    
  106.     }    
  107. public Object plugin(Object arg0) {  
  108. return Plugin.wrap(arg0, this);  
  109.     }  
  110. publicvoid setProperties(Properties arg0) {  
  111.     }  
  112. /** 
  113.      * 對SQL引數(?)設值,參考org.apache.ibatis.executor.parameter.DefaultParameterHandler 
  114.      * @param ps 
  115.      * @param mappedStatement 
  116.      * @param boundSql 
  117.      * @param parameterObject 
  118.      * @throws SQLException 
  119.      */
  120. privatevoid setParameters(PreparedStatement ps,MappedStatement mappedStatement,BoundSql boundSql,Object parameterObject) throws SQLException {    
  121.         ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());    
  122.         List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();    
  123. if (parameterMappings != null) {    
  124.             Configuration configuration = mappedStatement.getConfiguration();    
  125.             TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();    
  126.             MetaObject metaObject = parameterObject == null ? null: configuration.newMetaObject(parameterObject);    
  127. for (int i = 0; i < parameterMappings.size(); i++) {    
  128.                 ParameterMapping parameterMapping = parameterMappings.get(i);    
  129. if (parameterMapping.getMode() != ParameterMode.OUT) {    
  130.                     Object value;    
  131.                     String propertyName = parameterMapping.getProperty();    
  132.                     PropertyTokenizer prop = new PropertyTokenizer(propertyName);    
  133. if (parameterObject == null) {    
  134.                         value = null;    
  135.                     } elseif (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {    
  136.                         value = parameterObject;    
  137.                     } elseif (boundSql.hasAdditionalParameter(propertyName)) {    
  138.                         value = boundSql.getAdditionalParameter(propertyName);    
  139.                     } elseif (propertyName.startsWith(ForEachSqlNode.ITEM_PREFIX)&& boundSql.hasAdditionalParameter(prop.getName())) {    
  140.                         value = boundSql.getAdditionalParameter(prop.getName());    
  141. if (value != null) {    
  142.                             value = configuration.newMetaObject(value).getValue(propertyName.substring(prop.getName().length()));    
  143.                         }    
  144.                     } else {    
  145.                         value = metaObject == null ? null : metaObject.getValue(propertyName);    
  146.                     }    
  147.                     TypeHandler typeHandler = parameterMapping.getTypeHandler();    
  148. if (typeHandler == null) {    
  149. thrownew ExecutorException("There was no TypeHandler found for parameter "+ propertyName + " of statement "+ mappedStatement.getId());    
  150.                     }    
  151.                     typeHandler.setParameter(ps, i + 1, value, parameterMapping.getJdbcType());    
  152.                 }    
  153.             }    
  154.         }    
  155.     }    
  156. private MappedStatement copyFromMappedStatement(MappedStatement ms,     
  157.              SqlSource newSqlSource) {     
  158.             Builder builder = new MappedStatement.Builder(ms.getConfiguration(),     
  159.             ms.getId(), newSqlSource, ms.getSqlCommandType());     
  160.             builder.resource(ms.getResource());     
  161.             builder.fetchSize(ms.getFetchSize());     
  162.             builder.statementType(ms.getStatementType());     
  163.             builder.keyGenerator(ms.getKeyGenerator());     
  164.             builder.keyProperty(ms.getKeyProperty());     
  165.             builder.timeout(ms.getTimeout());     
  166.              builder.parameterMap(ms.getParameterMap());     
  167.             builder.resultMaps(ms.getResultMaps());     
  168.             builder.cache(ms.getCache());     
  169.             MappedStatement newMs = builder.build();     
  170. return newMs;     
  171.             }     
  172. }  

簡要說明:剛剛忘記了,有一些查詢操作是不需要分頁的。可以自行修改攔截器中程式碼部分,加個判斷啥的。

5:spring 配置

[html] view plaincopy

  1. <beanid="paginationInterceptor"class="com.flydreamer.interceptor.PaginationInterceptor"></bean>

[html] view plaincopy

  1. <beanid="sqlSessionFactory"class="org.mybatis.spring.SqlSessionFactoryBean">
  2. <propertyname="dataSource"ref="dataSource"/>
  3. <propertyname="plugins">
  4. <refbean="paginationInterceptor"/>
  5. </property>
  6. </bean>