MapStruct-Plus
MapStruct增加包
下面介绍一个 MapStruct 的增强包 —— MapStruct Plus,一个注解,可以生成两个类之间的转换接口,使 Java 类型转换更加便捷、优雅。
入门示例
官网地址:https://www.mapstruct.plus
源码地址:https://github.com/ZhaoRd/mapstruct-spring-plus
添加依赖
<dependencies>
<!-- spring-boot-starter-web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Mapstruct-plus -->
<dependency>
<groupId>io.github.linpeilie</groupId>
<artifactId>mapstruct-plus-spring-boot-starter</artifactId>
<version>1.4.4</version>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version>
<scope>provided</scope>
</dependency>
<!-- Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>17</source>
<target>17</target>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version>
</path>
<path>
<groupId>io.github.linpeilie</groupId>
<artifactId>mapstruct-plus-processor</artifactId>
<version>1.4.4</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>0.2.0</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
定义两个类
- User
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String username;
private int age;
private boolean young;
}
- UserDto
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserDTO {
private String username;
private int age;
private boolean young;
}
指定对象映射关系
在 User
或者 UserDTO
上面增加注解 —— @AutoMapper
,并设置 targetType
为对方类。
@AutoMapper(target = UserDTO.class)
public class User {
// ...
}
测试
@SpringBootTest
public class QuickStartTest {
@Resource
private Converter converter;
@Test
public void test() {
User user = new User();
user.setUsername("jack");
user.setAge(23);
user.setYoung(false);
UserDTO userDto = converter.convert(user, UserDTO.class);
System.out.println(userDto); // UserDto{username='jack', age=23, young=false}
User newUser = converter.convert(userDto, User.class);
System.out.println(newUser); // User{username='jack', age=23, young=false}
}
}
小结
引入依赖后,使用 Mapstruct Plus 步骤非常简单。
- 给需要转换的类添加
AutoMapper
注解 - 获取
Converter
实例,调用convert
方法即可
特性
完全兼容 Mapstruct
Mapst实现了增强操作,如果之前已经使用了 Mapstruct,可以直接替换相关依赖。
单注解即可实现两个对象相互转换
例如快速开始中,只在 User
类上面增加注解 @AutoMapper
,Mapstruct Plus 除了会生成 User
-> UserDto
的转换接口,默认还会生成 UserDto
-> User
的转换接口。
编译后,可以查看生成的类,如下:
自定义对象类型的属性自动转换
当两个需要转换的对象 A
和 ADto
,其中的属性 B
和 BDto
是自定义类型,并且也定义了 @AutoMapper
注解的话,在生成转换 A
和 ADto
时,会自动依赖属性 B
和 BDto
的转换接口,实现其相应的属性转换。
例如:
分别有两组对象模型:汽车(Car) 和座椅配置(SeatConfiguration),其中 Car 依赖 SeatConfiguration。
两组对象结构一致,只不过代表层级不一样,这里拿 dto 层的对象定义举例:
CarDto
@AutoMapper(target = Car.class)
public class CarDto {
private SeatConfigurationDto seatConfiguration;
}
SeatConfiguration
@AutoMapper(target = SeatConfiguration.class)
public class SeatConfigurationDto {
private int seatCount;
}
测试:
@Test
public void carConvertTest() {
CarDto carDto = new CarDto();
SeatConfigurationDto seatConfigurationDto = new SeatConfigurationDto();
seatConfigurationDto.setSeatCount(4);
carDto.setSeatConfiguration(seatConfigurationDto);
final Car car = converter.convert(carDto, Car.class);
System.out.println(car); // Car(seatConfiguration=SeatConfiguration(seatCount=4))
assert car.getSeatConfiguration() != null;
assert car.getSeatConfiguration().getSeatCount() == 4;
}
单个对象对多个对象进行转换
Mapstruct Plus 提供了 @AutoMappers
注解,支持配置多个目标对象,进行转换。
例如:有三个对象,User
、UserDto
、UserVO
,User
分别要和其他两个对象进行转换。则可以按如下配置:
@Data
@AutoMappers({
@AutoMapper(target = UserDto.class),
@AutoMapper(target = UserVO.class)
})
public class User {
// ...
}
Map 转对象
Mapstruct Plus 提供了 @AutoMapMapper
注解,支持生成 Map<String, Object>
转换为当前类的接口。同时,还支持 map 中嵌套 Map<String, Object>
转换为自定义类嵌套自定义类的场景。
其中,map 中的 value 支持的类型如下:
- String
- BigDecimal
- BigInteger
- Integer
- Long
- Double
- Number
- Boolean
- Date
- LocalDateTime
- LocalDate
- LocalTime
- URI
- URL
- Calendar
- Currency
- 自定义类(自定义类也需要增加
@AutoMapMapper
注解
例如:
有如下两个接口:
MapModelA
@Data
@AutoMapMapper
public class MapModelA {
private String str;
private int i1;
private Long l2;
private MapModelB mapModelB;
}
MapModelB
@Data
@AutoMapMapper
public class MapModelB {
private Date date;
}
测试:
@Test
public void test() {
Map<String, Object> mapModel1 = new HashMap<>();
mapModel1.put("str", "1jkf1ijkj3f");
mapModel1.put("i1", 111);
mapModel1.put("l2", 11231);
Map<String, Object> mapModel2 = new HashMap<>();
mapModel2.put("date", DateUtil.parse("2023-02-23 01:03:23"));
mapModel1.put("mapModelB", mapModel2);
final MapModelA mapModelA = converter.convert(mapModel1, MapModelA.class);
System.out.println(mapModelA); // MapModelA(str=1jkf1ijkj3f, i1=111, l2=11231, mapModelB=MapModelB(date=2023-02-23 01:03:23))
}
支持自定义转换
自定义属性转换
Mapstruct Plus 提供了 @AutoMapping
注解,该注解在编译后,会变为 Mapstruct 中的 @Mapping
注解,已经实现了几个常用的注解属性。
指定不同名称属性字段映射转换
例如,Car
类中属性 wheels
属性,转换 CarDto
类型时,需要将该字段映射到 wheelList
上面,可以在 wheels
上面增加如下注解:
@AutoMapper(target = CarDto.class)
public class Car {
@AutoMapping(target = "wheelList")
private List<String> wheels;
}
自定义时间格式化
在将 Date
类型的属性,转换为 String
类型时,可以通过 dateFormat
来指定时间格式化:
@AutoMapper(target = Goods.class)
public class GoodsDto {
@AutoMapping(target = "takeDownTime", dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date takeDownTime;
}
自定义数字格式化
当数字类型(double
、long
、BigDecimal
)转换为 String
类型时,可以通过 numberFormat
指定 java.text.DecimalFormat
所支持的格式:
@AutoMapper(target = Goods.class)
public class GoodsDto {
@AutoMapping(target = "price", numberFormat = "$#.00")
private int price;
}
自定义 Java 表达式
@AutoMapping
提供了 expression
属性,支持配置一段可执行的 Java 代码,来执行具体的转换逻辑。
例如,当一个 List<String>
的属性,想要转换为用 ,
分隔的字符串时,可以通过该配置,来执行转换逻辑:
@AutoMapper(target = UserDto.class)
public class User {
@AutoMapping(target = "educations", expression = "java(java.lang.String.join(",", source.getEducationList()))")
private List<String> educationList;
}
自定义类型转换器
@AutoMapping
注解提供了 uses
属性,引入自定义的类型转换器,来提供给当前类转换时使用。
实例场景:
项目中会有字符串用 ,
分隔,在一些类中,需要根据逗号拆分为字符串集合。针对于这种场景,可以有两种方式:首先可以指定字段映射时的表达式,但需要对每种该情况的字段,都添加表达式,复杂且容易出错。
第二,就可以自定义一个类型转换器,通过 uses
来使用
public interface StringToListString {
default List<String> stringToListString(String str) {
return StrUtil.split(str);
}
}
@AutoMapper(target = User.class, uses = StringToListStringConverter.class)
public class UserDto {
private String username;
private int age;
private boolean young;
@AutoMapping(target = "educationList")
private String educations;
// ......
}
测试:
@SpringBootTest
public class QuickStartTest {
@Autowired
private Converter converter;
@Test
public void ueseTest() {
UserDto userDto = new UserDto();
userDto.setEducations("1,2,3");
final User user = converter.convert(userDto, User.class);
System.out.println(user.getEducationList()); // [1, 2, 3]
assert user.getEducationList().size() == 3;
}
}
还没有人赞赏,快来当第一个赞赏的人吧!
- 2¥
- 5¥
- 10¥
- 20¥
- 50¥
声明:本文为原创文章,版权归信息岛所有,欢迎分享本文,转载请保留出处!