深入使用MapStruct |
您所在的位置:网站首页 › js编译时和运行时不一样 › 深入使用MapStruct |
前言
上一篇我们介绍了如何在java中进行对象的转换:juejin.cn/post/722518…。 其中我们重点提到了MapStruct这一工具。今天我们就来深入的了解一下MapStruct在开发中的常用功能。 功能我们先来创建用于对象转换的两个类: @Data public static class UserVO { private String fullName; private int age; private Extend extend; } @Data public static class User { private String name; private int age; private Extend extend; } @Data private static class Extend { private String email; private String address; private String phone; private String company; private String jobTitle; private String education; private String nationality; private String gender; } 复制代码 1.普通映射普通映射是将一个类映射到另外一个类上,使用简单。 如上述代码演示的两个类,我们需要把User中的属性全都复制到UserVO上去。当两个属性的名称不一致时,我们需要配置一下显示的配置一下映射关系,如下: @Mapping (source = "name", target = "fullName")。 @Mapper public interface CommonUserMapper { CommonUserMapper INSTANCE = Mappers.getMapper(CommonUserMapper.class); @Mapping(source = "name", target = "fullName") UserVO toUserVO(User user); } 复制代码其运行代码如下:UserVO userVO = CommonUserMapper.INSTANCE.toUserVO(user) 。 从运行时变量的结果截图来看,userVO对象中的extend属性和原始User中的extend的对象是同一个,说明我们在不做其他的操作时, MapStruct对类中的对象属性是浅拷贝。 要实现深度拷贝有以下办法: 新建一个和Extend类含有相同属性的新类。比如下图示例,我新建了一个ExtendVO类来进行属性的映射。MapStruct允许我们在配置映射关系时,可以配置普通参数。如下示例所示,我们将字符串参数email映射到 UserVO.Extend.email 上: @Mapping(source = "user.name", target = "fullName") @Mapping(source = "email", target = "extend.email") UserVO toUserVO(User user , String email); 复制代码这里要注意一下,当配置了参数时,在配置对象属性关系映射时,也要显示的指明对象参数的名称。如这里的 @Mapping(source = "user.name", target = "fullName") 就显示指明了 source = "user.name" 。 运行结果如下入所示: 这个映射其实和【参数引用映射】差不多,将多个实体组合成一个输出对象。 如下示例所示,我们将原始Extend对象映射到UserVO.ExtendVO上: @Mapping(source = "user.name", target = "fullName") @Mapping(source = "extend", target = "extend") UserVO toUserVO(User user , Extend extend); 复制代码这里的注意点和 【参数引用映射】差不多。 运行结果如下入所示: 从运行结果,我们看明白一件事:这种方式对于 Extend -> UserVO.ExtendVO 是属于深拷贝的。 4.嵌套释放比如我们现在的User类,其内嵌了一个Extend类,现在我们需要把UserVO中的ExtendVO展开到UserVO中,变成一个平面类,那么我们改怎么配置呢? @Mapping(source = "user.name", target = "fullName") @Mapping(source = "extend", target = ".") UserVO toUserVO1(User user); 复制代码我们使用 “ . as target” ,来实现将一个嵌套的bean的值合并到一个扁平化的对象中。 运行结果如下入所示: 上面所演示示例都是使用MapStruct给我们生成了一个对象,那么我们需要更新一个对象属性时该怎么配置呢?在业务场景中,我们可能更需要是只更新某个对象的某些属性,那么又该怎么配置呢? @Mapping( target = "fullName" ,ignore = true) @Mapping(source = "extend", target = ".") void toUserVO2(User user, @MappingTarget UserVO userVO); 复制代码经过测试我们就可以回答上面的问题了,@MappingTarget 使用改注解标记目标对象我们就可以更新该对象的值。但是有一个问题,对象更新的策略和复制是一样的,所以如果你想不更新某个值,可以给加一个 ignore = true的标签来忽略它。 6.集合、流、枚举映射 集合MapStruct还可以支持集合类型,流,枚举等数据类型的映射关系。 Map示例配置(转换每个值和键的值)请注意一下这里使用的注解是MapMapping: @MapMapping(valueDateFormat = "dd.MM.yyyy") // 数据格式转换 Map longDateMapToStringStringMap(Map source); 复制代码我们通过反编译的方式可以看到其生成的class文件代码如下: 流的映射和集合映射类似,MapStruct通过分析自动完成对应的转换逻辑。 如下面的示例(将Integer流转换成字符串集合): Set integerStreamToStringSet(Stream integers); 复制代码 枚举集合的转换比较繁琐,而且使用场景有限,用处并不是很大,了解一下即可(枚举的映射关系使用的是ValueMapping)。下面采用一个官方的示例说明: @ValueMapping(source = "EXTRA", target = "SPECIAL"), @ValueMapping(source = "STANDARD", target = "DEFAULT"), @ValueMapping(source = "NORMAL", target = "DEFAULT") ExternalOrderType orderTypeToExternalOrderType(OrderType orderType); 复制代码 7.自定义 自定义注解自定义注解的主要作用是简化我们的配置。比如我们保存和更新时需要两个转换配置(因为复制逻辑可能不一样,比如更新时:id,createTime的属性是不能改变的),但是其他属性的赋值逻辑是一致的,那么我们就可以通过自定义注解的方式来简化这个过程。我们来看一个列子: @Common UserVO toSave(User user); @Mapping(target = "age", ignore = true) @Common void toUpdate(User user, @MappingTarget UserVO userVO); @Retention(RetentionPolicy.CLASS) @Mapping(source = "user.name", target = "fullName") @Mapping(source = "extend", target = ".") public @interface Common {} 复制代码从测试可以看出来和配置可以得出结果:我们自定义的注解被 toSave() 和 toUpdate()继承了,数据符合我们的预期。 自定义表达式自定义表达式是MapStruct提供的更高级和强大的功能。其可以支持你更灵活的去生成你属性的值。 自定义常量或默认值 @Mapping:defaultValue 当源的属性值为null的值,给目标属性赋默认值。 @Mapping:constant 直接给目标属性赋值,当使用constant时,无需使用source标签。 @Mapping:ignore 可以配置那个属性被忽略,这个在为某些拷贝对象时某些属性不需要赋值时挺好用的。 自定义表达式 @Mapping:defaultExpression 当源的属性值为null的值,调用一个表达式来计算一个值给目标属性。 @Mapping:expression 给某个属性赋值表达式计算的值,同样当使用expression时,无需使用source标签。我们来举几个列子: 给person对象的id赋值一个随机UUID。 @Mapping(expression = "java( UUID.randomUUID().toString() )", target = "id") PersonDto personToDto(Person person); 复制代码 导入spring容器中的bean,并调用方法获取值并给目标属性赋值。 @Mapper(componentModel = "spring") public abstract class SimpleMapper { @Autowired protected SimpleService simpleService; @Mapping(target = "name", expression = "java(simpleService.enrichName(source.getName()))") public abstract SimpleTarget sourceToTarget(SimpleSource source); } 复制代码表达式非常灵活,大家可以自行多多研究,如果不确定映射关系是怎么样的时候,可以反编译代码查看。 最后:如果大家觉得有用,请点赞关注和收藏。你的鼓励是我更新的最大动力。 |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |