簡要描述mybatis插件實現分頁

第一步:在mybatis配置文件中配置攔截器

<plugins>
    <plugin interceptor="x.x.x.x.x.x.xxxInterceptor" />
</plugins>

第二步:實現攔截器

package com.mg.background.common.persistence.interceptor;

import java.util.Properties;

import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;
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.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import com.mg.background.common.persistence.Pages;
import com.mg.background.common.persistence.utils.Reflections;

//攔截器註解,攔截器必須實現Interceptor接口
//AbstractInterceptor實現了Interceptor接口
//@Intercepts的參數中爲@Signature的數組,表示要攔截的類和類中要攔截的方法
//args爲這個方法需要的參數
//MappedStatement.class 爲一個節點對象 即<select/><insert/>之類
//RowBounds.class分頁對象 他的offset和limit屬性表示要展示數據的範圍
//ResultHandler.class結果集映射
@Intercepts({ @Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class }) })
public class PaginationInterceptor extends AbstractInterceptor {
    private static final long serialVersionUID = 4989671349466153547L;

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
    final MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
        Object parameter = invocation.getArgs()[1];
        //boundSql爲一條sql語句動態運行對象
        //mappedStatement.getBoundSql(parameter);動態計算sql運行的條件
        //即<if/>條件的計算,然後生成要運行的sql
        BoundSql boundSql = mappedStatement.getBoundSql(parameter);
        //得到入參類型
        Object parameterObject = boundSql.getParameterObject();
        //獲取分頁參數對象
        Pages<Object> pages = null;
        if (parameterObject != null) {
            //利用反射機制訪問對象屬性
            pages = convertParameter(parameterObject, pages);
        }
        //如果設置了分頁對象,則進行分頁
        if (pages != null && pages.getPageSize() != -1) {
            if (StringUtils.isBlank(boundSql.getSql())) {
                return null;
            }
            String originalSql = boundSql.getSql().trim();
            //得到總記錄數
            pages.setTotal(SQLHelper.getCount(originalSql, null, mappedStatement, parameterObject, boundSql, log));
            //分頁查詢 本地化對象 修改數據庫注意修改實現
            String pageSql = SQLHelper.generatePageSql(originalSql, pages, DIALECT);
            //                if (log.isDebugEnabled()) {
            //                    log.debug("PAGE SQL:" + StringUtils.replace(pageSql, "\n", ""));
            //                }
            invocation.getArgs()[2] = new RowBounds(RowBounds.NO_ROW_OFFSET, RowBounds.NO_ROW_LIMIT);
            BoundSql newBoundSql = new BoundSql(mappedStatement.getConfiguration(), pageSql, boundSql.getParameterMappings(), boundSql.getParameterObject());
            //解決MyBatis 分頁foreach 參數失效 start
            if (Reflections.getFieldValue(boundSql, "metaParameters") != null) {
                MetaObject mo = (MetaObject) Reflections.getFieldValue(boundSql, "metaParameters");
                Reflections.setFieldValue(newBoundSql, "metaParameters", mo);
            }
            //解決MyBatis 分頁foreach 參數失效 end
            MappedStatement newMs = copyFromMappedStatement(mappedStatement, new BoundSqlSqlSource(newBoundSql));
            invocation.getArgs()[0] = newMs;
        }
        //        }
        return invocation.proceed();
    }

    //綁定插件
    @Override
    public Object plugin(Object target) {
        //如果target有接口返回代理類,沒有返回類本身
        //如果代理類wrap方法會綁定一個攔截器,調用plugin的invoke方法
        //將攔截的方法的參數初始化成一個Invocation對象 然後調用intercept方法
        return Plugin.wrap(target, this);
    }

    //初始化攔截器時將配置文件中攔截器下配置的properties設置進來
    @Override
    public void setProperties(Properties properties) {
        super.initProperties(properties);
    }

    private MappedStatement copyFromMappedStatement(MappedStatement ms, SqlSource newSqlSource) {
        MappedStatement.Builder builder = new MappedStatement.Builder(ms.getConfiguration(), ms.getId(), newSqlSource, ms.getSqlCommandType());
        builder.resource(ms.getResource());
        builder.fetchSize(ms.getFetchSize());
        builder.statementType(ms.getStatementType());
        builder.keyGenerator(ms.getKeyGenerator());
        if (ms.getKeyProperties() != null) {
            for (String keyProperty : ms.getKeyProperties()) {
                builder.keyProperty(keyProperty);
            }
        }
        builder.timeout(ms.getTimeout());
        builder.parameterMap(ms.getParameterMap());
        builder.resultMaps(ms.getResultMaps());
        builder.cache(ms.getCache());
        return builder.build();
    }

    public static class BoundSqlSqlSource implements SqlSource {
        BoundSql boundSql;

        public BoundSqlSqlSource(BoundSql boundSql) {
            this.boundSql = boundSql;
        }

        public BoundSql getBoundSql(Object parameterObject) {
            return boundSql;
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章