概述
场景
很多时候,会出现需要实体转换的情况,直接通过get和set方法,代码很冗余而且麻烦,所以就出现了实体类映射工具。比如通过BeanUtil,但是BeanUtil是基于反射实现,在运行时才会被发现,而且层层反射的性能差,灵活性也不怎么好。相比而言MapStruct就更加合适。
Mapstruct的优势:
- 简化的映射配置:使用MapStruct,您只需要定义一个接口,并在接口中声明映射方法,无需编写繁琐的映射逻辑。MapStruct会根据方法的命名和参数类型自动生成映射代码。
- 零依赖:MapStruct是一个独立的库,不依赖于其他第三方库。
- 支持多种映射策略:MapStruct支持多种映射策略,包括属性名相同的映射、自定义映射方法、基于注解的映射等。您可以根据需要选择适合的映射策略。
- 易于扩展和定制:MapStruct提供了丰富的扩展点和配置选项,可以根据具体需求进行定制。您可以自定义映射逻辑、添加转换器、配置映射策略等。
- 支持嵌套映射和集合映射:MapStruct支持嵌套对象之间的映射,以及集合对象之间的映射。
- 编译时类型检查。
常见参数以及使用场景
用于在自动生成的映射器代码中指定属性之间的映射关系,允许你自定义如何映射源对象的属性到目标对象的属性。
参数说明:
souce、target
在源对象和目标对象之间存在不同命名或复杂映射关系时,可以指定如何映射。例如:
@Mapper
public interface MyMapper {
@Mapping(source = "sourceName", target = "targetName")
TargetObject map(SourceObject source);
}
在上面的例子中,@Mapping注解指定了源对象的sourceName属性应该映射到目标对象的targetName属性。
对于嵌套的bean
@Mapper
public interface FishTankMapper {
@Mapping(target = "fish.kind", source = "fish.type")
FishTankDto map( FishTank source );
}
dateFormat
用于指定日期属性的格式化方式
@Mapper
public interface MyMapper {
@Mapping(source = "dateOfBirth", target = "birthDate", dateFormat = "yyyy-MM-dd")
TargetObject map(SourceObject source);
}
numberFormat
用于指定数字的格式化方式
@Mapper
public interface CarMapper {
@Mapping(source = "price", numberFormat = "$#.00")
CarDto carToCarDto(Car car);
}
source对应的字段要符合numberFormat的要求
constant:
用于将属性映射为常量值,如@Mapping(target = "status", constant = "ACTIVE")。
expression
允许你为源和目标属性之间的映射提供自定义的Java表达式。
@Mapper
public interface SourceTargetMapper {
@Mapping(target = "timeAndFormat",
expression = "java( new org.sample.TimeAndFormat( s.getTime(), s.getFormat() ) )")
Target sourceToTarget(Source s);
}
defaultExpression
defaultExpression属性的值应该是一个字符串,这个字符串应该是一个有效的SpEL(Spring Expression Language)表达式。
它允许你提供一个默认的表达式,该表达式在源属性值为null时指定
imports java.util.UUID;
@Mapper( imports = UUID.class )
public interface SourceTargetMapper {
SourceTargetMapper INSTANCE = Mappers.getMapper( SourceTargetMapper.class );
@Mapping(target="id", source="sourceId", defaultExpression = "java( UUID.randomUUID().toString() )")
Target sourceToTarget(Source s);
}
ignore
用于指示在映射过程中是否忽略特定的属性。这个属性可以设置为true或false
默认为false,表示不忽略目标属性,映射器会尝试将源属性映射到目标属性。为true,映射器将不会尝试将源属性映射到目标属性。
@Mapper
public interface MyMapper {
@Mapping(source = "sourceAge", target = "targetAge", ignore = true)
TargetObject mapWithAgeIgnored(SourceObject source);
}
qualifiedBy、qualifiedByName
用于指定映射处理的自定义方法。
qualifiedBy属性接受一个类型为java.lang.Class<?>的参数,用于指定一个实现了指定接口的类,该类中定义了自定义的映射方法。
qualifiedByName属性接受一个字符串作为参数,用于指定一个具有特定名称的方法。这个方法应该定义在实体类之间映射的转换逻辑。
@Mapper(component = "mapper")
public interface MyMapper {
@Mapping(source = "age", target = "age", qualifiedBy = MyCustomMapper.class)
Person person2PersonDTO(Person person);
}
@Mapper(component = "mapper")
public interface MyMapper {
@Mapping(source = "age", target = "age", qualifiedByName = "convertAge")
Person person2PersonDTO(Person person);
}
dependsOn
用于指定其他注解的映射,这些注解依赖于当前注解的映射。
@Mapper
public interface UserMapper {
@Mapping(target = "id", source = "user.id")
@Mapping(target = "name", source = "user.name", dependsOn = {"repositoryName"})
UserDTO userToUserDTO(User user);
}
指定了name字段依赖于repositoryName字段的映射。这意味着在将User转换为UserDTO时,MapStruct会首先处理repositoryName字段的映射,然后再处理name字段的映射。
defaultValue
它允许你为映射的字段指定一个默认值。当源对象中的字段值为null或未定义时,会使用默认值映射给目标字段
快速入门-代码demo
依赖导入
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.4.2.Final</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.4.2.Final</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<scope>provided</scope>
</dependency>
实体类
@Data
public class UserDto {
private String name;
private Integer age;
private String gender;
private Integer userId;
private Integer password;
}
@Data
public class User {
private String name;
private Integer userId;
private Integer password;
}
映射
@Mapper
public interface UserMapper {
UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
UserDto toDto(User user);
User toEntity(UserDto userDto);
}
测试类
@Test
void contextLoads() {
UserDto userDto=new UserDto();
userDto.setName("xgss");
userDto.setUserId(123);
userDto.setPassword(666);
User user = UserMapper.INSTANCE.toEntity(userDto);
System.out.println(user);
}
测试结果: