问题来源:
开发时是mysql的库,要上线了!!!领导说换oracle!!!!
一堆老代码,还有各种select *,页面全是硬编码字段key,都是小写的!!!换了oracle后返回的字段key全部变成了大写,页面取不到值
博客一搜大部分是在sql中加别名解决,如果有时间。。。我也不想改!!!
解决办法:
自定义mybatis拦截器,拦截 ResultSetHandler 中的 handleResultSets 方法,对返回类型判断,如果是Map,并且key全部是大写,简单粗暴的全部转为小写。
上代码:
MyBatisInterceptor.java 自定义的Mybatis拦截器,相关教程可以百度
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.executor.resultset.DefaultResultSetHandler;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.ReflectorFactory;
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
import org.apache.ibatis.reflection.factory.ObjectFactory;
import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
import org.apache.ibatis.session.RowBounds;
import java.sql.Statement;
import java.util.*;
/**
* @ClassName MyBatisInterceptor
*
* @Author xhh
* @Date 2020/8/13
* @Version V1.0
**/
@Slf4j
@Intercepts(
{@Signature(
type = ResultSetHandler.class,
method = "handleResultSets",
args = {Statement.class}
)})
public class MyBatisInterceptor implements Interceptor {
private static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();
private static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();
private static final ReflectorFactory REFLECTOR_FACTORY = new DefaultReflectorFactory();
private String MAP = "java.util.Map";
private String HASH_MAP = "java.util.HashMap";
private String LINKED_HASH_MAP = "java.util.LinkedHashMap";
@Override
public Object intercept(Invocation invocation) throws Throwable {
ResultSetHandler resultSetHandler = (ResultSetHandler) invocation.getTarget();
//defaultResultSetHandler.getMappedStatement
MetaObject metaResultSetHandler = MetaObject.forObject(resultSetHandler, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY, REFLECTOR_FACTORY);
MappedStatement mappedStatement = (MappedStatement) metaResultSetHandler.getValue("mappedStatement");
Object proceed = invocation.proceed();
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
int size = resultMaps.size();
String resultMapTypeName = resultMaps.get(0).getType().getName();
// 判断了 三个Map类型 有各种各样的返回类型
if(size > 0
&& (
StringUtils.equalsIgnoreCase(MAP,resultMapTypeName)
|| StringUtils.equalsIgnoreCase(HASH_MAP,resultMapTypeName)
|| StringUtils.equalsIgnoreCase(LINKED_HASH_MAP,resultMapTypeName)
)){
if(proceed instanceof List){
List<Map<String,Object>> list = (List<Map<String, Object>>) proceed;
if(null != list && list.size()>0){
list.forEach(t->{
Map<String,Object> temp = new HashMap<>();
// 判断 key 是否全为大写字母
// 如果全部为大写 转为小写 加入到结果中
for(Map.Entry<String,Object> entry:t.entrySet()) {
if(StrUtil.isUpperCase(entry.getKey())){
temp.put(entry.getKey().toLowerCase(),entry.getValue());
}
}
t.putAll(temp);
});
}
}
}
return proceed;
}
@Override
public Object plugin(Object target) {
// 读取@Signature中的配置,判断是否需要生成代理类
if (target instanceof ResultSetHandler) {
return Plugin.wrap(target, this);
} else {
return target;
}
}
@Override
public void setProperties(Properties properties) {
}
}
MybatisConfiguration.java 配置类 注册mybatis拦截器,在springboot中可以这么写,还有其他注册方法,比如写配置文件
import com.ai.res.common.interceptor.MyBatisInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Properties;
/**
* @ClassName MybatisConfiguration
* @Description: TODO
* @Author xhh
* @Date 2020/8/13
* @Version V1.0
**/
@Configuration
public class MybatisConfiguration {
/**
* 注册拦截器
*/
@Bean
public MyBatisInterceptor mybatisInterceptor() {
MyBatisInterceptor interceptor = new MyBatisInterceptor();
// Properties properties = new Properties();
// 可以调用properties.setProperty方法来给拦截器设置一些自定义参数
// interceptor.setProperties(properties);
return interceptor;
}
}
拦截器中结果的判断对多种Map类型进行了判断,对Map中的key做了判断转换后原来的key也放在里面,目前良好运行大半年,暂时没有发现发问题,记录一下!