SpringBoot整合MapStruct对象转换
前言
在项目中我们经常会进行类与类之间相互的转换,DO转VO、VO转DO等。
关于这类转换工具有很多,我一般使用的是Hutool的Bean转换工具进行转换,spring也自带了转换工具,但是相对来说效率不是很高。因为他们或多或少都是基于反射去创建的,多少对效率有些影响。
性能对比博客:https://blog.csdn.net/u014374173/article/details/121117186
为什么使用MapStruct?
MapStrct在编译的时候会自动生成映射,get、set,基于最原始的赋值方式。
整合
引入maven依赖以及插件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
| <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.3.0</version> <relativePath/> </parent> <groupId>cc.staro</groupId> <artifactId>spring-mapStruct</artifactId> <version>0.0.1-SNAPSHOT</version> <name>spring-mapStruct</name> <description>spring-mapStruct</description> <properties> <java.version>17</java.version> <mapstruct.version>1.5.5.Final</mapstruct.version> <lombok-mapstruct-binding.version>0.2.0</lombok-mapstruct-binding.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct</artifactId> <version>${mapstruct.version}</version> </dependency> </dependencies>
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>${maven-compiler-plugin.version}</version> <configuration> <source>${java.version}</source> <target>${java.version}</target> <annotationProcessorPaths> <path> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-processor</artifactId> <version>${mapstruct.version}</version> </path> <path> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> </path> <path> <groupId>org.projectlombok</groupId> <artifactId>lombok-mapstruct-binding</artifactId> <version>${lombok-mapstruct-binding.version}</version> </path> </annotationProcessorPaths> </configuration> </plugin> </plugins> </build> </project>
|
下列几乎大部分都会转换为他,所以给他单独提取出来
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
|
@Data public class UserEntity {
private Long id;
private String name;
private Integer age;
private String address;
private String password;
private String email;
private List<Role> roles;
private Map<String, String> permissions; }
|
基本映射
我们会创建一个UserDTO对象与userEntity进行转换。为了方便起见,它们的属性字段都使用相同的名称:
1 2 3 4 5 6 7 8 9 10 11
| @Data public class UserDTO {
private String name;
private String password; }
|
Controller
1 2 3 4 5 6 7 8 9 10 11 12
|
@GetMapping("/mapStruct1") public String demo1(@RequestBody UserDTO userDTO){ System.out.println(userDTO); UserEntity userEntity = UserConvert.INSTANCE.convert(userDTO); System.out.println(userEntity); return "1、基本映射转换"; }
|
UserConvert
1 2 3 4 5 6 7 8 9 10 11
| @Mapper public interface UserConvert { UserConvert INSTANCE = Mappers.getMapper(UserConvert.class);
UserEntity convert(UserDTO userDTO); }
|
不同字段间映射
MapStruct通过@Mapping注解对这类情况提供了支持。
Controller
1 2 3 4 5 6 7 8 9 10 11 12
|
@GetMapping("/mapStruct2") public String demo2(@RequestBody UserEntity userEntity){ System.out.println(userEntity); UserVO userVO = UserConvert.INSTANCE.convert(userEntity); System.out.println(userVO); return "2、不同字段映射"; }
|
UserConvert
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
@Mappings({ @Mapping(source = "name", target = "nikeName") }) UserVO convert(UserEntity userEntity);
@Mapping(source = "name", target = "nikeName") UserVO convert(UserEntity userEntity);
|
UserVo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| @Data public class UserVO {
private String nikeName;
private Integer age;
private String address;
private String createTime;
private String email;
private List<Role> roles; }
|
多个源类
@MappingTarget指需要进行合并的目标值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
@GetMapping("/mapStruct3") public String demo3(@RequestBody UserDTO userDTO) { UserVO userVO = new UserVO(); System.out.println(userDTO + "--" + userVO); System.out.println("-------------1转换-----------"); UserEntity userEntity = UserConvert.INSTANCE.convert(userDTO, userVO); System.out.println(userEntity); System.out.println("-------------2合并-----------"); System.out.println(userDTO + "--" + userVO); UserConvert.INSTANCE.convertMerge(userDTO,userVO); System.out.println("合并后:"+userVO); return "3、多个源类"; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
UserEntity convert(UserDTO userDTO, UserVO userVO);
@Mapping(source = "name", target = "nikeName") @Mapping(source = "password", target = "address") void convertMerge(UserDTO userDTO,@MappingTarget UserVO userVO);
|
子对象映射
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
|
@GetMapping("/mapStruct4") public String demo4() { UserEntity userEntity = DemoController.mockUserEntity(); System.out.println(userEntity); UserVO userVO = UserConvert.INSTANCE.convert4(userEntity); System.out.println(userVO); System.out.println("---------自定义--------"); System.out.println(userEntity); UserVO userVO2 = UserConvert.INSTANCE.convert4Custom(userEntity); System.out.println(userVO2); return "4、子对象映射"; }
private static UserEntity mockUserEntity() { UserEntity userEntity = new UserEntity(); userEntity.setName("star"); userEntity.setAge(18); userEntity.setAddress("中国"); userEntity.setEmail("232@qq.com"); userEntity.setPassword("123456"); userEntity.setId(1); userEntity.setRoles(new ArrayList<>() {{ add(new Role(1, "管理员1", "这是一个管理员1")); add(new Role(2, "管理2员", "这是一个管理员2")); }}); return userEntity; }
|
1 2 3 4 5 6
| @Data @AllArgsConstructor public class RoleDTO { private Integer id; private String name; }
|
1 2 3 4 5 6 7
| @Data @AllArgsConstructor public class Role { private Integer id; private String name; private String description; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
UserVO convert4(UserEntity userEntity);
RoleDTO convert4(Role role);
@Mapping(source = "userEntity.roles", target = "roles",qualifiedByName ="convert4Custom" ) UserVO convert4Custom(UserEntity userEntity);
@Named("convert4Custom") default RoleDTO convert4Custom(Role role){ return new RoleDTO(role.getId(),role.getName()+"自定义"); }
|
更新现有实例
具体参考多个源类
使用自定义映射方法
具体参考子对象映射
总结
上述就是一些常用的转换方式,集合等也是一样的转换方式,没有什么需要改变的,这里就不进行举例。
至于其他的可以参考下列文章
参考文章:MapStruct使用指南