日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

使用mybatis的interceptor修改执行sql以及传入参数

發布時間:2023/12/15 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 使用mybatis的interceptor修改执行sql以及传入参数 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
項目中途遇到業務需求更改,在查詢某張表時需要增加條件,由于涉及的sql語句多而且依賴其他服務的jar,逐個修改sql語句和接口太繁雜。項目使用mybatis框架,因此借鑒PageHelper插件嘗試使用mybatis的Interceptor來實現改需求。
總體思路:
  • 從BoundSql中獲取sql,通過正則匹配替換表名為子查詢REPLACE_TXT
  • 添加子查詢REPLACE_TXT 中需要用到的參數到mybatis參數列表中
  • 添加參數與占位符映射,即添加ParameterMapping對象到ParameterMappings中,由于statement在執行時是按照ParameterMappings的元素索引定位占位符封裝參數(即ParameterMappings中的第一個參數會封裝到第一個占位符上),因此ParameterMappings中的參數順序需要和占位符保持一致。其次ParameterMappings的元素個數需要和占位符個數保持一致。
  • 為了保證該intercept在最后執行,使用AutoConfiguration將intercept添加到SqlSessionFactory的Configuration中,并在spring.factories文件中添加AutoConfiguration
  • 未測試性能以及是否存在未知缺陷
1、Interceptor 代碼實現
package org.cnbi.project.other.sql.intercept;import cn.hutool.core.util.NumberUtil; import com.cnbi.cloud.common.core.exception.ServiceException; import com.github.pagehelper.Page; import com.github.pagehelper.util.ExecutorUtil; import com.github.pagehelper.util.MetaObjectUtil; import org.apache.ibatis.builder.annotation.ProviderSqlSource; 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.mapping.ParameterMapping; import org.apache.ibatis.plugin.*; import org.apache.ibatis.reflection.MetaObject; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds; import org.cnbi.project.other.sql.aop.PeriodHolder; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern;/*** @ClassName ParamInterceptor* @Description 修改接口太繁瑣,直接用mybatis攔截器對查詢sql進行攔截,將期間參數注入sql* @Author Wangjunkai* @Date 2019/10/23 11:36**/ @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 ParamInterceptor implements Interceptor {private final static Pattern DW_DIMCOMPANY = Pattern.compile("dw_dimcompany", Pattern.CASE_INSENSITIVE);private final static String REPLACE_TXT = "(select * from dw_dimcompany where cisdel = '0' and START_PERIOD <= ? and END_PERIOD > ?)";@Overridepublic Object intercept(Invocation invocation) throws Throwable {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){boundSql = ms.getBoundSql(parameter);} else {boundSql = (BoundSql) args[5];}//獲取sql語句,使用正則忽略大小寫匹配String sql = boundSql.getSql();Matcher matcher = DW_DIMCOMPANY.matcher(sql);//沒有需要替換的表名則放行if(!matcher.find()){return invocation.proceed();}//收集占位符個數(即paramIndex 的size)以及占位符次序(slot:即參數在ParameterMappings中的順序)int index = 0;ArrayList<Integer> paramIndex = new ArrayList<>();while(matcher.find(index)){index = matcher.end();String sqlPart = sql.substring(0, index);int slot = index - sqlPart.replace("?", "").length() + paramIndex.size() ;paramIndex.add(slot);paramIndex.add(slot + 1);}//替換子查詢String companyPeriodSql = matcher.replaceAll(REPLACE_TXT);cacheKey = args.length == 4 ? executor.createCacheKey(ms, parameter, rowBounds, boundSql) : (CacheKey) args[4];//處理參數Object parameterObject = processParameterObject(ms, parameter, boundSql, cacheKey, paramIndex);BoundSql companyPeriodBoundSql = new BoundSql(ms.getConfiguration(), companyPeriodSql, boundSql.getParameterMappings(), parameterObject);Map<String, Object> additionalParameters = ExecutorUtil.getAdditionalParameter(boundSql);//設置動態參數for (String key : additionalParameters.keySet()) {companyPeriodBoundSql.setAdditionalParameter(key, additionalParameters.get(key));}return executor.query(ms, parameterObject, RowBounds.DEFAULT, resultHandler, cacheKey, companyPeriodBoundSql);}public Object processParameterObject(MappedStatement ms, Object parameterObject, BoundSql boundSql, CacheKey pageKey, ArrayList<Integer> paramIndex) {//處理參數Map<String, Object> paramMap = null;if (parameterObject == null) {paramMap = new HashMap<>();} else if (parameterObject instanceof Map) {//解決不可變Map的情況paramMap = new HashMap<>();paramMap.putAll((Map) parameterObject);} else {paramMap = new HashMap<>();// sqlSource為ProviderSqlSource時,處理只有1個參數的情況if (ms.getSqlSource() instanceof ProviderSqlSource) {String[] providerMethodArgumentNames = ExecutorUtil.getProviderMethodArgumentNames((ProviderSqlSource) ms.getSqlSource());if (providerMethodArgumentNames != null && providerMethodArgumentNames.length == 1) {paramMap.put(providerMethodArgumentNames[0], parameterObject);paramMap.put("param1", parameterObject);}}//動態sql時的判斷條件不會出現在ParameterMapping中,但是必須有,所以這里需要收集所有的getter屬性//TypeHandlerRegistry可以直接處理的會作為一個直接使用的對象進行處理boolean hasTypeHandler = ms.getConfiguration().getTypeHandlerRegistry().hasTypeHandler(parameterObject.getClass());MetaObject metaObject = MetaObjectUtil.forObject(parameterObject);//需要針對注解形式的MyProviderSqlSource保存原值if (!hasTypeHandler) {for (String name : metaObject.getGetterNames()) {paramMap.put(name, metaObject.getValue(name));}}//下面這段方法,主要解決一個常見類型的參數時的問題if (boundSql.getParameterMappings() != null && boundSql.getParameterMappings().size() > 0) {for (ParameterMapping parameterMapping : boundSql.getParameterMappings()) {String name = parameterMapping.getProperty();if (!name.equals(GLOBALPERIOD)&& paramMap.get(name) == null) {if (hasTypeHandler|| parameterMapping.getJavaType().equals(parameterObject.getClass())) {paramMap.put(name, parameterObject);break;}}}}}return processPageParameter(ms, paramMap, boundSql, pageKey, paramIndex);}private final static String GLOBALPERIOD = "globalPeriod";public Object processPageParameter(MappedStatement ms, Map<String, Object> paramMap, BoundSql boundSql, CacheKey pageKey, ArrayList<Integer> paramIndex) {paramMap.put(GLOBALPERIOD, getPeriod());//處理pageKeypageKey.update(getPeriod());//處理參數配置handleParameter(boundSql, ms, paramIndex);return paramMap;}protected void handleParameter(BoundSql boundSql, MappedStatement ms, ArrayList<Integer> paramIndex) {if (boundSql.getParameterMappings() != null) {List<ParameterMapping> newParameterMappings = new ArrayList<>(boundSql.getParameterMappings());for (Integer index : paramIndex) {if(index < newParameterMappings.size()) {newParameterMappings.add(index, new ParameterMapping.Builder(ms.getConfiguration(), GLOBALPERIOD, String.class).build());}else{newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), GLOBALPERIOD, String.class).build());}}MetaObject metaObject = MetaObjectUtil.forObject(boundSql);metaObject.setValue("parameterMappings", newParameterMappings);}}private final static String Q = "Q";private final static String H = "H";private String getPeriod(){//使用threadlocal保存從request中獲取的參數,此處不再描述String period = PeriodHolder.getPeriod();if(NumberUtil.isNumber(period)){return period;}else if(period.contains(Q)){return period.substring(0, 4) + Integer.parseInt(period.substring(5)) * 3;}else if(period.contains(H)){return period.substring(0, 4) + Integer.parseInt(period.substring(5)) * 6;}else{throw new ServiceException("非法期間:" + period);}}@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) {//nothing to do...} }
2、AutoConfiguration代碼實現
package org.cnbi.project.autoconfig;import com.github.pagehelper.autoconfigure.PageHelperAutoConfiguration; import org.apache.ibatis.session.SqlSessionFactory; import org.cnbi.project.other.sql.intercept.ParamInterceptor; import org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.context.annotation.Configuration;import javax.annotation.PostConstruct; import java.util.Iterator; import java.util.List;/*** @ClassName ParamIntecepterAutoConfiguration* @Description* @Author Wangjunkai* @Date 2019/10/23 15:41**/ @AutoConfigureAfter({MybatisAutoConfiguration.class, PageHelperAutoConfiguration.class}) @Configuration public class ParamIntecepterAutoConfiguration {@Autowiredprivate List<SqlSessionFactory> sqlSessionFactoryList;public ParamIntecepterAutoConfiguration() {}@PostConstructpublic void addParamInterceptor() {ParamInterceptor interceptor = new ParamInterceptor();Iterator var3 = this.sqlSessionFactoryList.iterator();while(var3.hasNext()) {SqlSessionFactory sqlSessionFactory = (SqlSessionFactory)var3.next();sqlSessionFactory.getConfiguration().addInterceptor(interceptor);}} }

博主個人微信:

總結

以上是生活随笔為你收集整理的使用mybatis的interceptor修改执行sql以及传入参数的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。