Java tutorial
/* * The MIT License (MIT) * * Copyright (c) 2014-2017 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.sinotopia.mybatis.pagehelper; import com.sinotopia.mybatis.pagehelper.cache.Cache; import com.sinotopia.mybatis.pagehelper.cache.CacheFactory; import com.sinotopia.mybatis.pagehelper.util.MSUtils; import com.sinotopia.mybatis.pagehelper.util.StringUtil; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.plugin.*; import org.apache.ibatis.session.Configuration; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds; import java.lang.reflect.Field; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Properties; /** * Mybatis - <br/> * ? : http://git.oschina.net/free/Mybatis_PageHelper * * @author cacotopia * @version 5.0.0 */ @SuppressWarnings({ "rawtypes", "unchecked" }) @Intercepts({ @Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class }), @Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class }), }) public class PageInterceptor implements Interceptor { //countms protected Cache<String, MappedStatement> msCountMap = null; private Dialect dialect; private String default_dialect_class = "com.github.pagehelper.PageHelper"; private Field additionalParametersField; private String countSuffix = "_COUNT"; @Override public Object intercept(Invocation invocation) throws Throwable { try { Object[] args = invocation.getArgs(); MappedStatement ms = (MappedStatement) args[0]; Object parameter = args[1]; RowBounds rowBounds = (RowBounds) args[2]; ResultHandler resultHandler = (ResultHandler) args[3]; Executor executor = (Executor) invocation.getTarget(); CacheKey cacheKey; BoundSql boundSql; //? if (args.length == 4) { //4 ? boundSql = ms.getBoundSql(parameter); cacheKey = executor.createCacheKey(ms, parameter, rowBounds, boundSql); } else { //6 ? cacheKey = (CacheKey) args[4]; boundSql = (BoundSql) args[5]; } List resultList; //???? if (!dialect.skip(ms, parameter, rowBounds)) { //????? String msId = ms.getId(); Configuration configuration = ms.getConfiguration(); Map<String, Object> additionalParameters = (Map<String, Object>) additionalParametersField .get(boundSql); //?? count if (dialect.beforeCount(ms, parameter, rowBounds)) { String countMsId = msId + countSuffix; Long count; //? count MappedStatement countMs = getExistedMappedStatement(configuration, countMsId); if (countMs != null) { count = executeManualCount(executor, countMs, parameter, boundSql, resultHandler); } else { countMs = msCountMap.get(countMsId); // if (countMs == null) { //?? ms Long ms countMs = MSUtils.newCountMappedStatement(ms, countMsId); msCountMap.put(countMsId, countMs); } count = executeAutoCount(executor, countMs, parameter, boundSql, rowBounds, resultHandler); } //? // true false if (!dialect.afterCount(count, parameter, rowBounds)) { // 0 return dialect.afterPage(new ArrayList(), parameter, rowBounds); } } //?? if (dialect.beforePage(ms, parameter, rowBounds)) { //? key CacheKey pageKey = cacheKey; //?? parameter = dialect.processParameterObject(ms, parameter, boundSql, pageKey); //? sql String pageSql = dialect.getPageSql(ms, boundSql, parameter, rowBounds, pageKey); BoundSql pageBoundSql = new BoundSql(configuration, pageSql, boundSql.getParameterMappings(), parameter); //?? for (String key : additionalParameters.keySet()) { pageBoundSql.setAdditionalParameter(key, additionalParameters.get(key)); } // resultList = executor.query(ms, parameter, RowBounds.DEFAULT, resultHandler, pageKey, pageBoundSql); } else { //?? resultList = executor.query(ms, parameter, RowBounds.DEFAULT, resultHandler, cacheKey, boundSql); } } else { //rowBounds?????? resultList = executor.query(ms, parameter, rowBounds, resultHandler, cacheKey, boundSql); } return dialect.afterPage(resultList, parameter, rowBounds); } finally { dialect.afterAll(); } } /** * count ??? * * @param executor * @param countMs * @param parameter * @param boundSql * @param resultHandler * @return * @throws IllegalAccessException * @throws SQLException */ private Long executeManualCount(Executor executor, MappedStatement countMs, Object parameter, BoundSql boundSql, ResultHandler resultHandler) throws IllegalAccessException, SQLException { CacheKey countKey = executor.createCacheKey(countMs, parameter, RowBounds.DEFAULT, boundSql); BoundSql countBoundSql = countMs.getBoundSql(parameter); Object countResultList = executor.query(countMs, parameter, RowBounds.DEFAULT, resultHandler, countKey, countBoundSql); Long count = ((Number) ((List) countResultList).get(0)).longValue(); return count; } /** * ? count * * @param executor * @param countMs * @param parameter * @param boundSql * @param rowBounds * @param resultHandler * @return * @throws IllegalAccessException * @throws SQLException */ private Long executeAutoCount(Executor executor, MappedStatement countMs, Object parameter, BoundSql boundSql, RowBounds rowBounds, ResultHandler resultHandler) throws IllegalAccessException, SQLException { Map<String, Object> additionalParameters = (Map<String, Object>) additionalParametersField.get(boundSql); // count key CacheKey countKey = executor.createCacheKey(countMs, parameter, RowBounds.DEFAULT, boundSql); //? count sql String countSql = dialect.getCountSql(countMs, boundSql, parameter, rowBounds, countKey); //countKey.update(countSql); BoundSql countBoundSql = new BoundSql(countMs.getConfiguration(), countSql, boundSql.getParameterMappings(), parameter); //? SQL ???? BoundSql for (String key : additionalParameters.keySet()) { countBoundSql.setAdditionalParameter(key, additionalParameters.get(key)); } // count Object countResultList = executor.query(countMs, parameter, RowBounds.DEFAULT, resultHandler, countKey, countBoundSql); Long count = (Long) ((List) countResultList).get(0); return count; } /** * ??? MS??countpage? * * @param configuration * @param msId * @return */ private MappedStatement getExistedMappedStatement(Configuration configuration, String msId) { MappedStatement mappedStatement = null; try { mappedStatement = configuration.getMappedStatement(msId, false); } catch (Throwable t) { //ignore } return mappedStatement; } @Override public Object plugin(Object target) { //TODO Spring bean ????? setProperties ???? //TODO https://github.com/pagehelper/Mybatis-PageHelper/issues/26 return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { // count ms msCountMap = CacheFactory.createCache(properties.getProperty("msCountCache"), "ms", properties); String dialectClass = properties.getProperty("dialect"); if (StringUtil.isEmpty(dialectClass)) { dialectClass = default_dialect_class; } try { Class<?> aClass = Class.forName(dialectClass); dialect = (Dialect) aClass.newInstance(); } catch (Exception e) { throw new PageException(e); } dialect.setProperties(properties); String countSuffix = properties.getProperty("countSuffix"); if (StringUtil.isNotEmpty(countSuffix)) { this.countSuffix = countSuffix; } try { //??? BoundSql additionalParameters additionalParametersField = BoundSql.class.getDeclaredField("additionalParameters"); additionalParametersField.setAccessible(true); } catch (NoSuchFieldException e) { throw new PageException(e); } } }