spring boot+mybatis查询结果为map的时候将key转换为驼峰形式方法

本文详细解析了在SpringBoot+MyBatis项目中,如何自定义MapWrapper以实现Map集合返回结果的key值从下划线命名转换为驼峰命名,解决了官方map-underscore-to-camel-case配置仅对实体bean生效的问题。

        前言:项目使用springboot+mybatis搭建,在一些联表查询中使用了Map集合来接收结果,不过发现返回的结果中key都是和数据库列名一样:带有下划线很不方便,记得官方文档上有个驼峰转换的配置 map-underscore-to-camel-case , 于是想当然的以为加上就ok了,测试后发现接收为对象实体的时候确实是可以转换为驼峰形式,但是map集合还是不起作用。

        于是想到从源码入手,先理清 map-underscore-to-camel-case是怎么运行的,首先在配置文件中增加如上配置,然后点击进入源码发现mybatis将配置文件中的值读取赋值给自己的属性mapUnderscoreToCamelCase

        然后点击属性mapUnderscoreToCamelCase,查看有哪些地方进行了引用,发现有个DefaultResultSetHandler.java调用MetaObject中findProperty方法使用到了这个属性:

       接着点击 findProperty 方法,发现 ObjectWrapper 是一个接口,这样我们就需要查看是哪个类进行了实现,通过 debug 发现是MapWrapper BeanWrapper 两个类进行了实现,前者没有做任何处理直接返回了name后者判断如果配置为true的话将返回的列名toUppercase后和通过反射获得的对象属性进行比对,如果比对上了就返回属性名(这也就解释了为什么结果为实体bean的时候会进行转换,map没有转换的原因):

BeanWrapper.java
@Override
  public String findProperty(String name, boolean useCamelCaseMapping) {
    return metaClass.findProperty(name, useCamelCaseMapping);
  }

MetaClass.java
public String findProperty(String name, boolean useCamelCaseMapping) {
    if (useCamelCaseMapping) {
      name = name.replace("_", "");
    }
    return findProperty(name);
  }

public String findProperty(String name) {
    StringBuilder prop = buildProperty(name, new StringBuilder());
    return prop.length() > 0 ? prop.toString() : null;
  }
private StringBuilder buildProperty(String name, StringBuilder builder) {
    PropertyTokenizer prop = new PropertyTokenizer(name);
    if (prop.hasNext()) {
      String propertyName = reflector.findPropertyName(prop.getName());
      if (propertyName != null) {
        builder.append(propertyName);
        builder.append(".");
        MetaClass metaProp = metaClassForProperty(propertyName);
        metaProp.buildProperty(prop.getChildren(), builder);
      }
    } else {
      String propertyName = reflector.findPropertyName(name);
      if (propertyName != null) {
        builder.append(propertyName);
      }
    }
    return builder;
  }

Reflector.java
/**
 *在初始化Reflector的时候根据反射机制将指定class的所有属性获取并全部转成大写保存到下面的caseInsensitivePropertyMap集合里,这里进行get操作并返回
 */
public String findPropertyName(String name) {
    return caseInsensitivePropertyMap.get(name.toUpperCase(Locale.ENGLISH));
  }

        看到这里已经很清楚怎么改了:

        1、我们需要自定义 wrappe r继承 MapWrapper 类并重写它的 findProperty 方法,通过userCamelCaseMapping参数判断是否需要进行驼峰处理。

package com.sailing.yjbj.config.wrapper;

import com.google.common.base.CaseFormat;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.wrapper.MapWrapper;

import java.util.Map;

/**
 * @author baibing
 * @project: iemp-yjbj
 * @package: com.sailing.yjbj.config.wrapper
 * @Description: 自定义wrapper处理spring boot + mybatis返回结果为map时的key值转换为驼峰
 * @date 2018/11/1 11:34
 */
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){
            return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL,name);
        }
        return name;
    }
}

        2、同时也要实现 ObjectWrapperFactory 工厂接口,判断如果所传对象为Map类型的时候,才将自定义的 wrapper 处理器返回并使用。

package com.sailing.yjbj.config.wrapper;

import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.wrapper.ObjectWrapper;
import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;

import java.util.Map;

/**
 * @author baibing
 * @project: iemp-yjbj
 * @package: com.sailing.yjbj.config.wrapper
 * @Description: 实现接口 ObjectWrapperFactory,通过包装工厂来创建自定义的wrapper
 * @date 2018/11/1 11:38
 */
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、最后需要替换原来默认的实现,mybaits文档上告诉了我们怎么做,返回一个 ConfigurationCustomizer ,通过匿名内部类将自己的实现工厂set进去即可:

package com.sailing.yjbj.config;

import com.sailing.yjbj.config.wrapper.MapWrapperFactory;
import org.mybatis.spring.boot.autoconfigure.ConfigurationCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author baibing
 * @project: iemp-yjbj
 * @package: com.sailing.yjbj.config
 * @Description: mybatis配置类,将自定义的MapWrapperFactory覆盖默认的ObjectWrapperFactory
 * @date 2018/11/1 11:42
 */
@Configuration
public class MybatisConfig {

    @Bean
    public ConfigurationCustomizer mybatisConfigurationCustomizer(){
        System.out.println("initiazing ConfigurationCustomizer....");
        return new ConfigurationCustomizer() {
            @Override
            public void customize(org.apache.ibatis.session.Configuration configuration) {
                configuration.setObjectWrapperFactory(new MapWrapperFactory());
            }
        };
    }
}

        4、驼峰转换的时候使用了google的guava库,maven依赖为:

<!-- 引用的 guava库,里面有转换驼峰的-->
		<dependency>
			<groupId>com.google.guava</groupId>
			<artifactId>guava</artifactId>
			<version>24.1-jre</version>
		</dependency>

        最后:通过测试返回的 Map 的时候成功进行了驼峰处理~~~~

项目下载地址:https://download.youkuaiyun.com/download/white_ice/10778916

因csdn后台会自动修改积分,导致现在积分较高,可以去下面地址免费下载:https://github.com/KingOfMonkey/springboot-mybatis ,喜欢的给个star。

<think>我们被要求整合Spring Boot + MyBatis + Swagger。这是一个常见的Java Web开发技术栈组合。 我们将创建一个简单的Spring Boot项目,集成MyBatis(用于数据访问)和Swagger(用于API文档)。 步骤如下: 1. 创建Spring Boot项目 2. 添加相关依赖(Spring Boot, MyBatis, Swagger, 数据库驱动等) 3. 配置数据源和MyBatis 4. 创建实体类、Mapper接口和Mapper XML文件 5. 创建Service和Controller 6. 配置Swagger 7. 运行并测试 下面我们逐步实现: 步骤1:创建Spring Boot项目 可以使用Spring Initializr(https://start.spring.io/)创建一个基础的Spring Boot项目,选择以下依赖: - Spring Web - MyBatis Framework - MySQL Driver (这里以MySQL为例,也可以选择其他数据库) 步骤2:添加Swagger依赖 在pom.xml中添加Swagger相关依赖(这里使用Swagger2): ```xml <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.9.2</version> </dependency> ``` 步骤3:配置数据源和MyBatis 在application.properties(或application.yml)中配置数据源和MyBatis: ```properties # 数据源配置 spring.datasource.url=jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC spring.datasource.username=root spring.datasource.password=123456 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver # MyBatis配置 # 指定Mapper.xml文件位置 mybatis.mapper-locations=classpath:mapper/*.xml # 指定实体类所在的包 mybatis.type-aliases-package=com.example.demo.entity ``` 步骤4:创建实体类、Mapper接口和Mapper XML文件 假设我们有一个User实体类: 实体类:User.java ```java package com.example.demo.entity; public class User { private Long id; private String name; private Integer age; // 省略getter和setter } ``` Mapper接口:UserMapper.java ```java package com.example.demo.mapper; import com.example.demo.entity.User; import org.apache.ibatis.annotations.Mapper; import java.util.List; @Mapper public interface UserMapper { List<User> findAll(); } ``` Mapper XML文件:在resources/mapper目录下创建UserMapper.xml ```xml <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.example.demo.mapper.UserMapper"> <select id="findAll" resultType="User"> select * from user </select> </mapper> ``` 步骤5:创建Service和Controller Service接口:UserService.java ```java package com.example.demo.service; import com.example.demo.entity.User; import java.util.List; public interface UserService { List<User> findAll(); } ``` Service实现:UserServiceImpl.java ```java package com.example.demo.service.impl; import com.example.demo.entity.User; import com.example.demo.mapper.UserMapper; import com.example.demo.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Override public List<User> findAll() { return userMapper.findAll(); } } ``` Controller:UserController.java ```java package com.example.demo.controller; import com.example.demo.entity.User; import com.example.demo.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController @RequestMapping("/user") public class UserController { @Autowired private UserService userService; @GetMapping("/list") public List<User> list() { return userService.findAll(); } } ``` 步骤6:配置Swagger 创建Swagger配置类:SwaggerConfig.java ```java package com.example.demo.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.service.ApiInfo; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; @Configuration @EnableSwagger2 public class SwaggerConfig { @Bean public Docket createRestApi() { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("com.example.demo.controller")) // 指定controller存放的目录 .paths(PathSelectors.any()) .build(); } private ApiInfo apiInfo() { return new ApiInfoBuilder() .title("Spring Boot整合Swagger") .description("Spring Boot整合Swagger,详细信息......") .version("1.0.0") .build(); } } ``` 步骤7:运行并测试 启动Spring Boot应用,访问Swagger UI:http://localhost:8080/swagger-ui.html 注意:确保数据库中有user表,并且有数据。 以上就是一个简单的Spring Boot + MyBatis + Swagger的整合示例。 但是,请注意,在实际开发中,我们可能还需要考虑事务管理、异常处理、日志、分页等。这里只是一个最基础的整合。 相关问题: 1. 如何配置MyBatis驼峰命名转换? 2. 如何在Spring Boot中配置多数据源? 3. 如何对Swagger进行安全配置(比如添加登录认证)? 4. 如何整合MyBatis-Plus来简化MyBatis的开发? </think> 以下是一个完整的Spring Boot + MyBatis + Swagger整合方案,包含详细代码和解释: ### 解决方案 我们将创建一个简单的用户管理系统,包含以下模块: 1. Spring Boot基础框架 2. MyBatis操作MySQL数据库 3. Swagger生成API文档 4. RESTful接口示例 --- ### 1. 项目结构 ``` src ├── main │ ├── java │ │ └── com │ │ └── example │ │ └── demo │ │ ├── config │ │ │ └── SwaggerConfig.java │ │ ├── controller │ │ │ └── UserController.java │ │ ├── entity │ │ │ └── User.java │ │ ├── mapper │ │ │ └── UserMapper.java │ │ ├── service │ │ │ ├── UserService.java │ │ │ └── impl │ │ │ └── UserServiceImpl.java │ │ └── DemoApplication.java │ └── resources │ ├── mapper │ │ └── UserMapper.xml │ ├── application.yml │ └── schema.sql ``` --- ### 2. 核心代码实现 #### 依赖 (`pom.xml`) ```xml <dependencies> <!-- Spring Boot Starter --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- MyBatis + MySQL --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.0</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <!-- Swagger --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>3.0.0</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>3.0.0</version> </dependency> <!-- Lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies> ``` #### 配置文件 (`application.yml`) ```yaml server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/demo_db?useSSL=false&serverTimezone=UTC username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver mybatis: mapper-locations: classpath:mapper/*.xml # MyBatis映射文件位置 configuration: map-underscore-to-camel-case: true # 自动驼峰命名转换 # 初始化数据库脚本 spring.sql.init.mode: always ``` #### 数据库初始化 (`schema.sql`) ```sql CREATE TABLE IF NOT EXISTS users ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50) NOT NULL, email VARCHAR(50) NOT NULL UNIQUE, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); INSERT INTO users (name, email) VALUES ('张三', 'zhangsan@example.com'), ('李四', 'lisi@example.com'); ``` #### 实体类 (`User.java`) ```java package com.example.demo.entity; import lombok.Data; import java.time.LocalDateTime; @Data public class User { private Integer id; private String name; private String email; private LocalDateTime createdAt; } ``` #### Mapper接口 (`UserMapper.java`) ```java package com.example.demo.mapper; import com.example.demo.entity.User; import org.apache.ibatis.annotations.*; import java.util.List; @Mapper public interface UserMapper { @Select("SELECT * FROM users") List<User> findAll(); @Insert("INSERT INTO users(name, email) VALUES(#{name}, #{email})") @Options(useGeneratedKeys = true, keyProperty = "id") int insert(User user); @Delete("DELETE FROM users WHERE id = #{id}") int deleteById(Integer id); } ``` #### Service层 (`UserService.java` 和 `UserServiceImpl.java`) ```java // UserService.java package com.example.demo.service; import com.example.demo.entity.User; import java.util.List; public interface UserService { List<User> getAllUsers(); void createUser(User user); void deleteUser(Integer id); } // UserServiceImpl.java package com.example.demo.service.impl; import com.example.demo.entity.User; import com.example.demo.mapper.UserMapper; import com.example.demo.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Override public List<User> getAllUsers() { return userMapper.findAll(); } @Override public void createUser(User user) { userMapper.insert(user); } @Override public void deleteUser(Integer id) { userMapper.deleteById(id); } } ``` #### Controller (`UserController.java`) ```java package com.example.demo.controller; import com.example.demo.entity.User; import com.example.demo.service.UserService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.List; @RestController @RequestMapping("/api/users") @Api(tags = "用户管理接口") public class UserController { @Autowired private UserService userService; @GetMapping @ApiOperation("获取所有用户") public List<User> getAllUsers() { return userService.getAllUsers(); } @PostMapping @ApiOperation("创建新用户") public void createUser(@RequestBody User user) { userService.createUser(user); } @DeleteMapping("/{id}") @ApiOperation("删除用户") public void deleteUser(@PathVariable Integer id) { userService.deleteUser(id); } } ``` #### Swagger配置 (`SwaggerConfig.java`) ```java package com.example.demo.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.service.ApiInfo; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; @Configuration public class SwaggerConfig { @Bean public Docket api() { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("com.example.demo.controller")) .paths(PathSelectors.any()) .build(); } private ApiInfo apiInfo() { return new ApiInfoBuilder() .title("用户管理系统API文档") .description("Spring Boot整合MyBatis和Swagger示例") .version("1.0.0") .build(); } } ``` #### 主启动类 (`DemoApplication.java`) ```java package com.example.demo; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @MapperScan("com.example.demo.mapper") // 扫描Mapper接口 public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ``` --- ### 3. 功能验证 1. 启动应用:运行 `DemoApplication` 2. 访问Swagger UI:`http://localhost:8080/swagger-ui/` 3. 测试接口: - GET `/api/users` 获取用户列表 - POST `/api/users` 创建用户 - DELETE `/api/users/{id}` 删除用户 --- ### 4. 关键点解释 1. **MyBatis集成**: - `@MapperScan` 自动扫描Mapper接口 - `mapper-locations` 配置XML映射文件路径 - 驼峰命名自动转换简化字段映射 2. **Swagger配置**: - `@Api`标注控制器分类 - `@ApiOperation`标注接口功能 - 访问路径 `/swagger-ui/` 3. **RESTful设计**: - 使用标准HTTP方法 (GET/POST/DELETE) - 资源化URL设计 (`/api/users`) --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值