Java 实体映射工具 MapStruct

逃离我推掉我的手 2022-12-06 01:17 365阅读 0赞

项目复杂性提升后,应用与应用之间,还有单独的应用细分模块之后,DO 一般不会让外部依赖,这时候需要在提供对外接口的模块里放 DTO 用于对象传输,也即是 DO 对象对内,DTO对象对外,DTO 可以根据业务需要变更,并不需要映射 DO 的全部属性。

这种 对象与对象之间的互相转换,就需要有一个专门用来解决转换问题的工具,毕竟每一个字段都 get/set 会很麻烦。

MapStruct 就是这样的一个属性映射工具,只需要定义一个 Mapper 接口,MapStruct 就会自动实现这个映射接口,避免了复杂繁琐的映射实现。MapStruct官网地址: http://mapstruct.org/
API教程下载:mapstruct-guide.pdf
在这里插入图片描述

工程中引入 maven 依赖

  1. <properties>
  2. <mapstruct.version>1.4.1.Final</mapstruct.version>
  3. </properties>
  4. <dependencies>
  5. <dependency>
  6. <groupId>org.mapstruct</groupId>
  7. <artifactId>mapstruct</artifactId>
  8. <version>${ mapstruct.version}</version>
  9. </dependency>
  10. <dependency>
  11. <groupId>org.mapstruct</groupId>
  12. <artifactId>mapstruct-jdk8</artifactId>
  13. <version>${ mapstruct.version}</version>
  14. </dependency>
  15. <dependency>
  16. <groupId>org.mapstruct</groupId>
  17. <artifactId>mapstruct-processor</artifactId>
  18. <version>${ mapstruct.version}</version>
  19. </dependency>
  20. </dependencies>
  21. <build>
  22. <plugins>
  23. <plugin>
  24. <groupId>org.apache.maven.plugins</groupId>
  25. <artifactId>maven-compiler-plugin</artifactId>
  26. <version>3.8.1</version>
  27. <configuration>
  28. <source>1.8</source> <!-- depending on your project -->
  29. <target>1.8</target> <!-- depending on your project -->
  30. <annotationProcessorPaths>
  31. <path>
  32. <groupId>org.mapstruct</groupId>
  33. <artifactId>mapstruct-processor</artifactId>
  34. <version>${ mapstruct.version}</version>
  35. </path>
  36. <!-- other annotation processors -->
  37. </annotationProcessorPaths>
  38. </configuration>
  39. </plugin>
  40. </plugins>
  41. </build>
基本映射

有两个对象 User 和 UserDto需要转换,下面是这2个实体的属性

  1. public class User implements Serializable {
  2. private String id;
  3. private String name;
  4. private String phoneNumber;
  5. private String email;
  6. private String photoUrl;
  7. private Boolean deleted;
  8. private Boolean used;
  9. //getter and setter ...
  10. }
  11. public class UserDto implements Serializable {
  12. private String name;
  13. private String phoneNumber;
  14. private String email;
  15. //getter and setter ...
  16. }

添加UserModelConveter 接口,引入MapStruct相关功能

  1. import org.mapstruct.Mapper;
  2. import org.mapstruct.factory.Mappers;
  3. @Mapper(componentModel = "spring")
  4. public interface UserModelConverter {
  5. UserModelConverter INSTANCE = Mappers.getMapper(UserModelConverter.class);
  6. /** * 使用示例 * 如果实体模型中的字段不一致,通过@Mapping注解手动对应 @Mapping(source = "name", target = "fullName") PersonDto personToPersonDto(Person person); List<UserVO1> toConvertVOList(List<User> source);//转换集合 */
  7. UserDto userToUserDto(User user);
  8. }

若源对象属性与目标对象属性名字一致,会自动映射对应属性,不一样的需要手动指定

还可以用 format 转成自己想要的类型,如:转换格式的 birthDateFormat 加了dateFormat

如果某个属性你不想映射,可以加个 ignore=true

  1. @Mapper(componentModel = "spring")
  2. public interface UserModelConverter {
  3. UserModelConverter INSTANCE = Mappers.getMapper(UserModelConverter.class);
  4. @Mappings({
  5. @Mapping(source = "birthday", target = "birth"),
  6. @Mapping(source = "birthday", target = "birthDateFormat", dateFormat = "yyyy-MM-dd HH:mm:ss"),
  7. @Mapping(target = "birthExpressionFormat", expression = "java(org.apache.commons.lang3.time.DateFormatUtils.format(person.getBirthday(),\"yyyy-MM-dd HH:mm:ss\"))"),
  8. @Mapping(source = "user.age", target = "age"),
  9. @Mapping(target = "email", ignore = true)
  10. })
  11. PersonDTO domain2dto(Person person);
  12. List<PersonDTO> domain2dto(List<Person> people);
  13. }

使用UserModelConverter转换model

  1. User user = userService.getUserByPhoneNumber(phoneNumber);
  2. UserDto userDto = UserModelConverter.INSTANCE.userToUserDto(user);

启动项目,编译之后, UserModelConverter 接口目录下会自动生成实现类,在 target/classes 下生成对应的实现类

在这里插入图片描述

下面这个 UserModelConverterImpl 是自动生成的

  1. package com.zypcy.userservice.mapstruct;
  2. import com.zypcy.userservice.dto.UserDto;
  3. import com.zypcy.userservice.entity.User;
  4. import org.springframework.stereotype.Component;
  5. @Component
  6. public class UserModelConverterImpl implements UserModelConverter {
  7. public UserModelConverterImpl() {
  8. }
  9. public UserDto userToUserDto(User user) {
  10. if (user == null) {
  11. return null;
  12. } else {
  13. UserDto userDto = new UserDto();
  14. userDto.setId(user.getId());
  15. userDto.setName(user.getName());
  16. userDto.setPhoneNumber(user.getPhoneNumber());
  17. userDto.setEmail(user.getEmail());
  18. userDto.setPhotoUrl(user.getPhotoUrl());
  19. userDto.setUpdateDate(user.getUpdateDate());
  20. return userDto;
  21. }
  22. }
  23. }
多对一

MapStruct 可以将几种类型的对象映射为另外一种类型,比如将多个 DO 对象转换为 DTO

例子:两个DO 对象 (Item 和 Sku),一个 DTO 对象 SkuDTO

  1. @NoArgsConstructor
  2. @AllArgsConstructor
  3. @Data
  4. public class Item {
  5. private Long id;
  6. private String title;
  7. }
  8. @NoArgsConstructor
  9. @AllArgsConstructor
  10. @Data
  11. public class Sku {
  12. private Long id;
  13. private String code;
  14. private Integer price;
  15. }
  16. @NoArgsConstructor
  17. @AllArgsConstructor
  18. @Data
  19. public class SkuDTO {
  20. private Long skuId;
  21. private String skuCode;
  22. private Integer skuPrice;
  23. private Long itemId;
  24. private String itemName;
  25. }

创建 ItemConverter(映射)接口,MapStruct 就会自动实现该接口

  1. @Mapper
  2. public interface ItemConverter {
  3. ItemConverter INSTANCE = Mappers.getMapper(ItemConverter.class);
  4. @Mappings({
  5. @Mapping(source = "sku.id",target = "skuId"),
  6. @Mapping(source = "sku.code",target = "skuCode"),
  7. @Mapping(source = "sku.price",target = "skuPrice"),
  8. @Mapping(source = "item.id",target = "itemId"),
  9. @Mapping(source = "item.title",target = "itemName")
  10. })
  11. SkuDTO domain2dto(Item item, Sku sku);
  12. }

创建测试类,讲 Item 和 Sku 两个 DO对象,映射成一个 DTO 对象 SkuDTO

  1. public class ItemConverterTest {
  2. @Test
  3. public void test() {
  4. Item item = new Item(1L, "iPhone X");
  5. Sku sku = new Sku(2L, "phone12345", 1000000);
  6. SkuDTO skuDTO = ItemConverter.INSTANCE.domain2dto(item, sku);
  7. assertNotNull(skuDTO);
  8. assertEquals(skuDTO.getSkuId(),sku.getId());
  9. assertEquals(skuDTO.getSkuCode(),sku.getCode());
  10. assertEquals(skuDTO.getSkuPrice(),sku.getPrice());
  11. assertEquals(skuDTO.getItemId(),item.getId());
  12. assertEquals(skuDTO.getItemName(),item.getTitle());
  13. }
  14. }

MapStruct 注解关键词

  1. @Mapper 只有在接口加上这个注解, MapStruct 才会去实现该接口
  2. @Mapper 里有个 componentModel 属性,主要是指定实现类的类型,一般用到两个
  3. default:默认,可以通过 Mappers.getMapper(Class) 方式获取实例对象
  4. spring:在接口的实现类上自动添加注解 @Component,可通过 @Autowired 方式注入
  5. @Mapping:属性映射,若源对象属性与目标对象名字一致,会自动映射对应属性
  6. source:源属性
  7. target:目标属性
  8. dateFormatString Date 日期之间相互转换,通过 SimpleDateFormat,该值为 SimpleDateFormat 的日期格式
  9. ignore: 忽略这个字段
  10. @Mappings:配置多个@Mapping
  11. @MappingTarget 用于更新已有对象
  12. @InheritConfiguration 用于继承配置

发表评论

表情:
评论列表 (有 0 条评论,365人围观)

还没有评论,来说两句吧...

相关阅读

    相关 MapStruct实体间转换

    摘要: 在实际项目中,我们经常需要将PO转DTO、DTO转PO等一些实体间的转换。比较出名的有BeanUtil 和ModelMapper等,它们使用简单,但是在稍显复杂的业务场