package com.sisco.db.daosupport.interceptor; import com.sisco.db.daosupport.Page; import com.sisco.db.daosupport.helper.PageHelper; import com.sisco.db.daosupport.helper.TypeHandlerHelper; import com.sisco.db.daosupport.type.DataBaseType; import com.sisco.sys.base.SpringContext; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.executor.resultset.DefaultResultSetHandler; import org.apache.ibatis.executor.resultset.ResultSetHandler; import org.apache.ibatis.mapping.*; import org.apache.ibatis.plugin.*; import org.apache.ibatis.reflection.MetaObject; import org.apache.ibatis.reflection.SystemMetaObject; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds; import org.springframework.stereotype.Component; import java.lang.reflect.Field; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.Statement; import java.util.*; @Intercepts({@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})}) @Component public class PageInterceptor implements Interceptor { private static final List<ResultMapping> emptyResultMapping = new ArrayList<>(0); private String prop = "spring.datasource.driver-class-name"; private Page page; private DataBaseType type; @Override public Object intercept(Invocation invocation) throws Throwable { //如果项目中分页的pageSize是统一的,也可以在这里统一配置和获取,这样就不用每次请求都传递pageSize参数了。参数是在配置拦截器时配置的。 if(this.type==null) { this.type = PageHelper.getDataBaseType(SpringContext.applicationContext.getEnvironment().getProperty(prop).toString()); } final Object[] args = invocation.getArgs(); if(invocation.getTarget() instanceof ResultSetHandler){ DefaultResultSetHandler handler = (DefaultResultSetHandler)invocation.getTarget(); Field field = handler.getClass().getDeclaredField("mappedStatement"); field.setAccessible(true); MappedStatement mappedStatement = (MappedStatement)field.get(handler); if(mappedStatement.getId().equals("com.sisco.db.daosupport.database.IDML.getResultSetByExecuteSql_$Page") || mappedStatement.getId().equals("com.sisco.db.daosupport.database.IDML.getDataSetByExecuteProcedure_$Page")){ List<Map> maps = new ArrayList<>(); Map<String,Object> actual = new HashMap<>(); Statement statement = (Statement) args[0]; ResultSet rs = statement.getResultSet(); ResultSetMetaData rsm = rs.getMetaData(); //获得列集 for(int i = 0; i< rs.getMetaData().getColumnCount(); i++){ String colName = rsm.getColumnName(i+1); actual.put(colName,""); } maps.add(actual); return maps; }else { return invocation.proceed(); } } Map<String,Object> params = (Map<String,Object>)args[1]; //参数默认设置 if(params!=null && params.containsKey("params") && params.get("params")!=null){ Map<String,Object> map = TypeHandlerHelper.nullToEmpty((Map<String,Object>)params.get("params")); params.put("params",map); } //分页 if(params!=null && params.containsKey("page") && params.get("page")!=null && (params.get("page") instanceof Page)){ page = (Page)params.get("page"); MappedStatement ms = (MappedStatement) args[0]; Object parameterObject = args[1]; BoundSql boundSql = ms.getBoundSql(parameterObject); // 将参数中的MappedStatement替换为新的qs,防止并发异常 MappedStatement qs = createMappedStatement(ms, new BoundSqlSqlSource(boundSql)); args[0] = qs; MetaObject msObject = SystemMetaObject.forObject(qs); String sql = (String) msObject.getValue("sqlSource.boundSql.sql"); // 简单的通过total的值来判断是否进行count查询 if(page.getQueryCount()==null || page.getQueryCount()){ // 求count - 重写sql msObject.setValue("sqlSource.boundSql.sql", getCountSql(sql)); // 查询总数 Object result = invocation.proceed(); int totalCount = (Integer) ((List) result).get(0); page.setTotalRecord(new Long(totalCount)); } // 分页sql - 重写sql msObject.setValue("sqlSource.boundSql.sql",getPageSql(sql, page)); // 恢复类型 msObject.setValue("resultMaps", ms.getResultMaps()); } return invocation.proceed(); } /** * 只拦截Executor、ResultSetHandler * @param target * @return */ @Override public Object plugin(Object target) { //生成object对象的动态代理对象 if (target instanceof Executor || target instanceof ResultSetHandler) { return Plugin.wrap(target, this); } else { return target; } } //设置代理对象的参数 @Override public void setProperties(Properties properties) { System.out.println(properties); } /** * 获取统计条数的 sql * @param sql * @return */ public String getCountSql(String sql){ switch (type){ case sqlserver: case oracle: if(sql.toUpperCase().lastIndexOf("ORDER BY") > 0){ sql = sql.substring(0,sql.toUpperCase().lastIndexOf("ORDER BY")); } break; default: sql = "select count(0) from (" + sql + ") tmp_count"; } return sql; } /** * 获取分页sql * @param sql * @param page * @return */ private String getPageSql(String sql, Page page) { StringBuilder pageSql = new StringBuilder(); switch (type){ case mysql: pageSql.append(sql); pageSql.append(" limit " + page.getStartPage() + "," + page.getPageSize()); break; case oracle: pageSql.append("SELECT * FROM ( "); pageSql.append(" SELECT TMP_PAGE.*, ROWNUM ROW_ID FROM ( "); pageSql.append(" " + sql); pageSql.append(" ) TMP_PAGE "); pageSql.append(") PAGE_T "); pageSql.append(" WHERE ROW_ID <= "+ page.getPageSize()* page.getCurrentPage()+" AND ROW_ID > " + page.getStartPage() ); break; case sqlserver: pageSql.append("SELECT * FROM ("); if(sql.toUpperCase().lastIndexOf("ORDER BY") > 0){ pageSql.append(" SELECT TMP_PAGE.*, ROW_NUMBER() OVER (" + sql.substring(sql.toUpperCase().lastIndexOf("ORDER BY")) + ") as ROW_ID FROM ("); pageSql.append(" " + sql); pageSql.append(" ) TMP_PAGE"); }else { pageSql.append(" SELECT TMP_PAGE.*, ROW_NUMBER() OVER (ORDER BY rownum) as ROW_ID FROM ( "); pageSql.append(" SELECT *,1 as rownum FROM ("); pageSql.append(" " + sql); pageSql.append(" ) TMP_T "); pageSql.append(" ) TMP_PAGE"); } pageSql.append(") PAGE_T "); pageSql.append(" WHERE ROW_ID <= " + page.getPageSize() * page.getCurrentPage() + " AND ROW_ID > " + page.getStartPage()); break; } return pageSql.toString(); } /** * 由于MappedStatement是一个全局共享的对象 * 因而需要复制一个对象来进行操作 * 防止并发访问导致错误 * @param ms * @param newSqlSource * @return */ private MappedStatement createMappedStatement(MappedStatement ms,SqlSource newSqlSource) { MappedStatement.Builder builder = new MappedStatement.Builder(ms.getConfiguration(), ms.getId() + "_$Page", newSqlSource,ms.getSqlCommandType()); builder.resource(ms.getResource()); builder.fetchSize(ms.getFetchSize()); builder.statementType(ms.getStatementType()); builder.keyGenerator(ms.getKeyGenerator()); if (ms.getKeyProperties() != null && ms.getKeyProperties().length != 0) { StringBuffer keyProperties = new StringBuffer(); for (String keyProperty : ms.getKeyProperties()) { keyProperties.append(keyProperty).append(","); } keyProperties.delete(keyProperties.length() - 1,keyProperties.length()); builder.keyProperty(keyProperties.toString()); } builder.timeout(ms.getTimeout()); builder.parameterMap(ms.getParameterMap()); // 由于resultMaps第一次需要返回int类型的结果,所以这里需要生成一个resultMap - 防止并发错误 List<ResultMap> resultMaps = new ArrayList<>(); ResultMap resultMap = new ResultMap.Builder(ms.getConfiguration(),ms.getId(), int.class, emptyResultMapping).build(); resultMaps.add(resultMap); builder.resultMaps(resultMaps); builder.resultSetType(ms.getResultSetType()); builder.cache(ms.getCache()); builder.flushCacheRequired(ms.isFlushCacheRequired()); builder.useCache(ms.isUseCache()); return builder.build(); } private class BoundSqlSqlSource implements SqlSource { BoundSql boundSql; public BoundSqlSqlSource(BoundSql boundSql) { this.boundSql = boundSql; } public BoundSql getBoundSql(Object parameterObject) { return boundSql; } } }
mybatis没有查询到数据如何获取字段名(包括分页代码)
最新推荐文章于 2023-05-17 14:12:53 发布