1.前言大家在开发的时候,最头疼的就是:对象之间的拷贝,前端VO和数据库Entity的不一致!性能最好的是手动设置,主要是枯燥乏味,没有技术含量。不仅耗费大量时间,而且容易出错;所以,我们要想成为优秀的程序员,就要多用轮子,这样开发效率事半功倍,开发技能也增长不少!如果对系统性能没有要求,不管怎么实现都是好的,但是一定要追求,追求高质量!任何东西都有它的价值,千万不要推,不要踩!2.MapStruct简介MapStruct是一个基于JSR269的Java注解处理器,用于生成类型安全的Bean映射类。您所要做的就是定义一个映射器接口,该接口声明任何所需的映射方法。在编译期间,MapStruct将生成此接口的实现。此实现使用纯Java方法调用在源对象和目标对象之间进行映射,即没有反射或类似方法。与手动编写映射代码相比,MapStruct通过生成繁琐且容易出错的代码来节省时间。遵循configure方法的约定,MapStruct使用合理的默认值,但在配置或实现特殊行为时会误入歧途。3.优点与动态映射框架相比,MapStruct有以下优点:使用普通方法调用代替反射,执行速度快。编译时类型安全:您只能映射相互映射的对象和属性,您不会意外地将订单实体映射到客户DTO等。在构建时清除错误报告,如果映射不完整(不是alltargetpropertiesaremapped)映射不正确(找不到正确的映射方法或类型转换)可以看一下性能图:四、集成实践1、使用@Mapper将接口标记为映射接口。对于源对象和目标对象中具有不同名称的属性,可以使用注解配置名称:@Mapping按照约定,该接口声明一个成员MappersINSTANCE,它为客户端提供对映射器实现的访问。让我们详细使用它!2.这里使用最新的import依赖。如果引入lombok,可能会出现问题,就是两者都运行在编译期。如果在lombok之前执行mapstruct,会找不到get和set方法,所以会出现Problem,官网已经有解决方案!现在它将无错误地启动!org.mapstructmapstruct<版本>1.5.3.Finalorg.projectlomboklombok1.18.243.错误汇总不会自动生成impl实现类吗?我们需要添加依赖:org.mapstructmapstruct-processor1.5.3.Final重启会出现Conflictwithlombok:java:源参数中不存在名为“name”的属性。类型“UserVO”没有属性。官网解决方案文章地址:https://mapstruct.org/faq/#Can-I-use-MapStruct-together-with-Project-Lombok。org.apache.maven.pluginsmaven-compiler-plugin3.8.1<配置>1.81.8org.mapstructmapstruct-processor1.5.3。最终org.projectlomboklombok1.18.24org.projectlomboklombok-mapstruct-binding<版本>0.2.04.常见做法一张用户表:@DatapublicclassUser{privateIntegerid;私有字符串用户名;privateIntegerage;}前端用户VO:@DatapublicclassUserVO{privateIntegerid;私有字符串名称;privateIntegerage;}我们为两个对象之间的映射创建一个接口:.mapstruct.Mapping;importorg.mapstruct.factory.Mappers;/***@authorwangzhenjun*@date2023/1/2816:05*/@MapperpublicinterfaceUserMapper{UserMapperINSTANCE=Mappers.getMapper(UserMapper.class);@Mapping(source="name",target="username")UseruserVOToUser(UserVOuserVO);}可以嵌套更多属性:@Mappings({@Mapping(source="name",target="username"),@Mapping(source="name1",target="username1")})也可以:@Mapping(source="name",target="username")@Mapping(source="name1",target="username1")写测试类:@SpringBootTestclassDemoApplicationTests{@TestvoiddemoMapstruct(){UserVOuserVO=newUserVO(1,"小红",18);用户user=UserMapper.INSTANCE.userVOToUser(userVO);System.out.println(用户);}}我们看到副本没有任何问题!我们来看看它是如何实现的:mapstruct在编译时会自动生成一个实现类来帮助我们赋值,无需指定默认策略,同名复制!不一致可以像上面那样指定,不指定就没有set方法!5、常用做法2下面演示多源参数的映射方法:我们在用户类中添加一个字段:privateBigDecimalscore;添加一个新的Score类:@Data@AllArgsConstructorpublicclassScore{privateIntegerstudentId;私有BigDecimal分数;}调整上面的UserMapper接口:@Mappings({@Mapping(source="userVO.name",target="username"),@Mapping(source="score.score",target="score")})UseruserVOToUser(UserVOuserVO,Score分数);测试代码:UserVOuserVO=newUserVO(1,"小红",18);Scorescore=newScore(1,newBigDecimal(100));Useruser=UserMapper.INSTANCE。userVOToUser(userVO,score);System.out.println(用户);结果很正常:6.常见做法3我们来看一个自定义的方法,可以在企业级使用,然后赋值:场景:一个商品有长宽高,我们把长宽高从厘米到米!还有很多String到Integer、Float等的转换,都是按照下面的自定义方法实现的!VO和object是一样的!@Data@AllArgsConstructorpublicclassProductVO{privateIntegerid;私有字符串名称;私有BigDecimal长度;私有BigDecimal宽度;qualifiedByName:指定自定义方法的名称@Named("cmToM"):别名,不使用就找不到方法。可以一起写,也可以在整个工具类中写方法,在这里引用!如果使用spring,我们可以将接口作为bean注入(推荐)并添加参数启动:@Mapper(componentModel=MappingConstants.ComponentModel.SPRING)/***@authorwangzhenjun*@date2023/1/2817:13*/@Mapper(componentModel=MappingConstants.ComponentModel.SPRING)publicinterfaceProductMapper{@Mapping(source="length",target="length",qualifiedByName="cmToM")@Mapping(source="width",target="宽度",qualifiedByName="cmToM")@Mapping(source="high",target="high",qualifiedByName="cmToM")ProductproductVOToPrduct(ProductVOproductVO);@Named("cmToM")默认BigDecimalcmToM(BigDecimaloldValue){if(oldValue==null){returnBigDecimal.ZERO;}返回oldValue.divide(newBigDecimal("100"));}}测试:@SpringBootTestclassDemoApplicationTests{@AutowiredprivateProductMapperproductMapper;@TestvoiddemoMapstruct(){ProductVOproductVO=newProductVO(1,"美丽家园",newBigDecimal(100),newBigDecimal(50),newBigDecimal(8));产品product=productMapper.productVOToProduct(productVO);System.out.println(产品);}}完美转换!7、常用实战4、实战中,一个LocalDateTime和String相互转换。后面可以去官网文档找自己需要的:在刚才的商品分类中增加一个字段:privateStringcreatedAt;向VO添加一个字段:privateLocalDateTimecreatedAt;写一个转换类:这个交给spring管理,因为ProductMapper也交给spring管理,不加就找不到这个类!@ComponentpublicclassLocalDateTimeMapper{publicStringasString(LocalDateTimedate){DateTimeFormatterformatter=DateTimeFormatter.ofPattern("yyyy-MM-ddHH:mm:ss");返回日期!=null?日期.格式(格式化程序):空;}publicLocalDateTimeasLocalDateTime(Stringdate){DateTimeFormatterformatter=DateTimeFormatter.ofPattern("yyyy-MM-ddHH:mm:ss");返回日期!=null?LocalDateTime.parse(日期,格式化程序):空;}}由ProductMapper修改看一下:uses=LocalDateTimeMapper.class用我们上面写的类就可以了!@Mapper(componentModel=MappingConstants.ComponentModel.SPRING,uses=LocalDateTimeMapper.class)publicinterfaceProductMapper{@Mapping(source="length",target="length",qualifiedByName="cmToM")@Mapping(source="width",target="width",qualifiedByName="cmToM")@Mapping(source="high",target="high",qualifiedByName="cmToM")ProductproductVOToProduct(ProductVOproductVO);@Named("cmToM")默认BigDecimalcmToM(BigDecimaloldValue){if(oldValue==null){returnBigDecimal.ZERO;}返回oldValue.divide(newBigDecimal("100"));}}测试下:ProductVOproductVO=newProductVO(1,"美丽家园地图",newBigDecimal(100),newBigDecimal(50),newBigDecimal(8),LocalDateTime.now());Productproduct=productMapper.productVOToProduct(productVO);System.out.println(product);完成美化: