1.什么是Mapper?
MapStruct是一个代码生成器,它基于convention over configuration(约定优于配置)的思想,极大地简化了 Java bean 类型之间转换。
1.1 为什么使用mapstruct?
JAVA开发按照传统的MVC或DDD模型开发时,各层传输之间的bean类型不同会涉及到大量的bean转换,比如: DO、BO、DTO、entity、VO等
现在有这么个场景,从数据库查询出来了一个user对象(包含id,用户名,密码,手机号,邮箱,角色这些字段)和一个对应的角色对象role(包含id,角色名,角色描述这些字段),现在在controller需要用到user对象的id,用户名,和角色对象的角色名三个属性。
一种方式是直接把两个对象传递到controller层,但是这样会多出很多没用的属性。更通用的方式是需要用到的属性封装成一个类(DTO),通过传输这个类的实例来完成数据传输。
1.2 使用mapstruct优点 与缺点分别是什么?
*优点:
mapstruct是在编译时完成Bean转换,与内存式(BeanUtils.copy…)对比,提升了服务性能。
mapstruct是在编译时完成Bean转换, 编译后在target目录,生成对应的xxximp.java文件,代码对开发人员透明,方便定位bug。
2.项目中如何引入mapstruct
<properties> <lombok.version>1.18.16</lombok.version> <org.mapstruct.version>1.4.2.Final</org.mapstruct.version> </properties> <dependencies> .... <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct</artifactId> <version>${org.mapstruct.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> <!-- other annotation processors --> <path> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> </path> <path> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-processor</artifactId> <version>${org.mapstruct.version}</version> </path> </annotationProcessorPaths> </configuration> </plugin> </plugins> </build> </project>
3 mapstruct如何使用(语法说明): 直接贴代码
3.1 方式1
/** * @Mapper 定义这是一个MapStruct对象属性转换接口,在这个类里面规定转换规则 * 在项目构建时,会自动生成改接口的实现类,这个实现类将实现对象属性值复制 */ @Mapper public interface UserRoleMapper { /** * 获取该类自动生成的实现类的实例 * 接口中的属性都是 public static final 的 方法都是public abstract的 */ UserRoleMapper INSTANCES = Mappers.getMapper(UserRoleMapper.class); /** * 这个方法就是用于实现对象属性复制的方法 * * @Mapping 用来定义属性复制规则 source 指定源对象属性 target指定目标对象属性 * * @param user 这个参数就是源对象,也就是需要被复制的对象 * @return 返回的是目标对象,就是最终的结果对象 */ @Mappings({@Mapping(source = "id",target = "userId"), @Mapping(source = "username",target = "name"), @Mapping(source = "roleName",target = "role.roleName")}) UserRoleDto toUserRoleDto(User user); }
3.2 方式2
//将bean交给spring管理, --> componentModel = "spring" //目标属性未匹配时系统忽略,不打印警告日志 -->unmappedTargetPolicy = ReportingPolicy.IGNORE // 公共的转换组件引用 --> uses = {ConvertUtil.class} @Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE, uses = {ConvertUtil.class}, componentModel = "spring") public interface CarMapper { // 转换函数的定义 @Mapping(source = "numberOfSeats", target = "seatCount") CarDto carToCarDto(Car car); 2 }
3.3 @Mapper语法小样
// 示例小样1 @Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE, uses = ConvertUtil.class, componentModel = "spring") // 指定默认值 @Mapping(target = "name", source="name", defaultValue = "我是默认值") // 使用java可执行代码或函数 @Mapping(target = "name", expression = "java(\"OT\" + paramBean.getId())") // 使用常量代替默认值 @Mapping(target = "stringConstant", constant = "Constant Value") //日期格式化 @Mapping(source = "birthday", target = "birthday", dateFormat = "yyyy-MM-dd HH:mm:ss") // Integer 到 String的转换 @Mapping(source = "price", numberFormat = "$#.00") //Date 转字符串 @Mapping(source = "currentDate", dateFormat = "dd.MM.yyyy") @Mappings({ @Mapping(source = "birthday", target = "birthday", dateFormat = "yyyy-MM-dd HH:mm:ss"), @Mapping(source = "name", target = "name") }) @IterableMapping(dateFormat = "dd.MM.yyyy") List<String> dateToString(List<Date> dates) // 引用另一个映射器类 @Mapper(uses = PrivateDateMapper.class) public class CartMapper { CartDto cartToCartDto(Cart cart); } public class DateMapper { public String asString(Date date) { ... ... } public Date toDate(String date) { ... ... } } // 示例小样2 DO 转 DTO public interface PersonDo2DtoMapping { PersonDo2DtoMapping INSTANCE = Mappers.getMapper(PersonDo2DtoMapping.class); @Mapping(source = "birthday", target = "birthday", dateFormat = "yyyy-MM-dd HH:mm:ss") PersonDto do2dto(PersonDo personDo); } // 示例小样3 DO集合 转 DTO集合: public interface PersonDo2DtoMapping { PersonDo2DtoMapping INSTANCE = Mappers.getMapper(PersonDo2DtoMapping.class); @Mapping(source = "birthday", target = "birthday", dateFormat = "yyyy-MM-dd HH:mm:ss") PersonDto do2dto(PersonDo personDo); // 会使用domain2dto方法进行对象list转换 // 集合的bean的转换本质是:转换的时候调用了do2dto方法,也就是说mapsstruct能自动的使用合适的转换方法 List<PersonDto> listToList(List<PersonDo> people); } //示例小样4 多个类型的 DO 转换为一个类型的 DTO public interface PersonDo2DtoMapping { PersonDo2DtoMapping INSTANCE = Mappers.getMapper(PersonDo2DtoMapping.class); @Mapping(source = "psersonDo.birthday", target = "birthday", dateFormat = "yyyy-MM-dd HH:mm:ss") @Mapping(source = "userDo.name", target = "name") PersonDto twoDoTOTwoDto(PersonDo personDo,UserDO userDo); } //示例小样5 自定义DO 转 DTO 的映射规则 // eg:比如的用户性别sex DO对应的是Integer类型{0:男,1:女}, DTO对应的是String类型{0:男,1:女} /**定义PersonSexConverterRule 转换规则类*/ public class PersonSexConverterRule { public String intToString(int sex) { if (sex == 0) { return "男"; } else { return "女"; } } } @Mapper(uses = PersonSexConverterRule.class) public interface PersonDo2DtoMapping { PersonDo2DtoMapping INSTANCE = Mappers.getMapper(PersonDo2DtoMapping.class); // ?? 规则作用在哪个属性上,是根据属性类型进行规则匹配的? @Mapping(source = "birthday", target = "birthday", dateFormat = "yyyy-MM-dd HH:mm:ss") PersonDto do2dto(PersonDo personDo); } //示例小样6 spring整合:需要在映射接口的mapper注解中添加参数componentModel = "spring" @Mapper(uses = PersonSexConverterRule.class,componentModel = "spring") public interface PersonDo2DtoMapping { PersonDo2DtoMapping INSTANCE = Mappers.getMapper(PersonDo2DtoMapping.class); // ?? 规则作用在哪个属性上,是根据属性类型进行规则匹配的? @Mapping(source = "birthday", target = "birthday", dateFormat = "yyyy-MM-dd HH:mm:ss") PersonDto do2dto(PersonDo personDo); }
Comments | NOTHING