MapStruct是一个开源的Java映射框架,它可以帮助开发者在不同类型的Java对象之间进行无缝转换。通过使用注解配置映射规则,MapStruct可以自动生成高效的映射代码,减少手动编写转换逻辑的工作量。它支持在编译时生成映射代码,因此可以提供更好的性能和类型安全性。总的来说,MapStruct使Java对象之间的转换变得更加简单和高效。
1.使用MapStruct替换BeanUtils
在处理一般简单场景时,可以选择使用BeanUtils、Spring官方工具或其他第三方工具,它们功能相似。然而,对于复杂字段映射,这些工具可能不够强大,并且在进行批量转换时,效率也会受到影响。这时候,MapStruct就能很好地解决这两个问题。在编译时,MapStruct会自动生成映射代码,保证高性能、提前发现问题并让开发人员能够进行彻底的错误检查。
2.集成MapStruct
2.1.首先需要依赖他的相关的jar包
<!-- 引入mapstruct -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.4.2.Final</version>
</dependency>
因为MapStruct需要在编译器生成转换代码,所以需要在maven-compiler-plugin插件中配置上对mapstruct-processor的引用,由于项目中已经使用了lombok和fluent-mybatis,
所以这两个也需要纳入管理,如果还有其他需要在编译器生成转换代码的组件,也需要纳入管理(可以保证编译的顺序)
注意:官网有坑,lombok一定要放在最前面,让其先生成get/set方法,否则mapstruct编译会找不到属性的get/set方法
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>utf-8</encoding>
<!-- 管理自动生成代码,会按Path先后先顺序生成lombok放在前面,否则mapstruct使用时会找不到get方法 -->
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.4.2.Final</version>
</path>
<path>
<groupId>com.github.atool</groupId>
<artifactId>fluent-mybatis-processor</artifactId>
<version>1.6.8</version>
</path>
<!-- other annotation processors -->
</annotationProcessorPaths>
</configuration>
</plugin>
2.2.我们需要定义一个做映射的接口(实体类和DTO代码省略)
/**
* MapStruct实体类和DTO转换 类名不能以Mapper结尾,否则和fluent-mybatis冲突
*/
@Mapper
public interface MapStruct {
MapStruct INSTANCE = Mappers.getMapper(MapStruct.class);
/**
* 将ApiGroupEntity转成ApiGroupDto
* @param entity
* @return
*/
@Mappings({
@Mapping(source = "id", target = "id"),
@Mapping(source = "name", target = "name"),
@Mapping(source = "groupRemark", target = "groupRemark")
})
ApiGroupDto convertEntityToDto(ApiGroupEntity entity);
}
编译成功后,会在target下自动生成对应的实现类MapStructImpl
package com.cnhqd.scap.dataStation.mapper.mapstruct;
import com.cnhqd.scap.dataStation.dto.api.ApiGroupDto;
import com.cnhqd.scap.dataStation.entity.api.ApiGroupEntity;
public class MapStructImpl implements MapStruct {
public MapStructImpl() {
}
public ApiGroupDto convertEntityToDto(ApiGroupEntity entity) {
if (entity == null) {
return null;
} else {
ApiGroupDto apiGroupDto = new ApiGroupDto();
apiGroupDto.setId(entity.getId());
apiGroupDto.setName(entity.getName());
apiGroupDto.setGroupRemark(entity.getGroupRemark());
apiGroupDto.setDomainInfo(entity.getDomainInfo());
apiGroupDto.setRelProjectId(entity.getRelProjectId());
apiGroupDto.setCreatePerson(entity.getCreatePerson());
return apiGroupDto;
}
}
}
2.3.测试
public static void main(String[] args) {
ApiGroupEntity entity = new ApiGroupEntity();
entity.setId("123");
entity.setGroupRemark("789");
entity.setName("API分组");
ApiGroupDto apiGroupDto = MapStruct.INSTANCE.convertEntityToDto(entity);
System.out.println(apiGroupDto);
}
输出结果:
ApiGroupDto(id=123, name=API分组, groupRemark=789, domainInfo=null, relProjectId=null, createPerson=null)
Process finished with exit code 0
3.MapStruct的使用方法
MapStruct使用时只需使用映射类获取实例,调用对应方法即可
MapStruct.INSTANCE.convertEntityToDto(entity);
MapStruct支持属性名称不一致,属性类型不一致和多对一等多种方式,下面以简单的示例来展开
3.1属性名称不一致
需要转换的两个类属性名称不一致
/**
* user类
*/
@Data
@AllArgsConstructor
public class User {
private String id;
private String name;
private int age;
}
/**
* userDto
*/
@Data
public class UserDto {
private String userId;
private String userName;
private int userAge;
}
映射方法
@Mappings({
@Mapping(source = "id", target = "userId"),
@Mapping(source = "name", target = "userName"),
@Mapping(source = "age", target = "userAge")
})
UserDto convertDto(User entity);
测试
public static void main(String[] args) {
User user = new User("123", "张三", 25);
UserDto userDto = EntityConvertDtoMapper.INSTANCE.convertDto(user);
System.out.println(userDto);
}
输出结果:
UserDto(userId=123, userName=张三, userAge=25)
3.2属性类型不一致
需要转换的两个类属性类型不一致User的id为long,UserDto为String
@Data
@AllArgsConstructor
public class User {
private long id;
private String name;
private int age;
}
@Data
public class UserDto {
private String id;
private String name;
private int age;
}
映射方法
通过expression属性指定java表达式,表达式中的方法可以自定义。本例用String.valueOf()
@Mappings({
@Mapping(target = "id", expression = "java(java.lang.String.valueOf(entity.getId()))")
})
UserDto convertDto(User entity);
测试
public static void main(String[] args) {
User user = new User(123, "张三", 25);
UserDto userDto = EntityConvertDtoMapper.INSTANCE.convertDto(user);
System.out.println(userDto);
}
结果:
UserDto(id=123, name=张三, age=25)
3.3多对一
两个实体类转成一个Dto
@Data
@AllArgsConstructor
public class User {
private long id;
private String name;
private int age;
}
@Data
@AllArgsConstructor
public class UserInfo {
private long id;
private String address;
private String position;
}
@Data
public class UserDto {
private String id;
private String name;
private int age;
private String address;
private String position;
}
映射方法
@Mappings({
@Mapping(source = "user.id", target = "id"),
@Mapping(source = "user.name", target = "name"),
@Mapping(source = "user.age", target = "age"),
@Mapping(source = "info.address", target = "address"),
@Mapping(source = "info.position", target = "position")
})
UserDto convertDto(User user, UserInfo info);
测试:
public static void main(String[] args) {
User user = new User(123, "张三", 25);
UserInfo info = new UserInfo(123, "西安市", "产品经理");
UserDto userDto = EntityConvertDtoMapper.INSTANCE.convertDto(user, info);
System.out.println(userDto);
}
结果:UserDto(id=123, name=张三, age=25, address=西安市, position=产品经理)
3.4批量copy
一个Mappings映射,可以对应多个转换方法,例如:
@Mappings({
@Mapping(source = "id", target = "userId"),
@Mapping(source = "name", target = "userName"),
@Mapping(source = "age", target = "userAge")
})
// 单条数据copy
UserDto convertDto(User entity);
// 批量copy
List<UserDto> convertListDto(List<User> entity);
如有问题,欢迎评论、指正!
4 和spring集成
@Mapper(componentModel = "spring")
public interface DataQualityJobCalculateDelayInfoConverter {
/**
* entity to dto
* @param list
* @return
*/
List<DataQualityJobCalculateDelayInfoDto> toDtoList(List<DataQualityJobCalculateDelayInfo> list);
DataQualityJobCalculateDelayInfoDto toDto(DataQualityJobCalculateDelayInfo info);
DataQualityJobCalculateDelayInfo toEntity(DataQualityJobCalculateDelayInfoDto info);
}
在Spring中的使用
@Autowired
private DataQualityJobCalculateDelayInfoConverter converter;