我们有这样一个场景,有一个 StudentDto
类,还有一个 StudentVo
类
| @Data |
| public class StudentDto { |
| private String id; |
| private String code; |
| private String sex; |
| private String userName; |
| } |
| @Data |
| public class StudentVo { |
| private String id; |
| private String name; |
| private String code; |
| private String age; |
| private String score; |
| private String sex; |
| } |
“
如果我们知道 StudentVo
的值,需要将 StudentVo
的属性拷贝到 StudentDto
中,你会怎么做。
”
StudentVo
的值如下
| public StudentVo initVo() { |
| StudentVo studentVo = new StudentVo(); |
| studentVo.setId("1"); |
| studentVo.setAge("27"); |
| studentVo.setName("Lvshen"); |
| studentVo.setCode("001"); |
| studentVo.setScore("100"); |
| studentVo.setSex("male"); |
| return studentVo; |
| } |
传统的解决方法,通过 getter/setter
方法将对应的属性值进行拷贝。
| @org.junit.Test |
| public void test3() { |
| StudentVo studentVo = initVo(); |
| StudentDto studentDto = new StudentDto(); |
| studentDto.setCode(studentVo.getCode()); |
| studentDto.setId(studentVo.getId()); |
| studentDto.setSex(studentVo.getSex()); |
| studentDto.setUserName(studentVo.getName()); |
| |
| System.out.println(studentDto); |
| } |
测试结果
看了上面的方法,你可能觉得不是很简单么。但如果属性非常多,比如有 20 多个。用上面的方法就会不美观,满屏的 getter/setter
方法,看着都眼花。
这时我们就可以使用 BeanUtils.copyProperties
方法啦,这里的 BeanUtils
是 Spring 的,而不是 apache
的。
| @org.junit.Test |
| public void test2() { |
| StudentVo studentVo = initVo(); |
| StudentDto studentDto = new StudentDto(); |
| BeanUtils.copyProperties(studentVo,studentDto); |
| |
| System.out.println(studentDto); |
| } |
测试结果
我们还可以使用性能更优越的 MapStruct
,你可能没有听过这个东西。没关系,我们直接上代码。
MapStruct 是一个可以生成类型安全的,高性能的且无依赖的 JavaBean 映射代码的注解处理器,可以在编译期生成对应的 mapping,既没有 BeanUtils 等工具使用反射的性能问题,又免去了自己写映射代码的繁琐。
引入 Maven 依赖
| <dependency> |
| <groupId>org.mapstruct</groupId> |
| <artifactId>mapstruct</artifactId> |
| <version>1.3.1.Final</version> |
| </dependency> |
| |
| <dependency> |
| <groupId>org.mapstruct</groupId> |
| <artifactId>mapstruct-processor</artifactId> |
| <version>1.3.1.Final</version> |
| </dependency> |
我们先编写一个 StudentConverter
类
| @Mapper |
| public interface StudentConverter { |
| StudentConverter INSTANCE = Mappers.getMapper(StudentConverter.class); |
| |
| @Mappings(@Mapping(source = "name",target = "userName")) |
| StudentDto vo2dto(StudentVo vo); |
| } |
这里的 @Mapper
来源于 org.mapstruct.Mapper
,用来说明这是一个实体转换类接口。
@Mappings
用来声明成员属性的映射,source = "name",target = "userName"
即将 StudentVo
中 name
的值拷贝给 StudentDto
中的 userName
,如果属性名称相同,就不需要做这个映射。
测试结果
| @org.junit.Test |
| public void test1() { |
| StudentVo studentVo = initVo(); |
| StudentDto studentDto = StudentConverter.INSTANCE.vo2dto(studentVo); |
| |
| System.out.println(studentDto); |
| } |
你以为 MapStruct
只能进行实体之间的拷贝?NO,MapStruct
还可以进行 List 之间的拷贝,这个就太牛了。
| @Mapper |
| public interface StudentConverter { |
| StudentConverter INSTANCE = Mappers.getMapper(StudentConverter.class); |
| |
| @Mappings(@Mapping(source = "name",target = "userName")) |
| StudentDto vo2dto(StudentVo vo); |
| |
| List<StudentDto> listVo2dto(List<StudentVo> vos); |
| } |
测试
| public void test() { |
| List<StudentVo> voList = initVoList(); |
| List<StudentDto> studentDtos = StudentConverter.INSTANCE.listVo2dto(voList); |
| System.out.println(studentDtos); |
| } |
测试结果
当然 MapStruct
等功能远比你想象的要多,有兴趣的可以看看这篇文章
“
https://www.cnblogs.com/homejim/p/11313128.html
”
市面上 BeanUtils
底层是使用反射的,我们知道使用反射会影响性能。而且 BeanUtils
需要类型和名称都一样才会进行映射, 但在很多时候, 由于不同的团队之间使用的名词不一样, 还是需要很多的手动使用 getter/setter
。
于是 MapStruct
诞生了。
MapSturct
是一个生成类型安全, 高性能且无依赖的 JavaBean 映射代码的注解处理器(annotation processor)。
它有下面几个特点:
“
- 基于注解的处理器
- 可以自定义
JavaBean
之间的属性映射 - 类型安全, 高性能, 无依赖性
”
编译之后会生成方法实现
实现的类、方法如下
该工具可以帮我们实现 JavaBean
之间的转换, 通过注解的方式。通过 MapStruct
来生成的代码, 其类似于人手写。速度上可以得到保证。