springMVC、myBatis的物理分頁和高階查詢
阿新 • • 發佈:2019-02-13
最新專案用到springMVC和mybatis,分頁其實用一個RowBounds可以實現,但是高階查詢不好封裝, 經過反覆測試,總算搞出來了,感覺封裝的不是很好,有待優化和提高!
原理:利用mybatis自定義外掛功能,自定義一個攔截器,攔截需要分頁的sql,並想辦法通過BoundSql物件進行處理,大致分8步:
1、獲得BoundSql物件
2、獲取原始的寫在配置檔案中的SQL
3、攔截到mapper中定義的執行查詢方法中的引數
4、解析引數,獲取高階查詢引數資訊
5、解析引數,獲取查詢限制條件
6、根據4、5中的引數拼裝並重新生成SQL語句
7、將SQL設定回BoundSql物件中
8、完成。
攔截器:
Java程式碼- package com.wtas.page.interceptor;
- import java.sql.Connection;
- import java.sql.PreparedStatement;
- import java.sql.ResultSet;
- import java.sql.SQLException;
- import java.util.List;
- import java.util.Map;
-
import java.util.Properties;
- import java.util.Set;
- import javax.xml.bind.PropertyException;
- import org.apache.ibatis.executor.ErrorContext;
- import org.apache.ibatis.executor.ExecutorException;
- import org.apache.ibatis.executor.statement.BaseStatementHandler;
-
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
- import org.apache.ibatis.executor.statement.StatementHandler;
- import org.apache.ibatis.mapping.BoundSql;
- import org.apache.ibatis.mapping.MappedStatement;
- import org.apache.ibatis.mapping.ParameterMapping;
- import org.apache.ibatis.mapping.ParameterMode;
- 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.MetaObject;
- import org.apache.ibatis.reflection.property.PropertyTokenizer;
- import org.apache.ibatis.scripting.xmltags.ForEachSqlNode;
- import org.apache.ibatis.session.Configuration;
- import org.apache.ibatis.type.TypeHandler;
- import org.apache.ibatis.type.TypeHandlerRegistry;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import com.wtas.page.PageContext;
- import com.wtas.page.Pager;
- import com.wtas.page.Query;
- import com.wtas.utils.SystemUtil;
- /**
- * 查詢分頁攔截器,使用者攔截SQL,並加上分頁的引數和高階查詢條件
- *
- * @author dendy
- *
- */
- @Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class }) })
- public class PaginationInterceptor implements Interceptor {
- private final Logger logger = LoggerFactory
- .getLogger(PaginationInterceptor.class);
- private String dialect = "";
- // 暫時不需要這個引數,現在根據引數型別來判斷是否是分頁sql
- // private String pageMethodPattern = "";
- public Object intercept(Invocation ivk) throws Throwable {
- if (!(ivk.getTarget() instanceof RoutingStatementHandler)) {
- return ivk.proceed();
- }
- RoutingStatementHandler statementHandler = (RoutingStatementHandler) ivk
- .getTarget();
- BaseStatementHandler delegate = (BaseStatementHandler) SystemUtil
- .getValueByFieldName(statementHandler, "delegate");
- MappedStatement mappedStatement = (MappedStatement) SystemUtil
- .getValueByFieldName(delegate, "mappedStatement");
- // BoundSql封裝了sql語句
- BoundSql boundSql = delegate.getBoundSql();
- // 獲得查詢物件
- Object parameterObject = boundSql.getParameterObject();
- // 根據引數型別判斷是否是分頁方法
- if (!(parameterObject instanceof Query)) {
- return ivk.proceed();
- }
- logger.debug(" beginning to intercept page SQL...");
- Connection connection = (Connection) ivk.getArgs()[0];
- String sql = boundSql.getSql();
- Query query = (Query) parameterObject;
- // 查詢引數物件
- Pager pager = null;
- // 查詢條件Map
- Map<String, Object> conditions = query.getQueryParams();
- pager = query.getPager();
- // 拼裝查詢條件
- if (conditions != null) {
- Set<String> keys = conditions.keySet();
- Object value = null;
- StringBuffer sb = new StringBuffer();
- boolean first = true;
- for (String key : keys) {
- value = conditions.get(key);
- if (first) {
- sb.append(" where ").append(key).append(value);
- first = !first;
- } else {
- sb.append(" and ").append(key).append(value);
- }
- }
- sql += sb.toString();
- }
- // 獲取查詢數來的總數目
- String countSql = "SELECT COUNT(0) FROM (" + sql + ") AS tmp ";
- PreparedStatement countStmt = connection.prepareStatement(countSql);
- BoundSql countBS = new BoundSql(mappedStatement.getConfiguration(),
- countSql, boundSql.getParameterMappings(), parameterObject);
- setParameters(countStmt, mappedStatement, countBS, parameterObject);
- ResultSet rs = countStmt.executeQuery();
- int count = 0;
- if (rs.next()) {
- count = rs.getInt(1);
- }
- rs.close();
- countStmt.close();
- // 設定總記錄數
- pager.setTotalResult(count);
- // 設定總頁數
- pager.setTotalPage((count + pager.getShowCount() - 1)
- / pager.getShowCount());
- // 放到作用於
- PageContext.getInstance().set(pager);
- // 拼裝查詢引數
- String pageSql = generatePageSql(sql, pager);
- SystemUtil.setValueByFieldName(boundSql, "sql", pageSql);
- logger.debug("generated pageSql is : " + pageSql);
- return ivk.proceed();
- }
- /**
- * setting parameters
- *
- * @param ps
- * @param mappedStatement
- * @param boundSql
- * @param parameterObject
- * @throws SQLException
- */
- private void setParameters(PreparedStatement ps,
- MappedStatement mappedStatement, BoundSql boundSql,
- Object parameterObject) throws SQLException {
- ErrorContext.instance().activity("setting parameters")
- .object(mappedStatement.getParameterMap().getId());
- List<ParameterMapping> parameterMappings = boundSql
- .getParameterMappings();
- if (parameterMappings != null) {
- Configuration configuration = mappedStatement.getConfiguration();
- TypeHandlerRegistry typeHandlerRegistry = configuration
- .getTypeHandlerRegistry();
- MetaObject metaObject = parameterObject == null ? null
- : configuration.newMetaObject(parameterObject);
- for (int i = 0; i < parameterMappings.size(); i++) {
- ParameterMapping parameterMapping = parameterMappings.get(i);
- if (parameterMapping.getMode() != ParameterMode.OUT) {
- Object value;
- String propertyName = parameterMapping.getProperty();
- PropertyTokenizer prop = new PropertyTokenizer(propertyName);
- if (parameterObject == null) {
- value = null;
- } else if (typeHandlerRegistry
- .hasTypeHandler(parameterObject.getClass())) {
- value = parameterObject;
- } else if (boundSql.hasAdditionalParameter(propertyName)) {
- value = boundSql.getAdditionalParameter(propertyName);
- } else if (propertyName
- .startsWith(ForEachSqlNode.ITEM_PREFIX)
- && boundSql.hasAdditionalParameter(prop.getName())) {
- value = boundSql.getAdditionalParameter(prop.getName());
- if (value != null) {
- value = configuration.newMetaObject(value)
- .getValue(
- propertyName.substring(prop
- .getName().length()));
- } <