mybatis Map查询结果下划线转驼峰的实例

 更新时间:2020年9月24日 16:39  点击:2763

添加一个配置类MybatisCamelConfig 即可

package com.fpi.notify.config;
 
import com.google.common.base.CaseFormat;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.wrapper.MapWrapper;
import org.apache.ibatis.reflection.wrapper.ObjectWrapper;
import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
import org.mybatis.spring.boot.autoconfigure.ConfigurationCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; 
import java.util.Map;
 
/**
 * mybatis查询Map返回值下划线转峰坨
 * @author xingxing_yuan
 * @since 2020-02-18 13:47
 */
@Configuration
public class MybatisCamelConfig {
 @Bean
 public ConfigurationCustomizer mybatisConfigurationCustomizer() {
//   使用自定义的解析器工厂
  return configuration -> configuration.setObjectWrapperFactory(new MapWrapperFactory());
 }
 
 /**
  * 实现工厂
  */
 static class MapWrapperFactory implements ObjectWrapperFactory {
  @Override
  public boolean hasWrapperFor(Object object) {
//  判断是Map就使用该解析
   return object instanceof Map;
  }
 
  @Override
  public ObjectWrapper getWrapperFor(MetaObject metaObject, Object object) {
//  将默认的解析器替换成峰坨转换
   return new CamelWrapper(metaObject, (Map) object);
  }
 }
 
 /**
  * 重写转换器;添加转换方法
  */
 static class CamelWrapper extends MapWrapper {
 
  CamelWrapper(MetaObject metaObject, Map<String, Object> map) {
   super(metaObject, map);
  }
 
  /**
   * mybatis查询结果下划线转峰坨
   *
   * @param name
   * @param useCamelCaseMapping 是否进行转换。yaml 中配置map-underscore-to-camel-case=true
   * @return
   */
  @Override
  public String findProperty(String name, boolean useCamelCaseMapping) {
   if (useCamelCaseMapping) {
//    使用guava的转换方法,覆盖Map的默认返回值
    return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, name);
   }
   return name;
  }
 
 }
}

补充知识:关于Springboot+Mybatis中返回结果集为Map时其内的Key转换为驼峰的命名(2种方法)

使用场景:

使用mybatis的时候,简单的连表查询,用Map接收的时候,都是像DB定义的字段一样,类似以下 student_name,student_id,没有转换为驼峰,但是又不能因为这一个定义一个javabean来映射数据库字段集合,这样,会有无穷无尽的javabean,完全不是办法。然后看了下mybatis-spring-boot的配置文档

http://www.mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/, 发现有这么个属性

mybatis.configuration.map-underscore-to-camel-case=true

看着属性意思,很像是 map 下划线转换为驼峰,然后我天真的以为,加个这个,就会将Map里面的key转换为驼峰的命名方式, 总归是太天真了。没办法,接着找了了一下,发现官方文档http://www.mybatis.org/mybatis-3/configuration.html#properties, 描述过这个的作用, 如下

才发现,这个属性的作用,是作用于javabean的field的,并不是map。既然 map-underscore-to-camel-case 不能作用于map,那么只能自己动手了,然后就想到了2个解决方案:

继承HashMap,重写Put函数,将mybatis返回的Map,写上自定义Map的路径,自定义的Map,将所有的key内部转换为驼峰表达式

找到mybatis的Handler,通过Handler来找到转换映射关系的接口定义,继承或者实现接口,然后走自定义的转换规则来实现Map映射的驼峰转换

最终决定,采用第二种,方便以后扩展

下面是使用第二种的两种在项目中的具体实现

第一种实现方法:

首先,我开始找mybatis的configuration里面的mapUnderscoreToCamelCase属性调用的地方

有两个地方调用了,然后我们看第一个调用的地方,发现名称是createAutomaticMappings,应该是map的映射字段创建,如下代码,光标显示的地方,就是调用的地方

然后我们在查看属性传递进去后的操作,点进 metaObject.findProperty的实现

接着在看,objectWrapper.findProperty,发现是个接口,然后我们需要查看,是对应的哪个实现,然后我debug发现是 MapWrapper的实现,并没有做任何操作,直接返回了name。

到这里,我们可以看下源码的目录结构,发现了以下

心里大概明白怎么回事了,具体过程应该如下

通过接口ObjectWrapper来定义行为,有默认的一些实现,然后通过工厂ObjectWrapperFactory接口,来创建ObjectWrapper接口,最后来进行对方的自动映射跟包装,至此,心里已经想到怎么改动了

1.首先,我们先继承类 MapWrapper,重写findProperty,通过useCamelCaseMapping来判断是否开启使用驼峰。

public class CustomWrapper extends MapWrapper{
 
 public CustomWrapper(MetaObject metaObject, Map<String, Object> map) {
 super(metaObject, map);
 }
 
 @Override
 public String findProperty(String name, boolean useCamelCaseMapping) {
 if(useCamelCaseMapping){
   //CaseFormat是引用的 guava库,里面有转换驼峰的,免得自己重复造轮子,pom添加
   /**
    **   <dependency>
       <groupId>com.google.guava</groupId>
       <artifactId>guava</artifactId>
       <version>24.1-jre</version>
       </dependency>
    **/
 return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL,name);
 }
 return name;
 }
}

2. 然后,我们在实现接口 ObjectWrapperFactory,通过包装工厂来创建自定义的包装类,通过hasWrapperFor判断参数不为空,并且类型是Map的时候才使用自己扩展的ObjectWrapper。

public class MapWrapperFactory implements ObjectWrapperFactory {
 @Override
 public boolean hasWrapperFor(Object object) {
 return object != null && object instanceof Map;
 }
 @Override
 public ObjectWrapper getWrapperFor(MetaObject metaObject, Object object) {
 return new CustomWrapper(metaObject,(Map)object);
 }
}

3. 做完以上操作后,我们需要替换下,以前默认的实现,刚好,mybatis-spring-boot上面有告诉我们怎么做,返回一个 ConfigurationCustomizer 的bean,通过匿名内部类实现覆盖默认的MapWrapper的findProperty函数。

@Configuration
public class MybatisConfig {
 
 @Bean
 public ConfigurationCustomizer mybatisConfigurationCustomizer(){
 return new ConfigurationCustomizer() {
 @Override
 public void customize(org.apache.ibatis.session.Configuration configuration) {
 configuration.setObjectWrapperFactory(new MapWrapperFactory());
 }
 };
 }
}

做了以上操作后,我们就将默认的Map映射的包装类查找property的部分,变成了自己想要的样子;最后,我们在 properties或者yml里面加上 mybatis.configuration.map-underscore-to-camel-case=true ,毕竟在CustomerWrapper里面,我们是通过使用这个来控制是否转换驼峰的,最后写个测试用例跑一下,然后会发现,以前db的字段,下划线已经转换成驼峰命名了。

第二种实现方法:

这种方法就比较投机取巧了, 但是可以很简单的实现Map集合的映射,下面我们来具体看看实现过程。(PS: 推荐使用第一种方法吧, 比较官方!)

1.首先mybatis-3.4.5.jar中一个MapWrapper类, 现在我把这个MapWrapper类直接复制一份,然后创建相应的包, 这个包路径跟在jar包中的包路径完全一样的(位于根路径下的: ), 然后将复制的该MapWrapper文件直接粘贴至该包下, 那么这个就是我们自己的MapWrapper类。

2.对默认的Map映射的包装类查找property的findProperty方法进行改造,加入自己的映射转换规则, 当然也可以像第一种方法中一样: “引用的 guava库,里面有转换驼峰的,免得自己重复造轮子,pom添加依赖即可。” 这里我们自己尝试的实现, 代码如下:

@Override
 public String findProperty(String name, boolean useCamelCaseMapping) {
 if (useCamelCaseMapping
    && ((name.charAt(0) >= 'A' && name.charAt(0) <= 'Z')
     || name.indexOf("_") >= 0)) {
   return underlineToCamelhump(name);
  }
  return name;
 }
 private String underlineToCamelhump(String inputString) {
  StringBuilder sb = new StringBuilder();
  boolean nextUpperCase = false;
  for (int i = 0; i < inputString.length(); i++) {
   char c = inputString.charAt(i);
   if (c == '_') {
    if (sb.length() > 0) {
     nextUpperCase = true;
    }
   } else {
    if (nextUpperCase) {
     sb.append(Character.toUpperCase(c));
     nextUpperCase = false;
    } else {
     sb.append(Character.toLowerCase(c));
    }
   }
  }
  return sb.toString();
 }

做了以上操作后,我们就将默认的Map映射的包装类查找property的部分,变成了自己想要的样子;

最后, 我们同样在Mybatis配置文件中添加了如下配置:

毕竟在CustomerWrapper里面,我们是通过使用这个来控制是否转换驼峰的。

当然最主要可以这样实现的原因还是基于类加载机制允许的基础上的,了解过相应的类加载原理及加载顺序后我们可以知道:“位于WEB-INF目录下自定义的class类优先与该目录下的lib下jar包中的类加载; 同一个JVM里面,判断两个类是否相同的依据是类的全路径名称和类加载器名称是否完全相同。

但由于委派机制的存在,每个类只要在父类加载器哪里被找到,子类加载器就不会再尝试加载了,因此,同名的类只能被加载一次,这被称为单一原则。”

以上这篇mybatis Map查询结果下划线转驼峰的实例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持猪先飞。

[!--infotagslink--]

相关文章

  • Java8 实现stream将对象集合list中抽取属性集合转化为map或list

    这篇文章主要介绍了Java8 实现stream将对象集合list中抽取属性集合转化为map或list的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-05
  • Mybatis Plus select 实现只查询部分字段

    这篇文章主要介绍了Mybatis Plus select 实现只查询部分字段的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-09-01
  • 解决Mybatis 大数据量的批量insert问题

    这篇文章主要介绍了解决Mybatis 大数据量的批量insert问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-01-09
  • mybatis的Configuration详解

    这篇文章主要介绍了mybatis的Configuration详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-11-04
  • mybatis 返回Integer,Double,String等类型的数据操作

    这篇文章主要介绍了mybatis 返回Integer,Double,String等类型的数据操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-11-25
  • Oracle使用like查询时对下划线的处理方法

    这篇文章主要介绍了Oracle使用like查询时对下划线的处理方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-03-16
  • MyBatis-Plus的物理删除和逻辑删除(使用场景)

    数据库中的数据删除会分为两种:物理删除 和 逻辑删除,接下来通过本文给大家介绍MyBatis-Plus的物理删除和逻辑删除使用场景分析,感兴趣的朋友一起看看吧...2021-09-25
  • Springboot如何使用mybatis实现拦截SQL分页

    这篇文章主要介绍了Springboot使用mybatis实现拦截SQL分页,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-06-19
  • Mybatis执行update失败的解决

    这篇文章主要介绍了Mybatis执行update失败的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-09-01
  • Mybatis plus中使用in查询出错如何解决

    这篇文章主要介绍了Mybatis plus中使用in查询出错的问题及解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2020-08-06
  • 解决Mybatis中mapper.xml文件update,delete及insert返回值问题

    这篇文章主要介绍了解决Mybatis中mapper.xml文件update,delete及insert返回值问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-11-23
  • mybatis-plus雪花算法自动生成机器id原理及源码

    Mybatis-Plus是一个Mybatis的增强工具,它在Mybatis的基础上做了增强,却不做改变,Mybatis-Plus是为简化开发、提高开发效率而生,但它也提供了一些很有意思的插件,比如SQL性能监控、乐观锁、执行分析等,下面一起看看mybatis-plus雪花算法自动生成机器id原理解析...2021-06-04
  • C++如何删除map容器中指定值的元素详解

    map容器是C++ STL中的重要一员,删除map容器中value为指定元素的问题是我们经常与遇到的一个问题,下面这篇文章主要给大家介绍了关于利用C++如何删除map容器中指定值的元素的相关资料,需要的朋友可以参考借鉴,下面来一起看看吧。...2020-04-25
  • Mybatis用注解写in查询的实现

    这篇文章主要介绍了Mybatis用注解写in查询的实现方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-07-13
  • JavaScript WeakMap使用详解

    这篇文章主要介绍了JavaScript WeakMap使用的详细介绍,帮助大家更好的理解和使用JavaScript,感兴趣的朋友可以了解下...2021-02-06
  • java中JSONObject转换为HashMap(方法+main方法调用实例)

    这篇文章主要介绍了java中JSONObject转换为HashMap(方法+main方法调用实例),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-11-14
  • Mybatis和Mybatis-Plus时间范围查询方式

    这篇文章主要介绍了Mybatis和Mybatis-Plus时间范围查询方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-08-06
  • JavaScript中的数组遍历forEach()与map()方法以及兼容写法介绍

    下面小编就为大家带来一篇JavaScript中的数组遍历forEach()与map()方法以及兼容写法介绍。小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2016-05-20
  • 解决jmap命令打印JVM堆信息异常的问题

    这篇文章主要介绍了解决jmap命令打印JVM堆信息异常的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-12-04
  • Mybatis之Select Count(*)的获取返回int的值操作

    这篇文章主要介绍了Mybatis之Select Count(*)的获取返回int的值操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-11-23