mybatis没有查询到数据如何获取字段名(包括分页代码)

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;
        }
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值