• Mapstruct应用


    Mapstruct应用

    1.说明

    MapStruct是一个代码生成器,它极大地简化了基于约定优于配置方法的Java bean类型之间映射的实现。
    生成的映射代码使用普通的方法调用,因此快速、类型安全且易于理解。

    官方地址:https://mapstruct.org/

    2.应用案例

    2.1搭建maven工程引入相关依赖

        <properties>
            <maven.compiler.source>8maven.compiler.source>
            <maven.compiler.target>8maven.compiler.target>
            <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
            <org.mapstruct.version>1.4.1.Finalorg.mapstruct.version>
            <org.projectlombok.version>1.18.12org.projectlombok.version>
        properties>
    
        <dependencies>
            <dependency>
                <groupId>org.mapstructgroupId>
                <artifactId>mapstructartifactId>
                <version>${org.mapstruct.version}version>
            dependency>
    
            
            <dependency>
                <groupId>org.projectlombokgroupId>
                <artifactId>lombokartifactId>
                <version>${org.projectlombok.version}version>
                <scope>providedscope>
            dependency>
    
            
            <dependency>
                <groupId>org.mapstructgroupId>
                <artifactId>mapstruct-processorartifactId>
                <version>${org.mapstruct.version}version>
                <scope>providedscope>
            dependency>
    
        dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.pluginsgroupId>
                    <artifactId>maven-compiler-pluginartifactId>
                    <version>3.8.1version>
                    <configuration>
                        <source>1.8source>
                        <target>1.8target>
                        <annotationProcessorPaths>
                            <path>
                                <groupId>org.projectlombokgroupId>
                                <artifactId>lombokartifactId>
                                <version>${org.projectlombok.version}version>
                            path>
                            <path>
                                <groupId>org.mapstructgroupId>
                                <artifactId>mapstruct-processorartifactId>
                                <version>${org.mapstruct.version}version>
                            path>
                        annotationProcessorPaths>
                    configuration>
                plugin>
            plugins>
        build>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    关于lombok和mapstruct的版本兼容问题多说几句,maven插件要使用3.6.0版本以上、lombok使用1.16.16版本以上,另外编译的lombok mapstruct的插件不要忘了加上。否则会出现下面的错误:No property named “aaa” exists in source parameter(s). Did you mean “null”?

    这种异常就是lombok编译异常导致缺少get setter方法造成的。还有就是缺少构造函数也会抛异常。

    实体类

    @Data
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    public class Student {
    
        private String name;
        private int age;
        private GenderEnum gender;
        private Double height;
        private LocalDateTime birthday;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    枚举

    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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    VO类

    @Data
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    public class StudentVO {
        private String name;
        private int age;
        private String gender;
        private Double height;
        private String birthday;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    转换类

    @Mapper
    public interface StudentConvert {
    
        StudentConvert INSTANCE = Mappers.getMapper(StudentConvert.class);
    
        @Mapping(source = "gender.name", target = "gender")
        @Mapping(source = "birthday", target = "birthday", dateFormat = "yyyy-MM-dd HH:mm:ss")
        StudentVO student2StudentVO(Student student);
    	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    测试类

    public class Test {
    
        public static void main(String[] args) {
    
            Student student = Student.builder().name("小明").age(6).gender(GenderEnum.Male).height(121.1).birthday(LocalDateTime.now()).build();
            System.out.println(student);
            // 这行代码便是实际要用的代码
            StudentVO studentVO = StudentConvert.INSTANCE.student2StudentVO(student);
            System.out.println(studentVO);
    
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    测试结果

    image-20231007102223681

    在使用的过程中只需要短短的一行代码就可以实现类型转换,那么mapstruct帮我们做了什么,实现了类型的转换呢?来看一下编译后生成的接口实现类

    public class StudentConvertImpl implements StudentConvert {
        public StudentConvertImpl() {
        }
    
        public StudentVO student2StudentVO(Student student) {
            if (student == null) {
                return null;
            } else {
                StudentVO studentVO = new StudentVO();
                //对枚举进行了转换,实体中的枚举值转换为了对应的中文描述
                studentVO.setGender(this.studentGenderName(student));
                // 对LocalDateTime对象按照指定格式进行了转换,同理Date也是一样
                if (student.getBirthday() != null) {
                    studentVO.setBirthday(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(student.getBirthday()));
                }
    
                studentVO.setName(student.getName());
                studentVO.setAge(student.getAge());
                studentVO.setHeight(student.getHeight());
                return studentVO;
            }
        }
    
        private String studentGenderName(Student student) {
            if (student == null) {
                return null;
            } else {
                GenderEnum gender = student.getGender();
                if (gender == null) {
                    return null;
                } else {
                    String name = gender.getName();
                    return name == null ? null : name;
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    2.2List转换

    属性映射基于上面的mapping配置

    转换类添加students2StudentVOs方法

    public interface StudentConvert {
    
        StudentConvert INSTANCE = Mappers.getMapper(StudentConvert.class);
    
        @Mapping(source = "gender.name", target = "gender")
        @Mapping(source = "birthday", target = "birthday", dateFormat = "yyyy-MM-dd HH:mm:ss")
        StudentVO student2StudentVO(Student student);
    
        List<StudentVO> students2StudentVOs(List<Student> studentList);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    测试类

    public class Test {
    
        public static void main(String[] args) {
    
            Student student = Student.builder().name("小明").age(6).gender(GenderEnum.Male).height(121.1).birthday(LocalDateTime.now()).build();
    
            List<Student> list = new ArrayList<>();
            list.add(student);
            List<StudentVO> result = StudentConvert.INSTANCE.students2StudentVOs(list);
            System.out.println(result);
    
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    测试结果

    image-20231007104915014

    2.3 多对象转换到一个对象

    实体类

    • 课程
    @Data
    @AllArgsConstructor
    @Builder
    @NoArgsConstructor
    public class Course {
    
        private String courseName;
        private int sortNo;
        private long id;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 学生
    @Data
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    public class Student {
    
        private String name;
        private int age;
        private GenderEnum gender;
        private Double height;
        private LocalDateTime birthday;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    VO类

    @Data
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    public class StudentVO {
        private String name;
        private int age;
        private String gender;
        private Double height;
        private String birthday;
        private String course;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    转换类

    @Mapper
    public interface StudentConvert {
    
        StudentConvert INSTANCE = Mappers.getMapper(StudentConvert.class);
    
        @Mapping(source = "student.gender.name", target = "gender")
        @Mapping(source = "student.birthday", target = "birthday", dateFormat = "yyyy-MM-dd HH:mm:ss")
        @Mapping(source = "course.courseName", target = "course")
        StudentVO studentAndCourse2StudentVO(Student student, Course course);
    
        List<StudentVO> students2StudentVOs(List<Student> studentList);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    测试类

    public class Test {
    
        public static void main(String[] args) {
            Student student = Student.builder().name("小明").age(6).gender(GenderEnum.Male).height(121.1).birthday(LocalDateTime.now()).build();
            Course course = Course.builder().id(1L).courseName("语文").build();
    
            StudentVO studentVO = StudentConvert.INSTANCE.studentAndCourse2StudentVO(student, course);
            System.out.println(studentVO);
    
            List<Student> list = new ArrayList<>();
            list.add(student);
            List<StudentVO> result = StudentConvert.INSTANCE.students2StudentVOs(list);
            System.out.println(result);
    
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    测试结果

    image-20231007105438139

    2.4默认值

    转换类

    @Mapper
    public interface StudentConvert {
    
        StudentConvert INSTANCE = Mappers.getMapper(StudentConvert.class);
    
    
        @Mapping(source = "student.gender.name", target = "gender")
        @Mapping(source = "student.birthday", target = "birthday", dateFormat = "yyyy-MM-dd HH:mm:ss")
        @Mapping(source = "course.courseName", target = "course")
        @Mapping(target = "name", source = "student.name", defaultValue = "张三")
        StudentVO studentAndCourse2StudentVO(Student student, Course course);
    
        List<StudentVO> students2StudentVOs(List<Student> studentList);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    测试类

    public class Test {
    
        public static void main(String[] args) {
            Student student = Student.builder().age(6).gender(GenderEnum.Male).height(121.1).birthday(LocalDateTime.now()).build();
            Course course = Course.builder().id(1L).courseName("语文").build();
    
            StudentVO studentVO = StudentConvert.INSTANCE.studentAndCourse2StudentVO(student, course);
            System.out.println(studentVO);
    
            List<Student> list = new ArrayList<>();
            list.add(student);
            List<StudentVO> result = StudentConvert.INSTANCE.students2StudentVOs(list);
            System.out.println(result);
    
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    可以看到默认值对于集合的转换并不会生效

    image-20231007105946136

    编译后的接口实现类

    public class StudentConvertImpl implements StudentConvert {
        public StudentConvertImpl() {
        }
    
        public StudentVO studentAndCourse2StudentVO(Student student, Course course) {
            if (student == null && course == null) {
                return null;
            } else {
                StudentVO.StudentVOBuilder studentVO = StudentVO.builder();
                if (student != null) {
                    studentVO.gender(this.studentGenderName(student));
                    if (student.getBirthday() != null) {
                        studentVO.birthday(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(student.getBirthday()));
                    }
    
                    if (student.getName() != null) {
                        studentVO.name(student.getName());
                    } else {
                        studentVO.name("张三");
                    }
    
                    studentVO.age(student.getAge());
                    studentVO.height(student.getHeight());
                }
    
                if (course != null) {
                    studentVO.course(course.getCourseName());
                }
    
                return studentVO.build();
            }
        }
    
        public List<StudentVO> students2StudentVOs(List<Student> studentList) {
            if (studentList == null) {
                return null;
            } else {
                List<StudentVO> list = new ArrayList(studentList.size());
                Iterator var3 = studentList.iterator();
    
                while(var3.hasNext()) {
                    Student student = (Student)var3.next();
                    list.add(this.studentToStudentVO(student));
                }
    
                return list;
            }
        }
    
        private String studentGenderName(Student student) {
            if (student == null) {
                return null;
            } else {
                GenderEnum gender = student.getGender();
                if (gender == null) {
                    return null;
                } else {
                    String name = gender.getName();
                    return name == null ? null : name;
                }
            }
        }
    
        protected StudentVO studentToStudentVO(Student student) {
            if (student == null) {
                return null;
            } else {
                StudentVO.StudentVOBuilder studentVO = StudentVO.builder();
                studentVO.name(student.getName());
                studentVO.age(student.getAge());
                if (student.getGender() != null) {
                    studentVO.gender(student.getGender().name());
                }
    
                studentVO.height(student.getHeight());
                if (student.getBirthday() != null) {
                    studentVO.birthday(DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(student.getBirthday()));
                }
    
                return studentVO.build();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
  • 相关阅读:
    互联网Java工程师面试题·Memcached篇·第一弹
    【Pytorch with fastai】第 20 章 :结语与问题
    React默认工程的目录说明
    SSM基于微信小程序的实验室安全管理系统毕业设计-附源码031527
    【Pytorch实用教程】如何在多个GPU上使用分布式数据并行进行训练模型
    如何看待AIGC技术?
    类 Unix 系统的文件目录结构
    python基础-2(数据容器【列表、元组、字符串、集合、字典】)
    动态链接概述
    CCF2022版最新目录已发布,最新变动情况分析
  • 原文地址:https://blog.csdn.net/qq_44981526/article/details/133635527