MapStruct简单介绍
MapStruct 是一个属性映射工具,只需要定义一个 Mapper
接口,MapStruct 就会自动实现
这个映射接口,避免了复杂繁琐的映射实现。
在一个Java工程中会涉及到多种对象,po、vo、dto、entity、do、domain这些定义的对象运用在不同的场景模块中,这种对象与对象之间的互相转换,就需要有一个专门用来解决转换问题的工具。以往的方式要么是自己写转换器,要么是用Apache或Spring的BeanUtils来实现转换。无论哪种方式都存在明显的缺点,比如手写转换器既浪费时间, 而且在添加新的字段的时候也要进行方法的修改;而无论是 BeanUtils, BeanCopier 等都是使用反射来实现,效率低下并且仅支持属性名一致时的转换。
MapSturct 是一个生成类型安全, 高性能且无依赖的 JavaBean 映射代码的注解处理器。作为一个工具类,相比于手写,其具有便捷,不容易出错的特点。
MapStruct的使用
引入依赖
maven工程需要在pom文件中引入以下依赖
<properties><mapstruct.version>1.3.0.Final</mapStruct.version></properties><dependencies><dependency><groupId>org.mapstruct</groupId><artifactId>mapstruct-jdk8</artifactId><version>${mapstruct.version}</version></dependency><dependency><groupId>org.mapstruct</groupId><artifactId>mapstruct-processor</artifactId><version>${mapstruct.version}</version></dependency></dependencies>
基本使用
定义数据实体
@Data@AllArgsConstructor@TableName("user")publicclassUser{@TableId(value="id",type=IdType.AUTO)privateLongid;@TableField("user_name")privateStringuserName;@TableField("gender")privateIntegergender;@TableField("age")privateIntegerage;@TableField("flag")privateIntegerflag;}
定义转换实体
@DatapublicclassUserDto{privateLongid;privateStringname;privateStringgender;privateIntegerage;}
编写转换接口
@MapperpublicinterfaceUserMapStruct{UserMapStructINSTANCE=Mappers.getMapper(UserMapStruct.class);/***单一对象的转换*这里模拟两种情况:1、属性名不一致2、使用表达式将实体类的性别int类型转成枚举中定义的性别的String类型释义*/@Mapping(source="userName",target="name")@Mapping(target="gender",expression="java(com.rameo.mapstruct.GenderEnum.desc(user.getGender()))")//支持表达式UserDtouserToDto(Useruser);/***对象集合的转换*/List<UserDto>userToDtoList(List<User>userList);}
编写测试方法
@RunWith(SpringRunner.class)@SpringBootTestpublicclassUserMapStructTest{privateUseruser;@Beforepublicvoidbefore(){user=newUser(1L,"sw","shenzhen",11,1);}@Testpublicvoidtest(){UserDtouserDto=UserMapStruct.INSTANCE.userToDto(user);Assert.assertNotNull(userDto);Assert.assertEquals(userDto.getId(),1);Assert.assertEquals(userDto.getName(),"sw");Assert.assertEquals(userDto.getCity(),"shenzhen");Assert.assertEquals(userDto.getAge(),12);}}
以上示例参考MapStruct官网的例子,例子中使用了lombok插件,请自行添加相关依赖和插件后使用。
MapStruct原理说明
在 target/generated-sources/annotations
里可以看到,代码中可以看到其生成了一个实现类
, 而代码也类似于我们手写。这个在编译期生成的代码,性能比反射要快不少。
MapStruct是利用编译期动态生成set/get代码的class文件 ,在运行时直接调用该class文件。 该方式实际上仍会存在set/get代码,只是不需要自己手写。
MapStruct 转换方式
属性名称相同,直接转化,类似BeanUtils的转换防守
属性名不相同, 可通过 @Mapping 注解进行指定转化 例 @Mapping(source = "userName", target = "name")
MapStruct使用注意
当多个对象中,有其中一个为 null,则会直接返回 null
如一对一转换一样,属性通过名字来自动匹配。因此,名称和类型相同的不需要进行特殊处理
当多个原对象中,有相同名字的属性时,需要通过 @Mapping 注解来具体的指定,以免出现歧义
当有多个属性不一致时,有两种解决方式
添加多个@Mapping(推荐)
用@Mappings将多个@Mapping包起来(sonar检测会告警,不影响使用)
参考资料
官网:mapstruct.org/
Github地址:https://github.com/mapstruct/mapstruct/
实例分享:https://github.com/mapstruct/mapstruct-examples