使用场景(问题)
由于内部系统的使用,大量的需使用sql语句,现在sql太多的散落在各个xml文件中,不方便管理.
# 原理
这里使用到了mybatis的插件特性,就是当mybatis拿到用户的参数后,在要执行sql前,我们就主动去拿出我们的sql去替换要执行的sql。 主要实现的类:AutoSqlIntercepter,相关的说明可以参考: ``` ``` package com.taing;
import com.taing.autosql.sqlconfig.IAutoSqlDao; import com.taing.autosqlutils.ServiceConfig; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang3.reflect.FieldUtils; import org.apache.ibatis.executor.statement.StatementHandler; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.ParameterMapping; import org.apache.ibatis.plugin.Interceptor; 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.session.Configuration;
import java.sql.Connection; import java.util.List; import java.util.Map; import java.util.Properties;
/**
-
@Author tianyi
-
@Description mybatis的拦截类
-
@Date 2023 - 01 - 30 **/ @Intercepts(@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})) public class AutoSqlIntercepter implements Interceptor {
@Override public Object intercept(Invocation invocation) throws Throwable { StatementHandler target = (StatementHandler) invocation.getTarget(); String fieldDelegate = "delegate"; Object delegate = FieldUtils.readField(target, fieldDelegate, true); MappedStatement mappedStatement = (MappedStatement) FieldUtils.readField(delegate, "mappedStatement", true); String sqlId = mappedStatement.getId(); String packageName = "com.taing.autosql.sqlconfig.IAutosqlDao"; if (sqlId.contains(packageName)) { // 取出sql BoundSql boundSql = target.getBoundSql(); // 获得用户的参数 Map<String, Object> paramObject = (Map<String, Object>) boundSql.getParameterObject(); // get the method from the paramter, if you can't find it ,the show error String serviceConfigMethod = "methodName"; String method = (String) paramObject.get(serviceConfigMethod); if (null == method || method.trim().length() == 0) { throw new IllegalArgumentException("the paramter can't find the" + serviceConfigMethod);
} Configuration configuration = new Configuration(); ServiceConfig serviceConfig = new ServiceConfig(configuration, IAutoSqlDao.class); serviceConfig.parse(method); MappedStatement ms = configuration.getMappedStatement(sqlId); BoundSql newBoundSql = ms.getBoundSql(boundSql.getParameterObject()); List<ParameterMapping> parameterMetaDataList = newBoundSql.getParameterMappings(); String sql = newBoundSql.getSql(); FieldUtils.writeField(boundSql, "sql", sql, true); String fieldName = "additionalParameters"; Object parameter = FieldUtils.readField(newBoundSql, fieldName, true); Map<String, Object> additionalParamters = parameter instanceof Map<?, ?> ? (Map<String, Object>) parameter : null; if (additionalParamters != null) { for (Map.Entry<String, Object> paramItem : additionalParamters.entrySet()) { if (paramItem != null) { boundSql.setAdditionalParameter(paramItem.getKey(), paramItem.getValue()); MapUtils.putAll(paramObject, new Object[]{paramItem}); } } } FieldUtils.writeField(boundSql, "parameterMappings", parameterMetaDataList, true); } return invocation.proceed();}
@Override public Object plugin(Object target) { return Plugin.wrap(target, this); }
@Override public void setProperties(Properties properties) {
} }
使用说明
主要的接口如下,这里输入在数据库的定义的参数名称findAllUserInfo