MapStruct是一个Java注解处理器,它可以自动生成类型安全的Java Bean映射代码。MapStruct的主要目的是简化Java Bean之间的映射,它通过注解来指定Java Bean之间的映射规则,然后自动生成映射代码。
在MapStruct中,有几个常用的注解:
-
@Mapper:用于指定一个Java Bean映射器接口,该接口定义了Java Bean之间的映射规则。
-
@Mapping:用于指定Java Bean属性之间的映射关系。
-
@Mappings:用于指定多个@Mapping注解,可以将多个Java Bean属性之间的映射关系组合在一起。
-
@InheritInverseConfiguration:用于指定一个反向映射规则,可以将目标Java Bean映射回源Java Bean。
-
@MappingTarget:用于指定一个目标Java Bean对象,可以将源Java Bean映射到目标Java Bean对象中。
-
@AfterMapping:用于指定一个方法,在Java Bean映射完成后调用该方法。
下面是一个简单的MapStruct示例,其中定义了一个Java Bean映射器接口,用于将SourceBean映射到TargetBean中:
@Mapper
public interface BeanMapper {
@Mapping(source = "sourceField", target = "targetField")
TargetBean map(SourceBean sourceBean);
}
在上面的示例中,@Mapper注解用于指定BeanMapper接口是一个Java Bean映射器接口。@Mapping注解用于指定sourceField属性映射到targetField属性。然后,MapStruct会自动生成BeanMapper接口的实现代码,用于将SourceBean映射到TargetBean中。
需要注意的是,MapStruct中的注解非常灵活,可以根据实际需求进行组合和使用。同时,MapStruct还提供了丰富的配置选项,可以进一步定制生成的Java Bean映射代码。
MapStruct 的主要优点:
- 生成类型安全的代码,减少了手写代码的错误和冗余;
- 支持多种映射策略,包括注解、XML 配置、Java SPI 等;
- 支持复杂类型的映射,如集合、嵌套对象等;
- 支持自定义转换器,可以自定义转换逻辑;
- 易于集成到现有项目中。
MapStruct 的使用步骤:
- 定义源类型和目标类型的 Java bean;
- 在源类型和目标类型中添加注解;
- 创建一个 Mapper 接口,并使用 @Mapper 注解标记它;
- 在 Mapper 接口中定义映射方法,使用 @Mapping 注解标记映射关系;
- 在需要进行映射的地方,使用 Mapper 接口的实现类进行映射。
示例:
假设有一个 User 类和一个 UserDto 类,需要将它们进行映射。
User 类:
public class User {
private Long id;
private String name;
private Integer age;
// getter/setter 略
}
UserDto 类:
public class UserDto {
private Long id;
private String username;
private Integer age;
// getter/setter 略
}
Mapper 接口:
@Mapper
public interface UserMapper {
UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
@Mapping(source = "name", target = "username")
UserDto userToUserDto(User user);
}
使用示例:
User user = new User();
user.setId(1L);
user.setName("Tom");
user.setAge(18);
UserDto userDto = UserMapper.INSTANCE.userToUserDto(user);
以上代码将会把 User 对象映射为 UserDto 对象,其中 User 的 name 属性会被映射到 UserDto 的 username 属性。
项目中使用示例:
1、引入依赖
<!--工具类:数据映射-->
<properties>
<mapstruct.version>1.5.5.Final</mapstruct.version>
</properties>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</dependency>
2、自定义转换接口
import org.mapstruct.Mapper;
import org.mapstruct.MappingConstants;
import java.util.List;
/**
* @since 2023/8/17
*/
@Mapper(componentModel = MappingConstants.ComponentModel.SPRING)
public interface ObjectConverter {
/**
* request to dto list
*
* @param list
* @return
*/
List<TargetObjectDTO> toDtoList(List<SourceObjectDTO> list);
}
3、接口调用
public class CustomerController {
private final ObjectConverter converter;
public ApiResponse<Boolean> saveBatch(@RequestBody List<SourceObjectDTO> list) {
boolean result = converter.toDtoList(list);
return ApiResponse.ok(null);
}
}
@MappingTarget 注解:
在 MapStruct 中,@MappingTarget 注解用于指定目标对象,以便在映射过程中将源对象的值映射到目标对象中。该注解可以用于方法级别或参数级别,用于指定要映射的目标对象。
@MappingTarget 注解的使用方法如下:
- 方法级别使用:
@Mapper
public interface UserMapper {
@MappingTarget User map(UserDto userDto, @MappingTarget User user);
}
在上面的代码中,@MappingTarget 注解用于指定目标对象 User,将 UserDto 对象的值映射到 User 对象中。
- 参数级别使用:
@Mapper
public interface UserMapper {
void map(UserDto userDto, @MappingTarget User user);
}
在上面的代码中,@MappingTarget 注解用于指定目标对象 User,将 UserDto 对象的值映射到 User 对象中。
需要注意的是,@MappingTarget 注解只能用于可变对象,即可以修改其属性值的对象。如果目标对象是不可变对象,如 Java 中的 String 类型,则不能使用 @MappingTarget 注解。
另外,@MappingTarget 注解还可以与其他注解一起使用,如 @Mapping、@InheritInverseConfiguration 等,以实现更复杂的映射逻辑。
@AfterMapping注解:
MapStruct是一个Java bean映射框架,它可以自动生成类型安全的映射代码,从而简化了Java bean之间的映射操作。在MapStruct中,@AfterMapping是一个注解,它可以用于在映射完成后执行一些自定义代码。
@AfterMapping注解可以用在方法上,用于在映射完成后执行一些额外的逻辑。该注解可以接受一个或多个参数,其中最重要的参数是source和target,它们分别表示源对象和目标对象。例如:
@Mapper
public interface UserMapper {
@Mapping(target = "fullName", source = "firstName")
@AfterMapping
default void setFullName(@MappingTarget UserDTO userDTO, User user) {
userDTO.setFullName(user.getFirstName() + " " + user.getLastName());
}
UserDTO userToUserDTO(User user);
}
在上面的例子中,我们定义了一个名为setFullName的方法,并使用@AfterMapping注解将其标记为映射完成后执行的方法。该方法接受两个参数,分别是UserDTO和User,它们分别表示映射后的目标对象和源对象。在该方法中,我们将源对象的firstName和lastName属性拼接成一个fullName属性,并设置到目标对象中。
需要注意的是,@AfterMapping注解只能用于void类型的方法,并且该方法的参数必须与映射方法的参数一致(除了@MappingTarget注解的参数)。此外,@AfterMapping注解还可以接受一个qualifiedBy参数,用于指定一个条件,只有当该条件成立时才执行该方法。例如:
@Mapper
public interface UserMapper {
@Mapping(target = "fullName", source = "firstName")
@AfterMapping(qualifiedBy = { FullNameCondition.class })
default void setFullName(@MappingTarget UserDTO userDTO, User user) {
userDTO.setFullName(user.getFirstName() + " " + user.getLastName());
}
UserDTO userToUserDTO(User user);
}
public class FullNameCondition {
public boolean shouldSetFullName(UserDTO userDTO, User user) {
return user.getLastName() != null;
}
}
在上面的例子中,我们定义了一个名为shouldSetFullName的方法,并将其标记为FullNameCondition类的静态方法。该方法接受两个参数,分别是UserDTO和User,它们分别表示映射后的目标对象和源对象。在该方法中,我们判断源对象的lastName属性是否为null,如果不为null,则返回true,表示应该执行setFullName方法。在@AfterMapping注解中,我们使用qualifiedBy参数指定了FullNameCondition.class,表示只有当FullNameCondition.shouldSetFullName方法返回true时才执行setFullName方法。
@Mappings注解:
在MapStruct中,@Mappings注解用于指定多个@Mapping注解。它可以用于以下两种情况:
- 映射多个属性
当源对象和目标对象之间有多个属性需要映射时,可以使用@Mappings注解来指定多个@Mapping注解。
例如:
@Mapper
public interface CarMapper {
@Mappings({
@Mapping(source = "make", target = "manufacturer"),
@Mapping(source = "numberOfSeats", target = "seatCount")
})
CarDto carToCarDto(Car car);
}
在上面的例子中,我们使用@Mappings注解来指定两个@Mapping注解,将源对象的“make”属性映射到目标对象的“manufacturer”属性,将“numberOfSeats”属性映射到“seatCount”属性。
- 忽略某些属性
有时候,我们希望在映射过程中忽略某些属性,可以使用@Mappings注解来指定忽略的属性。
例如:
@Mapper
public interface CarMapper {
@Mappings({
@Mapping(source = "make", target = "manufacturer"),
@Mapping(source = "numberOfSeats", target = "seatCount"),
@Mapping(target = "id", ignore = true)
})
CarDto carToCarDto(Car car);
}
在上面的例子中,我们使用@Mappings注解来指定三个@Mapping注解,将源对象的“make”属性映射到目标对象的“manufacturer”属性,将“numberOfSeats”属性映射到“seatCount”属性,并忽略目标对象的“id”属性。
总之,@Mappings注解是一个非常有用的注解,可以帮助我们在MapStruct中指定多个属性映射和忽略某些属性。
@InheritInverseConfiguration注解:
在使用 MapStruct 进行对象映射时,有时候我们需要将一个对象的属性值映射到另一个对象的属性上,同时也需要将这两个对象的属性映射反过来。这时候就可以使用 MapStruct 中的 @InheritInverseConfiguration
注解来实现反向映射。
@InheritInverseConfiguration
注解的作用是继承反向映射的配置,它通常与 @Mapping
注解一起使用。当我们在一个映射方法上使用了 @Mapping
注解指定了源对象属性和目标对象属性的映射关系时,MapStruct 会自动生成一个反向映射方法,用于将目标对象的属性值映射回源对象中。而 @InheritInverseConfiguration
注解就是用来继承这个自动生成的反向映射方法的配置。
下面是一个使用 @InheritInverseConfiguration
注解的示例:
@Mapper
public interface UserMapper {
@Mapping(source = "name", target = "username")
UserDTO toUserDTO(User user);
@InheritInverseConfiguration
User toUser(UserDTO userDTO);
}
在上面的示例中,我们定义了一个 UserMapper
接口,其中包含两个方法:toUserDTO()
和 toUser()
。toUserDTO()
方法用于将 User
对象映射为 UserDTO
对象,其中指定了 name
属性映射到 username
属性上。而 toUser()
方法则用于将 UserDTO
对象映射为 User
对象,并使用 @InheritInverseConfiguration
注解继承了自动生成的反向映射方法的配置。