mybatis 分页插件

package org.gjl.interceptor;

import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.scripting.defaults.DefaultParameterHandler;
import org.apache.ibatis.session.Configuration;
import org.gjl.vo.Parameters;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

/**
 * @Author GJL
 * @Desription
 * @Date 2017/12/6
 * @Modified By:
 **/
@Intercepts({@Signature(type = StatementHandler.class,method = "prepare",args = {Connection.class,Integer.class})})
public class MyInterceptor implements Interceptor{
    private Integer defaultPage;
    private Integer defaultPageSize;
    private Boolean defaultUseFlag;
    private Boolean defaultCheckFlag;
    private Boolean defaultCleanOyderBy;




    public Object intercept(Invocation invocation) throws Throwable {

        StatementHandler stmtHandler = (StatementHandler)getUnproxyObject(invocation.getTarget());
        MetaObject metaStatementHandler =  SystemMetaObject.forObject(stmtHandler);
        String sql = (String)metaStatementHandler.getValue("delegate.boundSql.sql");
        //mappedStatement 保存了一个映射器节点的内容 包含 我们配置的sql id 缓存信息 jdbcType javaType ResultType
        // ParameterType等重要内容 还有SqlSource 接口 该接口有多中实现 ,getBoundSql(ParameterObject)是他的方法。
        MappedStatement mappedStatement = (MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement");
        if(!checkSeleck(sql)){
            invocation.proceed();
        }
        BoundSql boundSql = (BoundSql) metaStatementHandler.getValue("delegate.boundSql");
        Object parameterObject = boundSql.getParameterObject();
        //获取到参数
       Parameters pageParams = getPageParamsFromParamObj(parameterObject);
       if(pageParams == null){
           return invocation.proceed();
       }
       //若不使用插件 则直接返回
       Boolean useFlag = pageParams.getUseFlag() == null?this.defaultUseFlag:pageParams.getUseFlag();
       if(!useFlag){
           return invocation.proceed();
       }
       //获取相关配置的参数
        Integer currentPage = pageParams.getCurrentPage() == null?this.defaultPage:pageParams.getCurrentPage();
       Integer pageSize = pageParams.getPageSize() == null ?this.defaultPageSize:pageParams.getPageSize();
       Boolean cleanOrderBy = pageParams.getCleanOrderBy() == null ?this.defaultCleanOyderBy:pageParams.getCleanOrderBy();
       Boolean checkFlag = pageParams.getCheckFlag() == null ?this.defaultCheckFlag:pageParams.getCheckFlag();
       //计算总条数
        int total = getTotal(invocation,metaStatementHandler,boundSql,cleanOrderBy);
        //回填总条数到页面参数
        pageParams.setTotal(total);
        //计算总页数
        int totalPage = total%pageSize == 0 ? total/pageSize : total/pageSize+1;
        //回填总页数到分页参数
        pageParams.setTotalPage(totalPage);

        //检查当前页码的有效性
        checkPage(checkFlag,currentPage,totalPage);

        //修改sql
        return prepareSQl(invocation,metaStatementHandler,boundSql,currentPage,pageSize);
    }

    private Object prepareSQl(Invocation invocation, MetaObject metaStatementHandler, BoundSql boundSql, Integer currentPage, Integer pageSize) throws InvocationTargetException, IllegalAccessException, SQLException {
            String sql = boundSql.getSql();
            String newSql = "select * from ("+sql+") $_paging_table  limit ?,?";
            metaStatementHandler.setValue("delegate.boundSql.sql",newSql);
             Object statementObj = invocation.proceed();
             this.preparePageDataParams((PreparedStatement)statementObj,currentPage,pageSize);
             return statementObj;

    }

    private void preparePageDataParams(PreparedStatement preparedStatement, Integer currentPage, Integer pageSize) throws SQLException {
        int idx = preparedStatement.getParameterMetaData().getParameterCount();
        preparedStatement.setInt(idx-1,(currentPage-1)*pageSize);
        preparedStatement.setInt(idx,pageSize);


    }

    private void checkPage(Boolean checkFlag, Integer currentPage, int totalPage) throws Exception {
        if(checkFlag){
            if(currentPage>totalPage){
                throw new Exception("查询失败【"+currentPage+"】大于总页数"+"【"+totalPage+"】!!");
            }
        }
    }

    private int getTotal(Invocation ivt, MetaObject metaStatementHandler, BoundSql boundSql, Boolean cleanOrderBy) {
        //获取当前的MappedStatement
       MappedStatement mappedStatement = (MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement");
       //配置对象
        Configuration cfg = mappedStatement.getConfiguration();
        //当前需要执行的sql
        String sql = (String)metaStatementHandler.getValue("delegate.boundSql.sql");
        //去掉最后的clearOrderBy
        sql = cleanOrderByForSql(sql);
        //改写为统计总数的sql语句
        String countSql = "select count(*) as total from ("+sql+") $_paging";
        Connection connection = (Connection) ivt.getArgs()[0];
        PreparedStatement ps = null;
        int total =0;
        try {
            ps = connection.prepareStatement(countSql);
            BoundSql countBoundSql = new BoundSql(cfg,countSql,boundSql.getParameterMappings(),boundSql.getParameterObject());
            ParameterHandler handler = new DefaultParameterHandler(mappedStatement,boundSql.getParameterObject(),countBoundSql);
            handler.setParameters(ps);
            ResultSet rs = ps.executeQuery();
            while(rs.next()){
                 total = rs.getInt("total");
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            if(ps !=null){
                try {
                    ps.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
        return total;
    }

    private String cleanOrderByForSql(String sql) {
        StringBuilder sb = new StringBuilder(sql);
        String newSql  = sql.toLowerCase();

        int index = newSql.lastIndexOf("order");
        if(index == -1){
            return sql;
        }

        return sb.substring(0,index);
    }

    private Parameters getPageParamsFromParamObj(Object parameterObject) {
        Parameters parameters = null;
        if(parameterObject == null){
            return null;
        }
        if(parameterObject instanceof Map){
            Map<String,Object> paramMap = (Map<String,Object>) parameterObject;
            Set<String> keySet = paramMap.keySet();
            Iterator<String> iterator = keySet.iterator();
            while(iterator.hasNext()){
                String key = iterator.next();
                Object value = paramMap.get(key);
                if(value instanceof Parameters){
                    return (Parameters) value;
                }
            }

        }else if(parameterObject instanceof Parameters){
            return (Parameters)parameterObject;

        }else{
            Field[] fields = parameterObject.getClass().getDeclaredFields();

            for(Field field :fields){
                if(field.getType() == Parameters.class){
                    try {
                        PropertyDescriptor pd = new PropertyDescriptor(field.getName(),parameterObject.getClass());
                      Method method =   pd.getReadMethod();
                      return (Parameters) method.invoke(parameterObject);
                    } catch (IntrospectionException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return parameters;

    }

    private boolean checkSeleck(String sql) {
        String trimSql = sql.trim();
        int  index = trimSql.indexOf("select");
        return index == 0;
    }

    private Object getUnproxyObject(Object target) {
        MetaObject metaObject = SystemMetaObject.forObject(target);
        Object object = null;
        while(metaObject.hasGetter("h")){
            object = metaObject.getValue("h");
            metaObject = SystemMetaObject.forObject(object);
        }


        if(object == null){
            return target;
        }
        return object;
    }

    public Object plugin(Object target) {
        return Plugin.wrap(target,this);
    }
    //设置插件配置参数
    public void setProperties(Properties properties) {
        String strDefaultPage =  properties.getProperty("default.page","1");
        String strDefaultPageSize = properties.getProperty("default.pageSize","50");
        String strDefaultUseFlag = properties.getProperty("default.useFlag","false");
        String strDefaultCheckFlag = properties.getProperty("default.checkFlag","false");
        String strDefaultCleanOrderBy = properties.getProperty("default.cleanOrderBy","false");
        this.defaultPage = Integer.parseInt(strDefaultPage);
        this.defaultPageSize = Integer.parseInt(strDefaultPageSize);
        this.defaultCheckFlag = Boolean.parseBoolean(strDefaultCheckFlag);
        this.defaultUseFlag = Boolean.parseBoolean(strDefaultUseFlag);
        this.defaultCleanOyderBy = Boolean.parseBoolean(strDefaultCleanOrderBy);

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值