1. 对比
- BeanUtils.copyProperties 使用反射实现,copy 粒度太粗
- MapStruct 编译期生成,效率高;灵活性高,支持嵌套,自定义扩展
1.1 引入依赖
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.4.2.Final</version>
</dependency>
<build>
<!-- Spring Boot 插件,打包为可执行的jar -->
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
<!-- Maven 编译插件,提供给 MapStruct 使用 -->
<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>
<annotationProcessorPaths>
<!-- 注解处理器 -->
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.4.2.Final</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>0.2.0</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
2. 实战
2.1 @Mapper
- @Mapper 是编译时 MapStruct 处理器的入口
- @Mapping 配置映射的属性名
- 映射方法的名字是随意的
@Mapper
public interface MapStructMapper {
MapStructMapper INSTANCE = Mappers.getMapper(MapStructMapper.class);
@Mapping(source = "id", target = "id")
@Mapping(source = "name", target = "orderName")
OrderDTO convert(Order order);
}
编译后的代码
@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2023-01-19T14:40:17+0800",
comments = "version: 1.4.2.Final, compiler: javac, environment: Java 1.8.0_77 (Oracle Corporation)"
)
public class MapStructMapperImpl implements MapStructMapper {
@Override
public OrderDTO convert(Order order) {
if ( order == null ) {
return null;
}
OrderDTO orderDTO = new OrderDTO();
orderDTO.setOrderName( order.getName() );
orderDTO.setId( order.getId() );
orderDTO.setOrderCode( order.getOrderCode() );
return orderDTO;
}
}
测试
public static void main(String[] args) {
MapStructMapper mapper = MapStructMapper.INSTANCE;
Order order = new Order(1001L, "A001", "Apple");
OrderDTO convert = mapper.convert(order);
System.out.println(convert);
}
3. 自定义类型转换
3.1 @Named
- @Named 字段类型不对应时,转换
- qualifiedByName 取自 @Named 声明的名称
@Mapper
public interface MapStructMapper {
MapStructMapper INSTANCE = Mappers.getMapper(MapStructMapper.class);
@Mapping(source = "name", target = "orderName")
@Mapping(source = "flag", target = "flagDesc", qualifiedByName = "booleanToString")
OrderDTO convert(Order order);
@Named("booleanToString")
default String booleanToString(boolean flag) {
return flag ? "是" : "否";
}
}
3.2 定制转换规则
当转换方法多个 Mapping 文件都要用到时,可以写一个工具类
@Mapper(uses = MapStructUtils.class)
public interface MapStructMapper {
MapStructMapper INSTANCE = Mappers.getMapper(MapStructMapper.class);
@Mapping(source = "name", target = "orderName")
@Mapping(source = "flag", target = "flagDesc", qualifiedByName = "booleanToString")
OrderDTO convert(Order order);
}
public class MapStructUtils {
@Named("booleanToString")
public String booleanToString(boolean flag) {
return flag ? "是" : "否";
}
}
编译后的代码
@Override
public OrderDTO convert(Order order) {
if ( order == null ) {
return null;
}
OrderDTO orderDTO = new OrderDTO();
orderDTO.setOrderName( order.getName() );
if ( order.getFlag() != null ) {
orderDTO.setFlagDesc( mapStructUtils.booleanToString( order.getFlag().booleanValue() ) );
}
orderDTO.setId( order.getId() );
orderDTO.setOrderCode( order.getOrderCode() );
return orderDTO;
}
4. 注入 Spring 容器
@Mapper(componentModel = "spring")
public interface MapStructMapper {}
编译后的类会加上 @Component 注解
···
@Component
public class MapStructMapperImpl implements MapStructMapper {}
···
可以直接注入
@Resource
private MapStructMapper mapper;
OrderDTO convert = mapper.convert(order);
网友评论