简化mapstruct代码: mapstruct-spring-plus
2021-05-07 08:37
127 查看
mapstruct
MapStruct 是一个属性映射工具,只需要定义一个 Mapper 接口,MapStruct 就会自动实现这个映射接口,避免了复杂繁琐的映射实现。MapStruct官网地址: http://mapstruct.org/
MapStruct 使用APT生成映射代码,其在效率上比使用反射做映射的框架要快很多。
mapstruct spring
MapStruct 结合spring使用,设定
componentModel = "spring"即可,如下Mapper接口:
@Mapper(componentModel = "spring") public interface CarDtoMapper{ Car dtoToEntity(CarDto dto); }
生成的映射代码如下,发现实现类上添加了
@Component注解
@Generated( value = "org.mapstruct.ap.MappingProcessor", date = "2021-04-26T11:02:50+0800", comments = "version: 1.4.2.Final, compiler: IncrementalProcessingEnvironment from gradle-language-java-6.8.jar, environment: Java 1.8.0_211 (Oracle Corporation)" ) @Component public class CarDtoMapperImpl implements CarDtoMapper { @Override public Car dtoToEntity(CarDto dto) { if ( dto == null ) { return null; } Car car = new Car(); car.setName( dto.getName() ); return car; } }
mapstruct spring 使用的缺点
mapstruct结合spring,在使用方式上主要是需要编写接口文件和定义函数所带来编码工作量:
- 需要创建mapper接口文件,这个是mapstruct框架的必 56c 须要经历的过程,代码量增加
- Dto和Entity之间互相转换,需要在接口中添加一个方法,并且添加上
InheritInverseConfiguration
注解,如下
@InheritInverseConfiguration(name = "dtoToEntity") CarDto entityToDto(Car dto);
- service 中依赖多个mapper转换,增加构造函数注入个数
- 覆盖已有对象,需要添加如下map方法,如下
Car dtoMapToEntity(CarDto dto, @MappingTarget Car car)
反向映射,同样需要添加如下方法
CarDto entityMapToDto(Car dto, @MappingTarget CarDto car);
理想的映射工具
对于对象映射,有一种理想的使用方式,伪代码如下
Car car = mapper.map(dto, Car.class); // or Car car = new Car(); mapper.map(dto, car); // 反向映射 CarDto dto = mapper.map(entity, CarDto.class); // or CarDto dto = new CarDto(); mapper.map(entity, dto);
只使用mapper对象,就可以解决任何对象之间的映射。
mapstruct 官方解决方案: mapstruct-spring-extensions
官方地址如下: https://github.com/mapstruct/mapstruct-spring-extensions
其思路是使用spring 的 Converter接口,官方用法如下
@Mapper(config = MapperSpringConfig.class) public interface CarMapper extends Converter<Car, CarDto> { @Mapping(target = "seats", source = "seatConfiguration") CarDto convert(Car car); } @ComponentScan("org.mapstruct.extensions.spring") @Component static class AdditionalBeanConfiguration { @Bean ConfigurableConversionService getConversionService() { return new DefaultConversionService(); } } @BeforeEach void addMappersToConversionService() { conversionService.addConverter(carMapper); conversionService.addConverter(seatConfigurationMapper); conversionService.addConverter(wheelMapper); conversionService.addConverter(wheelsMapper); conversionService.addConverter(wheelsDtoListMapper); } @Test void shouldKnowAllMappers() { then(conversionService.canConvert(Car.class, CarDto.class)).isTrue(); then(conversionService.canConvert(SeatConfiguration.class, SeatConfigurationDto.class)).isTrue(); then(conversionService.canConvert(Wheel.class, WheelDto.class)).isTrue(); then(conversionService.canConvert(Wheels.class, List.class)).isTrue(); then(conversionService.canCon ad8 vert(List.class, Wheels.class)).isTrue(); } @Test void shouldMapAllAttributes() { // Given final Car car = new Car(); car.setMake(TEST_MAKE); car.setType(TEST_CAR_TYPE); final SeatConfiguration seatConfiguration = new SeatConfiguration(); seatConfiguration.setSeatMaterial(TEST_SEAT_MATERIAL); seatConfiguration.setNumberOfSeats(TEST_NUMBER_OF_SEATS); car.setSeatConfiguration(seatConfiguration); final Wheels wheels = new Wheels(); final ArrayList<Wheel> wheelsList = new ArrayList<>(); final Wheel wheel = new Wheel(); wheel.setDiameter(TEST_DIAMETER); wheel.setPosition(TEST_WHEEL_POSITION); wheelsList.add(wheel); wheels.setWheelsList(wheelsList); car.setWheels(wheels); // When final CarDto mappedCar = conversionService.convert(car, CarDto.class); }
使用
mapstruct-spring-extensions,使用
ConfigurableConversionService, 虽然解决了使用同一个对象映射,但是代码量没有解决,同时,没有提供覆盖已有对象的使用方式
推荐 mapstruct-spring-plus
地址: https://github.com/ZhaoRd/mapstruct-spring-plus
这个项目参考了
mapstruct-spring-extensions项目,同时使用APT技术,动态生成
Mapper接口,解决编写接口的问题,提供
IObejctMapper接口,提供所有的map方法。
maven引入
<properties> <org.mapstruct.version>1.4.2.Final</org.mapstruct.version> <io.github.zhaord.version>1.0.1.RELEASE</io.github.zhaord.version> </properties> ... <dependencies> <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct</artifactId> <version>${org.mapstruct.version}</version> </dependency> <dependency> <groupId>io.github.zhaord</groupId> <artifactId>mapstruct-spring-plus-boot-starter</artifactId> <version>${io.github.zhaord.version}</version> </dependency> </dependencies> ... <build> <plugins> <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> ad0 <path> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-processor</artifactId> <version>${org.mapstruct.version}</version> </path> <path> <groupId>io.github.zhaord</groupId> <artifactId>mapstruct-spring-plus-processor</artifactId> <version>${io.github.zhaord.version}</version> </path> </annotationProcessorPaths> </configuration> </plugin> </plugins> </build>
gradle 引入
dependencies { ... compile 'org.mapstruct:mapstruct:1.4.2.Final' compile 'io.github.zhaord:mapstruct-spring-plus-boot-starter:1.0.1.RELEASE' annotationProcessor 'org.mapstruct:mapstruct-processor:1.4.2.Final' testAnnotationProcessor 'org.mapstruct:mapstruct-processor:1.4.2.Final' // if you are using mapstruct in test code annotationProcessor 'io.github.zhaord:mapstruct-spring-plus-processor:1.0.1.RELEASE' testAnnotationProcessor 'io.github.zhaord:mapstruct-spring-plus-processor:1.0.1.RELEASE' // if you are using mapstruct in test code ... }
使用案例
使用代码如下
public enum CarType { SPORTS, OTHER } @Data public class Car { private String make; private CarType type; } @Data @AutoMap(targetType = Car.class) public class CarDto { private String make; private String type; } @ExtendWith(SpringExtension.class) @ContextConfiguration( classes = {AutoMapTests.AutoMapTestConfiguration.class}) public class AutoMapTests { @Autowired private IObjectMapper mapper; @Test public void testDtoToEntity() { var dto = new CarDto(); dto.setMake("M1"); dto.setType("OTHER"); Car entity = mapper.map(dto, Car.class); assertThat(entity).isNotNull(); assertThat(entity.getMake()).isEqualTo("M1"); assertThat(entity.getCarType()).isEqualTo("OTHER"); } @ComponentScan("io.github.zhaord.mapstruct.plus") @Configuration @Component static class AutoMapTestConfiguration { } }
AutoMap 生成的接口代码
@Mapper( config = AutoMapSpringConfig.class, uses = {} ) public interface CarDtoToCarMapper extends BaseAutoMapper<CarDto, Car> { @Override @Mapping( ignore = false ) Car map(final CarDto source); @Override @Mappi 1463 ng( ignore = false ) Car mapTarget(final CarDto source, @MappingTarget final Car target); }
mapstruct-spring-plus 带来的便捷
- 使用
AutoMap
注解,减少了重复代码的编写,尤其是接口文件和映射方法 - 依赖注入,只需要注入
IObjectMapper
接口即可,具体实现细节和调用方法,对客户端友好 - 没有丢失mapstruct的功能和效率
@Mapping
注解,都可以使用@AutoMapField
来完成字段的映射设置,因为@AutoMapField
继承自@Mapping
,比如字段名称不一致、跳过映射等
关注我的公众号,一起探索新技术
相关文章推荐
- 业务代码的救星——Java 对象转换框架 MapStruct 妙用
- Maven整合ssm框架(Maven+Spring MVC+Spring+Mybatis Plus),Mybatis Plus自动生成代码(Generator) 文末附码云完整代码
- 二、springboot集成mybatis-plus,让代码变得简洁易维护
- 使用spring jdbc template简化jdbc数据库操作实例代码
- 3)SpringBoot-使用Lombok 插件简化代码
- spring-boot-plus-v2.0发布了-让天下没有难写的代码
- 用map, next 和 reject 简化代码(ruby)
- 业务代码的救星——Java 对象转换框架 MapStruct 妙用
- Spring+SpringMVC+MyBatis+easyUI整合基础篇(四)代码简化
- 使用spring中的HibernateTemplate简化代码,并且不用管理sessionFactory
- Spring Boot 代码简化利器 lombok
- springboot+mybatisPlus代码层级梳理
- 简化远程代码的调用SpringClioud_Feign
- 今晚看朋友用Hibernate和spring,struct,ibatis以及用MyEclipse插件生成代码
- 用好spring mvc validator可以简化代码
- 用好spring mvc validator可以简化代码
- Spring 可代码简化操作类
- spring3支持@value注解从配置文件中读取配置值,大大简化读取配置文件的代码@
- SpringBoot+mybatis plus的代码自动生成
- 关于SpringBoot中使用mapstruct插件实现复杂的对象映射