乐从容桂网站建设,网站建设公司 选中企动力公司,研究生做网站开发,山东泰安网页美化目录 1、MapStruct介绍2、应用设置2.1 Maven依赖 3、功能实战3.1 常用注解3.2 基本映射3.2.1 定义映射器的Java接口3.2.2 测试验证 3.3 参数引用映射3.3.1 定义映射器的Java接口3.3.2 测试验证 3.4 多对象参数映射3.4.1 定义映射器的Java接口3.4.2 测试验证3.4.3 注意点 3.5 嵌… 目录 1、MapStruct介绍2、应用设置2.1 Maven依赖 3、功能实战3.1 常用注解3.2 基本映射3.2.1 定义映射器的Java接口3.2.2 测试验证 3.3 参数引用映射3.3.1 定义映射器的Java接口3.3.2 测试验证 3.4 多对象参数映射3.4.1 定义映射器的Java接口3.4.2 测试验证3.4.3 注意点 3.5 嵌套映射3.5.1 定义映射器的Java接口3.5.2 测试验证3.5.3 注意点 3.6 对象更新3.6.1 定义映射器的Java接口3.6.2 测试验证3.6.3 注意点 4、性能比较4.1 Apache BeanUtils 与 MapStruct比较4.2 Hutool BeanUtil与 MapStruct比较4.3 Spring BeanUtils 与 MapStruct比较4.4 Cglib BeanCopier 与 MapStruct比较4.4 性能对比结果5次平均值 1、MapStruct介绍
MapStruct官方文档
MapStruct是一个Java注释处理器用于生成类型安全的bean映射类它基于约定优于配置方法极大地简化了 Java bean 类型之间映射的实现。您所要做的就是定义一个mapper接口该接口声明任何所需的映射方法。在编译期间MapStruct将生成此接口的实现。此实现使用普通的Java方法调用来在源对象和目标对象之间进行映射即没有反射或类似。与手工编写映射代码相比MapStruct通过生成繁琐且易于编写的代码来节省时间。遵循约定优于配置方法MapStruct使用合理的默认值但在配置或实现特殊行为时会采取措施。与动态映射框架相比MapStruct具有以下优势 通过使用普通方法调用而不是反射来快速执行 编译时类型安全只能映射相互映射的对象和属性不会将订单实体意外映射到客户DTO等。 在构建时清除错误报告如果 映射不完整并非所有目标属性都已映射 映射不正确找不到合适的映射方法或类型转换
2、应用设置
2.1 Maven依赖
?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersiongroupIdcom.siayou/groupIdartifactIdmapstruct-demo/artifactIdversion1.0-SNAPSHOT/versionpropertiesproject.build.sourceEncodingUTF-8/project.build.sourceEncodingmaven.compiler.source1.8/maven.compiler.sourcemaven.compiler.target1.8/maven.compiler.targetorg.mapstruct.version1.4.1.Final/org.mapstruct.versionorg.projectlombok.version1.18.12/org.projectlombok.version/propertiesdependenciesdependencygroupIdorg.mapstruct/groupIdartifactIdmapstruct/artifactIdversion${org.mapstruct.version}/version/dependency!-- lombok dependencies should not end up on classpath --dependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdversion${org.projectlombok.version}/versionscopeprovided/scope/dependency/dependenciesbuildpluginsplugingroupIdorg.apache.maven.plugins/groupIdartifactIdmaven-compiler-plugin/artifactIdversion3.8.1/versionconfigurationsource1.8/sourcetarget1.8/targetannotationProcessorPathspathgroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdversion${org.projectlombok.version}/version/pathpathgroupIdorg.mapstruct/groupIdartifactIdmapstruct-processor/artifactIdversion${org.mapstruct.version}/version/path/annotationProcessorPaths/configuration/plugin/plugins/build
/project3、功能实战
3.1 常用注解
Mapper 标记这个接口作为一个映射接口并且是编译时 MapStruct 处理器的入口Mapping 解决源对象和目标对象中属性名字不同的情况Mappings 当存在多个 Mapping 需要配置可以通过 Mappings 批量指定Mappers.getMapper Mapper 的 class 获取自动生成的实现对象从而让客户端可以访问 Mapper 接口的实现
3.2 基本映射
3.2.1 定义映射器的Java接口
Mapper
public interface StudentMapper {StudentMapper INSTANCE Mappers.getMapper(StudentMapper.class);//mapper可以进行字段映射改变字段类型指定格式化的方式包括一些日期的默认处理。//无论date转string,还是string转date,都是用dateFormatMapping(source gender.name, target gender)Mapping(source birthday, target birthday, dateFormat yyyy-MM-dd HH:mm:ss)StudentVO student2StudentVO(Student student);
}// Data 在编译时会自动添加 Getter、Setter、equals、canEqual、hasCode、toString 等方法高效且代码非常简洁。
// Builder 可代替需要的很多构造函数解决了某个类有很多构造函数的情况。
// AllArgsConstructor 在编译时会自动添加一个含有所有已声明字段的构造函数不必再手动编写含有所有已声明字段的构造函数。
// NoArgsConstructor 在编译时会自动添加一个无参的构造函数不必再手动编写无参构造函数。
Data
Builder
AllArgsConstructor
NoArgsConstructor
public class Student {//姓名private String name;//年龄private int age;//性别private GenderEnum gender;//身高private Double height;//生日private Date birthday;
}Data
Builder
AllArgsConstructor
NoArgsConstructor
public class StudentVO {//姓名private String name;//年龄private int age;//性别private String gender;//身高private Double height;//生日private String birthday;
}public enum GenderEnum {Male(1, 男),Female(0, 女);private String code;private String name;public String getCode() {return this.code;}public String getName() {return this.name;}GenderEnum(String code, String name) {this.code code;this.name name;}
}3.2.2 测试验证 public static void main(String[] args) {Student student Student.builder().name(张三).age(16).gender(GenderEnum.Male).height(174.3).birthday(new Date()).build();System.out.println(student);StudentVO studentVO StudentMapper.INSTANCE.student2StudentVO(student);System.out.println(studentVO);}//测试结果
Student(name张三, age16, genderMale, height174.3, birthdayFri Sep 22 16:22:38 CST 2023)
StudentVO(name张三, age16, gender男, height174.3, birthday2023-09-22 16:22:38)3.3 参数引用映射
3.3.1 定义映射器的Java接口
Data
Builder
AllArgsConstructor
NoArgsConstructor
public class StudentVO {//姓名private String name;//年龄private int age;//性别private String gender;//身高private Double height;//生日private String birthday;private ExtendDto extendDto;
}Data
Builder
AllArgsConstructor
NoArgsConstructor
public class Student {//姓名private String name;//年龄private int age;//性别private GenderEnum gender;//身高private Double height;//生日private Date birthday;private ExtendDto extendDto;
}Data
Builder
AllArgsConstructor
NoArgsConstructor
public class ExtendDto {//邮箱private String email;//地址private String address;//电话private String phone;
}Mapper
public interface StudentMapper {Mapping(source student.birthday, target birthday, dateFormat yyyy-MM-dd HH:mm:ss)Mapping(source email, target extendDto.email)StudentVO studentTwoStudentVO(Student student,String email);
}3.3.2 测试验证
public static void main(String[] args) {Student student Student.builder().name(李四).age(16).gender(GenderEnum.Male).height(174.3).birthday(new Date()).build();System.out.println(student);StudentVO studentVO StudentMapper.INSTANCE.studentTwoStudentVO(student,dmjxsy126.com);System.out.println(studentVO);}//测试结果
Student(name李四, age16, genderMale, height174.3, birthdayThu Sep 28 15:12:36 CST 2023, extendDtonull)
StudentVO(name李四, age16, genderMale, height174.3, birthday2023-09-28 15:12:36, extendDtoExtendDto(emaildmjxsy126.com, addressnull, phonenull))3.4 多对象参数映射
3.4.1 定义映射器的Java接口 Mapping(source student.birthday, target birthday, dateFormat yyyy-MM-dd HH:mm:ss)Mapping(source extendDto, target extendDto)StudentVO studentMapStudentVO(Student student,ExtendDto extendDto);3.4.2 测试验证 public static void main(String[] args) {Student student Student.builder().name(李四).age(16).gender(GenderEnum.Male).height(174.3).birthday(new Date()).build();ExtendDto extendDto ExtendDto.builder().email(dmjxsy126.com).phone(119).address(陕西).build();System.out.println(student);System.out.println(extendDto);StudentVO studentVO StudentMapper.INSTANCE.studentMapStudentVO(student,extendDto);System.out.println(studentVO);
}//测试结果
Student(name李四, age16, genderMale, height174.3, birthdayThu Sep 28 15:24:18 CST 2023, extendDtonull)
ExtendDto(emaildmjxsy126.com, address陕西, phone119)
StudentVO(name李四, age16, genderMale, height174.3, birthday2023-09-28 15:24:18, extendDtoExtendDto(emaildmjxsy126.com, address陕西, phone119))}3.4.3 注意点 当配置了参数时在配置对象属性关系映射时也要显示的指明对象参数的名称。如Mapping(source “student.birthday”, target “birthday”) 就显示指明了 source “student.birthday” 。 3.5 嵌套映射
3.5.1 定义映射器的Java接口 Mapping(source student.birthday, target birthday, dateFormat yyyy-MM-dd HH:mm:ss)Mapping(source extendDto, target .)StudentVO studentMapStudentVO(Student student);3.5.2 测试验证 public static void main(String[] args) {Student student Student.builder().name(李四).age(16).gender(GenderEnum.Male).height(174.3).birthday(new Date()).extendDto( ExtendDto.builder().email(dmjxsy126.com).phone(110).address(陕西).build()).build();System.out.println(student);StudentVO studentVO StudentMapper.INSTANCE.studentMapStudentVO(student);System.out.println(studentVO);}
//测试结果
Student(name李四, age16, genderMale, height174.3, birthdayThu Sep 28 15:31:14 CST 2023, extendDtoExtendDto(emaildmjxsy126.com, address陕西, phone110))
StudentVO(name李四, age16, genderMale, height174.3, birthday2023-09-28 15:31:14, extendDtoExtendDto(emaildmjxsy126.com, address陕西, phone110))
3.5.3 注意点 使用 “ . ” 将一个嵌套的bean的值合并到一个扁平化的对象中。 3.6 对象更新
3.6.1 定义映射器的Java接口 Mapping(source student.birthday, target birthday, dateFormat yyyy-MM-dd HH:mm:ss)Mapping(source extendDto, target .)
// Mapping(source name,target name, ignore true)void updateStudent(Student student,MappingTarget StudentVO studentVO);Mapping(source student.birthday, target birthday, dateFormat yyyy-MM-dd HH:mm:ss)Mapping(source extendDto, target .)Mapping(source name,target name, ignore true)void updateStudent(Student student,MappingTarget StudentVO studentVO);3.6.2 测试验证
public static void main(String[] args) {Student student Student.builder().name(李四).age(16).gender(GenderEnum.Male).height(174.3).birthday(new Date()).extendDto( ExtendDto.builder().email(dmjxsy126.com).phone(110).address(陕西).build()).build();StudentVO studentVO StudentVO.builder().name(王五).age(20).height(204.3).birthday(2020-01-01 12:11:11).extendDto( ExtendDto.builder().email(dmjxsy163.com).phone(110110119).address(陕西西安).build()).build();System.out.println(更新前 student:student.toString());System.out.println(更新前 studentVO:studentVO.toString());StudentMapper.INSTANCE.updateStudent(student,studentVO);System.out.println(更新后 student:student.toString());System.out.println(更新后 studentVO:studentVO.toString());}
//测试结果
更新前 :Student(name李四, age16, genderMale, height174.3, birthdayThu Sep 28 15:56:35 CST 2023, extendDtoExtendDto(emaildmjxsy126.com, address陕西, phone110))
更新前 :StudentVO(name王五, age20, gendernull, height204.3, birthday2020-01-01 12:11:11, extendDtoExtendDto(emaildmjxsy163.com, address陕西西安, phone110110119))
更新后 :Student(name李四, age16, genderMale, height174.3, birthdayThu Sep 28 15:56:35 CST 2023, extendDtoExtendDto(emaildmjxsy126.com, address陕西, phone110))
更新后 :StudentVO(name李四, age16, genderMale, height174.3, birthday2023-09-28 15:56:35, extendDtoExtendDto(emaildmjxsy126.com, address陕西, phone110))
//添加 Mapping(source name,target name, ignore true)
更新前 :Student(name李四, age16, genderMale, height174.3, birthdayThu Sep 28 15:57:39 CST 2023, extendDtoExtendDto(emaildmjxsy126.com, address陕西, phone110))
更新前 :StudentVO(name王五, age20, gendernull, height204.3, birthday2020-01-01 12:11:11, extendDtoExtendDto(emaildmjxsy163.com, address陕西西安, phone110110119))
更新后 :Student(name李四, age16, genderMale, height174.3, birthdayThu Sep 28 15:57:39 CST 2023, extendDtoExtendDto(emaildmjxsy126.com, address陕西, phone110))
更新后 :StudentVO(name王五, age16, genderMale, height174.3, birthday2023-09-28 15:57:39, extendDtoExtendDto(emaildmjxsy126.com, address陕西, phone110))
3.6.3 注意点 MappingTarget 使用改注解标记目标对象我们就可以更新该对象的值。如果想不更新某个值可以给加一个ignore true的标签来忽略。 4、性能比较
4.1 Apache BeanUtils 与 MapStruct比较 public static void main(String[] args) throws InvocationTargetException, IllegalAccessException {for (int i 0; i 10; i) {Long start System.currentTimeMillis();for (int i1 0; i1 1000000; i1) {Student student Student.builder().name(小明).age(6).gender(GenderEnum.Male).height(121.1).birthday(new Date()).build();StudentVO studentVO new StudentVO();org.apache.commons.beanutils.BeanUtils.copyProperties(studentVO, student);}System.out.println(org.apache.commons.beanutils.BeanUtils第 i 次执行---100W次转换耗时: (System.currentTimeMillis() - start));Long start2 System.currentTimeMillis();for (int i1 0; i1 1000000; i1) {Student student Student.builder().name(小明).age(6).gender(GenderEnum.Male).height(121.1).birthday(new Date()).build();StudentMapper.INSTANCE.student2StudentVO(student);}System.out.println(MapStruct第 i 次执行-----100W次转换耗时: (System.currentTimeMillis() - start2));}}
//测试结果
org.apache.commons.beanutils.BeanUtils第0次执行---100W次转换耗时:11854
MapStruct第0次执行-----100W次转换耗时:1981
org.apache.commons.beanutils.BeanUtils第1次执行---100W次转换耗时:10828
MapStruct第1次执行-----100W次转换耗时:2080
org.apache.commons.beanutils.BeanUtils第2次执行---100W次转换耗时:9894
MapStruct第2次执行-----100W次转换耗时:1891
org.apache.commons.beanutils.BeanUtils第3次执行---100W次转换耗时:9543
MapStruct第3次执行-----100W次转换耗时:1735
org.apache.commons.beanutils.BeanUtils第4次执行---100W次转换耗时:6862
MapStruct第4次执行-----100W次转换耗时:19584.2 Hutool BeanUtil与 MapStruct比较
public static void main(String[] args) throws InvocationTargetException, IllegalAccessException {for (int i 0; i 5; i) {Long start System.currentTimeMillis();for (int i1 0; i1 1000000; i1) {Student student Student.builder().name(小明).age(6).gender(GenderEnum.Male).height(121.1).birthday(new Date()).build();StudentVO studentVO new StudentVO();cn.hutool.core.bean.BeanUtil.copyProperties(studentVO,student,true);}System.out.println(cn.hutool.core.bean.BeanUtil第 i 次执行---100W次转换耗时: (System.currentTimeMillis() - start));Long start2 System.currentTimeMillis();for (int i1 0; i1 1000000; i1) {Student student Student.builder().name(小明).age(6).gender(GenderEnum.Male).height(121.1).birthday(new Date()).build();StudentMapper.INSTANCE.student2StudentVO(student);}System.out.println(MapStruct第 i 次执行-----100W次转换耗时: (System.currentTimeMillis() - start2));}}
//测试结果
cn.hutool.core.bean.BeanUtil第0次执行---100W次转换耗时:7169
MapStruct第0次执行-----100W次转换耗时:2538
cn.hutool.core.bean.BeanUtil第1次执行---100W次转换耗时:4797
MapStruct第1次执行-----100W次转换耗时:1707
cn.hutool.core.bean.BeanUtil第2次执行---100W次转换耗时:5582
MapStruct第2次执行-----100W次转换耗时:1505
cn.hutool.core.bean.BeanUtil第3次执行---100W次转换耗时:4906
MapStruct第3次执行-----100W次转换耗时:1322
cn.hutool.core.bean.BeanUtil第4次执行---100W次转换耗时:3789
MapStruct第4次执行-----100W次转换耗时:16354.3 Spring BeanUtils 与 MapStruct比较 public static void main(String[] args) throws InvocationTargetException, IllegalAccessException {for (int i 0; i 5; i) {Long start System.currentTimeMillis();for (int i1 0; i1 1000000; i1) {Student student Student.builder().name(小明).age(6).gender(GenderEnum.Male).height(121.1).birthday(new Date()).build();StudentVO studentVO new StudentVO();org.springframework.beans.BeanUtils.copyProperties(studentVO, student);}System.out.println(org.springframework.beans.BeanUtils第 i 次执行---100W次转换耗时: (System.currentTimeMillis() - start));Long start2 System.currentTimeMillis();for (int i1 0; i1 1000000; i1) {Student student Student.builder().name(小明).age(6).gender(GenderEnum.Male).height(121.1).birthday(new Date()).build();StudentMapper.INSTANCE.student2StudentVO(student);}System.out.println(MapStruct第 i 次执行-----100W次转换耗时: (System.currentTimeMillis() - start2));}}
//测试结果
org.springframework.beans.BeanUtils第0次执行---100W次转换耗时:1156
MapStruct第0次执行-----100W次转换耗时:3376
org.springframework.beans.BeanUtils第1次执行---100W次转换耗时:290
MapStruct第1次执行-----100W次转换耗时:1367
org.springframework.beans.BeanUtils第2次执行---100W次转换耗时:506
MapStruct第2次执行-----100W次转换耗时:1586
org.springframework.beans.BeanUtils第3次执行---100W次转换耗时:318
MapStruct第3次执行-----100W次转换耗时:1319
org.springframework.beans.BeanUtils第4次执行---100W次转换耗时:304
MapStruct第4次执行-----100W次转换耗时:12264.4 Cglib BeanCopier 与 MapStruct比较 public static void main(String[] args) throws InvocationTargetException, IllegalAccessException {for (int i 0; i 5; i) {Long start System.currentTimeMillis();for (int i1 0; i1 1000000; i1) {Student student Student.builder().name(小明).age(6).gender(GenderEnum.Male).height(121.1).birthday(new Date()).build();StudentVO studentVO new StudentVO();org.springframework.cglib.beans.BeanCopier.create(StudentVO.class, Student.class, false);}System.out.println(org.springframework.cglib.beans.BeanCopier第 i 次执行---100W次转换耗时: (System.currentTimeMillis() - start));Long start2 System.currentTimeMillis();for (int i1 0; i1 1000000; i1) {Student student Student.builder().name(小明).age(6).gender(GenderEnum.Male).height(121.1).birthday(new Date()).build();StudentMapper.INSTANCE.student2StudentVO(student);}System.out.println(MapStruct第 i 次执行-----100W次转换耗时: (System.currentTimeMillis() - start2));}}//测试结果
org.springframework.cglib.beans.BeanCopier第0次执行---100W次转换耗时:725
MapStruct第0次执行-----100W次转换耗时:4524
org.springframework.cglib.beans.BeanCopier第1次执行---100W次转换耗时:210
MapStruct第1次执行-----100W次转换耗时:1663
org.springframework.cglib.beans.BeanCopier第2次执行---100W次转换耗时:72
MapStruct第2次执行-----100W次转换耗时:1446
org.springframework.cglib.beans.BeanCopier第3次执行---100W次转换耗时:80
MapStruct第3次执行-----100W次转换耗时:1482
org.springframework.cglib.beans.BeanCopier第4次执行---100W次转换耗时:84
MapStruct第4次执行-----100W次转换耗时:14414.4 性能对比结果5次平均值
工具类执行1000执行1w执行10w执行100wApache BeanUtils103.2323.31105.87227.8Hutool BeanUtil111249.2925.44420.6Spring BeanUtils8093.4206.4728.6Cglib BeanCopier86.4103.8103.8263MapStruct53.6137.8447.82672.2