mybatis JdbcTypeInterceptor - 运行时自动添加 jdbcType 属性

上代码:

package tk.mybatis.plugin;

import org.apache.ibatis.executor.ErrorContext;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.ParameterMode;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.scripting.defaults.DefaultParameterHandler;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;
import org.apache.ibatis.type.TypeHandlerRegistry; import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.PreparedStatement;
import java.util.*; /**
* JdbcTypeInterceptor - 运行时自动添加 jdbcType 属性
*/
@Intercepts({
@Signature(type = ParameterHandler.class, method = "setParameters", args = {PreparedStatement.class})
})
public class JdbcTypeInterceptor implements Interceptor { private static Set<String> methodSet = new HashSet<>();
private static Map<Class<?>, JdbcType> typeMap = new HashMap<>();
private static final Field mappedStatementField;
private static final Field boundSqlField; static {
try {
mappedStatementField = DefaultParameterHandler.class.getDeclaredField("mappedStatement");
mappedStatementField.setAccessible(true); } catch (NoSuchFieldException e) {
throw new RuntimeException("获取 DefaultParameterHandler 字段 mappedStatement 时出错", e);
}
try {
boundSqlField = DefaultParameterHandler.class.getDeclaredField("boundSql");
boundSqlField.setAccessible(true);
} catch (NoSuchFieldException e) {
throw new RuntimeException("获取 DefaultParameterHandler 字段 boundSql 时出错", e);
}
//设置默认的方法,是用 Mapper 所有方法
Method[] methods = tk.mybatis.mapper.common.Mapper.class.getMethods();
for (Method method : methods) {
methodSet.add(method.getName());
}
//设置默认的类型转换,参考 TypeHandlerRegistry
register(Boolean.class, JdbcType.BOOLEAN);
register(boolean.class, JdbcType.BOOLEAN); register(Byte.class, JdbcType.TINYINT);
register(byte.class, JdbcType.TINYINT); register(Short.class, JdbcType.SMALLINT);
register(short.class, JdbcType.SMALLINT); register(Integer.class, JdbcType.INTEGER);
register(int.class, JdbcType.INTEGER); register(Long.class, JdbcType.BIGINT);
register(long.class, JdbcType.BIGINT); register(Float.class, JdbcType.FLOAT);
register(float.class, JdbcType.FLOAT); register(Double.class, JdbcType.DOUBLE);
register(double.class, JdbcType.DOUBLE); register(String.class, JdbcType.VARCHAR); register(BigDecimal.class, JdbcType.DECIMAL);
register(BigInteger.class, JdbcType.DECIMAL); register(Byte[].class, JdbcType.BLOB);
register(byte[].class, JdbcType.BLOB); register(Date.class, JdbcType.DATE);
register(java.sql.Date.class, JdbcType.DATE);
register(java.sql.Time.class, JdbcType.TIME);
register(java.sql.Timestamp.class, JdbcType.TIMESTAMP); register(Character.class, JdbcType.CHAR);
register(char.class, JdbcType.CHAR);
} @Override
public Object intercept(Invocation invocation) throws Throwable {
//这里不考虑有多个基于该方法插件时的情况
Object handler = invocation.getTarget();
MappedStatement mappedStatement = (MappedStatement) mappedStatementField.get(handler);
//一旦配置了 methods,就只对配置的方法进行处理
if (handler instanceof DefaultParameterHandler) {
if (methodSet.size() > 0) {
String msId = mappedStatement.getId();
String methodName = msId.substring(msId.lastIndexOf(".") + 1);
if (!methodSet.contains(methodName)) {
return invocation.proceed();
}
}
//获取基本变量信息
BoundSql boundSql = (BoundSql) boundSqlField.get(handler);
Object parameterObject = ((DefaultParameterHandler) handler).getParameterObject();
Configuration configuration = mappedStatement.getConfiguration();
TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
PreparedStatement ps = (PreparedStatement) invocation.getArgs()[0];
//原 DefaultParameterHandler 逻辑
ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings != null) {
for (int i = 0; i < parameterMappings.size(); i++) {
ParameterMapping parameterMapping = parameterMappings.get(i);
if (parameterMapping.getMode() != ParameterMode.OUT) {
Object value;
String propertyName = parameterMapping.getProperty();
if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
value = boundSql.getAdditionalParameter(propertyName);
} else if (parameterObject == null) {
value = null;
} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
} else {
MetaObject metaObject = configuration.newMetaObject(parameterObject);
value = metaObject.getValue(propertyName);
}
TypeHandler typeHandler = parameterMapping.getTypeHandler();
JdbcType jdbcType = parameterMapping.getJdbcType();
if (value == null && jdbcType == null) {
if (parameterMapping.getJavaType() != null && typeMap.containsKey(parameterMapping.getJavaType())) {
jdbcType = typeMap.get(parameterMapping.getJavaType());
} else {
jdbcType = configuration.getJdbcTypeForNull();
}
}
typeHandler.setParameter(ps, i + 1, value, jdbcType);
}
}
}
return null;
}
return invocation.proceed();
} @Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
} private boolean isNotEmpty(String str) {
return str != null && str.length() > 0;
} @Override
public void setProperties(Properties properties) {
String methodStr = properties.getProperty("methods");
if (isNotEmpty(methodStr)) {
//处理所有方法
if (methodStr.equalsIgnoreCase("ALL")) {
methodSet.clear();
} else {
String[] methods = methodStr.split(",");
for (String method : methods) {
methodSet.add(method);
}
}
}
//手动配置
String typeMapStr = properties.getProperty("typeMaps");
if (isNotEmpty(typeMapStr)) {
String[] typeMaps = typeMapStr.split(",");
for (String typeMap : typeMaps) {
String[] kvs = typeMap.split(":");
if (kvs.length == 2) {
register(kvs[0], kvs[1]);
}
}
}
} public static void register(String type, String jdbcType) {
try {
typeMap.put(Class.forName(type), JdbcType.valueOf(jdbcType));
} catch (ClassNotFoundException e) {
throw new RuntimeException("配置 typeMaps 时出错!", e);
}
} public static void register(Class<?> type, JdbcType jdbcType) {
typeMap.put(type, jdbcType);
}
}

在springboot中使用:

    @Bean
public Interceptor getInterceptor(){
return new JdbcTypeInterceptor();
}

它的好处,就是在运行mybatis动态sql的时候给属性添加jdbcType

mybatis jdbctype参考:https://www.cnblogs.com/pianai-shu/p/6349183.html

上一篇:毕业N年后,请不要像我一样被档案烦死


下一篇:scroll tabs