• MapStruct代码生成器使用


    MapStruct代码生成器使用

    DTO,Entity,VO,POJO,PO

    PO(Persistent Object):持久化对象,常在Dao层中使用
    Entity:实体类
    DTO(Data Transfer Object):Service层中使用,表示数据传输对象
    VO(View Object):表示层对象,是页面显示的数据对象,即数据返回
    POJO(Plain Ordinary Java Object):中间对象,随意转换为各类对象
    一般来说,这些类有大量重复的代码,他们之间进行转换会频繁调用get和set方法,MapStruct应运而生

    官方网址

    https://mapstruct.org/

    什么是MapStruct

    一个代码生成器,它基于约定优于配置的方法,极大地简化了 Java bean 类型之间的映射实现。

    生成的映射代码使用简单的方法调用,因此速度快、类型安全且易于理解。

    为什么要使用MapStruct

    1. 多层应用程序通常需要在不同的对象模型(例如实体和 DTO)之间进行映射。 编写这样的映射代码是一项乏味且容易出错的任务。 MapStruct 旨在通过尽可能地自动化来简化这项工作。
    2. 与其他映射框架相比,MapStruct 在编译时生成 bean 映射,这确保了高性能,允许快速的开发人员反馈和彻底的错误检查。
    3. 群体使用量大
    4. Dozer已经不再维护
    5. 高性能,解耦,适应开发

    QuickStart

    1.引入依赖

    <!-- https://mvnrepository.com/artifact/org.mapstruct/mapstruct -->
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct</artifactId>
        <version>1.5.2.Final</version>
    </dependency>
    
    <!-- https://mvnrepository.com/artifact/org.mapstruct/mapstruct-processor -->
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct-processor</artifactId>
        <version>1.5.2.Final</version>
    </dependency>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    2.设置两个类,这两个类直接需要转换

    UserDTO

    package com.example.dozer.dto;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class UserDTO {
        private String username;
        private String password;
        private int age;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    User

    package com.example.dozer.entity;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
        private String name;
        private String pwd;
        private int age;
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    3.编写转换的Mapper接口

    package com.example.dozer.mapper;
    
    import com.example.dozer.dto.UserDTO;
    import com.example.dozer.entity.User;
    import org.mapstruct.Mapper;
    import org.mapstruct.Mapping;
    import org.mapstruct.factory.Mappers;
    
    @Mapper
    public interface UserConvertMapper {
        //获取mapper对象使用mapStruct的Mappers.getMapper()
         UserConvertMapper instance = Mappers.getMapper(UserConvertMapper.class);
        //转化UserDTO-->User
        User userConvert(UserDTO userDTO);
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    4.编写测试

    package com.example.dozer.controller;
    
    import com.example.dozer.dto.UserDTO;
    import com.example.dozer.entity.User;
    import com.example.dozer.mapper.UserConvertMapper;
    
    public class TestController {
        public static void main(String[] args) {
            //模拟数据
            UserDTO userDTO = new UserDTO();
            userDTO.setUsername("zhangsan");
            userDTO.setPassword("1246asd");
            userDTO.setAge(16);
            //获取实例进行转换
            User user = UserConvertMapper.instance.userConvert(userDTO);
            System.out.println(user);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在这里插入图片描述

    结果解释

    如上方代码我们有两个类,UserDTO和User,两者需要进行转化,但是User和UserDTO相比,有两个属性不同
    在这里插入图片描述
    按照MapStruct默认规则(@Mapper注解实现自动转化)无法进行转化所以为null
    而age属性名称相同所以可以转化
    到这里大家别嫌MapStruct菜,怎么也不能直接一步搞定,你自己想想,程序又不是人,他怎么知道你的属性名称的对应呢!
    所以我们继续。。。。

    了解默认规则

    MapStruct能够自动进行类型转换的类型

    1. 8种基础类型及包装类之间能够自动转换
    2. 8种基础类型和String之间能自动转换
    3. 8种包装类型和String之间能自动转换
    4. 日期类型和String之间可以自动转换

    自定义进行映射规则

    我们使用@Mappings@Mapping的配合使用完成自定义映射

    实例

    以下我们修改上方QuickStart中的Mapper接口,在转换方法上使用@Mappings配合@Mapping进行自定义映射规则使用
    但你也可以直接写多个@Mapping不需要使用@Mappings包裹

    package com.example.dozer.mapper;
    
    import com.example.dozer.dto.UserDTO;
    import com.example.dozer.entity.User;
    import org.mapstruct.Mapper;
    import org.mapstruct.Mapping;
    import org.mapstruct.Mappings;
    import org.mapstruct.factory.Mappers;
    
    @Mapper
    public interface UserConvertMapper {
        //获取mapper对象使用mapStruct的Mappers.getMapper()
        UserConvertMapper instance = Mappers.getMapper(UserConvertMapper.class);
    
        //转化UserDTO-->User
        @Mappings(
                {
                        @Mapping(source = "username", target = "name"),
                        @Mapping(source = "password", target = "pwd")
                }
        )
        User userConvert(UserDTO userDTO);
    
    }
    
    
    • 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

    再次测试转化成功
    在这里插入图片描述

    @Mapping

    用于设定自定义的映射规则
    参数如下:

    1. source:源对象属性
    2. target:目标对象属性
    3. numberFormat:数字格式化策略
    4. dateFormat:日期格式化策略
    5. ignore:忽略属性不进行转化@Mapping(target="xxx",ignore=true)

    如何进行引用类型的转化?

    其实不用想的太复杂,引用类型也是基础类型构成的所以我们只要完成引用类型内部转化即可完成引用类型的转换了!

    实例

    User

    package com.example.dozer.entity;
    
    import com.example.dozer.po.UserPO;
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
        private String name;
        private String pwd;
        private int age;
        private UserPO userPO;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    UserDTO

    package com.example.dozer.dto;
    
    import com.example.dozer.pojo.UserPojo;
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class UserDTO {
        private String username;
        private String password;
        private int age;
        private UserPojo userPojo;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    UserPO

    package com.example.dozer.po;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class UserPO {
        private String cname;
        private int age;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    UserPojo

    package com.example.dozer.pojo;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class UserPojo {
        private String childName;
        private int age;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    转化mapper接口

    package com.example.dozer.mapper;
    
    import com.example.dozer.dto.UserDTO;
    import com.example.dozer.entity.User;
    import com.example.dozer.po.UserPO;
    import com.example.dozer.pojo.UserPojo;
    import org.mapstruct.Mapper;
    import org.mapstruct.Mapping;
    import org.mapstruct.Mappings;
    import org.mapstruct.factory.Mappers;
    
    @Mapper
    public interface UserConvertMapper {
        //获取mapper对象使用mapStruct的Mappers.getMapper()
        UserConvertMapper instance = Mappers.getMapper(UserConvertMapper.class);
    
        //转化UserDTO-->User
        @Mappings(
                {
                        @Mapping(source = "username", target = "name"),
                        @Mapping(source = "password", target = "pwd"),
                        @Mapping(source = "userPojo" ,target = "userPO")
                }
        )
        User userConvert(UserDTO userDTO);
    
        @Mapping(source = "childName",target = "cname")
        UserPO userPojoToPO(UserPojo userPojo);
    }
    
    
    • 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

    测试

    package com.example.dozer.controller;
    
    import com.example.dozer.dto.UserDTO;
    import com.example.dozer.entity.User;
    import com.example.dozer.mapper.UserConvertMapper;
    import com.example.dozer.pojo.UserPojo;
    
    public class TestController {
        public static void main(String[] args) {
            //模拟数据
            UserDTO userDTO = new UserDTO();
            userDTO.setUsername("zhangsan");
            userDTO.setPassword("1246asd");
            userDTO.setUserPojo(new UserPojo("cc",2));
            userDTO.setAge(16);
            //获取实例进行转换
            User user = UserConvertMapper.instance.userConvert(userDTO);
            System.out.println(user);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    在这里插入图片描述

    使用@AfterMapping实现属性自定义映射处理

    @AfterMapping表示让MapStruct在调用完自动转化方法后再调用这个方法
    如下,我设置一个若值为空则默认填入default字符串的方法

        @AfterMapping
         default void UserDTOToUser(UserDTO userDTO, @MappingTarget User user){
            if ("".equals(userDTO.getUsername())||userDTO.getUsername()==null){
                user.setName("default");
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    集合批量转换

    我们只需要设置如下示例类似的写法即可

    List<UserDTO> userToUserDto(List<User> userList)
    
    • 1

    没错就是这么简单,因为我们在前面设置了UserDTO转为User的方法,所以批量本质实际就是多次的调用单个转换

    @BeanMapping

    目的是为了完全自主的进行操作,更加灵活自由完成业务逻辑
    主要属性:
    ignoreByDefalut:忽略默认映射行为,避免不必要赋值、覆盖等操作

    @InheritConfiguration实现继承

    在方法上使用@InheritConfiguration就可以实现在我们写相同逻辑时直接继承原始方法上的@Mapping注解声明的内容,然后其他自己定义即可

     @InheritConfiguration
     void updateUserToUserDTO(User user,@MappingTarget UserDTO userDto)
    
    • 1
    • 2

    @InheritInverseConfiguration反向映射

    即我不用再在需要反向映射的方法上设置@Mapping进行源和目标的设置,直接使用该注解完成
    比如我已经写好了UserDTO转User的我使用这个注解可以直接完成User转UserDTO的方法不需要再写一遍反向的@Mapping配置了
    我们要做到只要设置一下name属性,标注对哪个方法进行反向映射即可

    @InheritInverseConfiguration(name="userToUserDTO")
    User userDTOTOUser(UserDTO userDTO);
    
    • 1
    • 2

    @Mapper

    我们通过前面的使用知道@Mapper就是用来标注当前类或接口一个MapStruct的转化Mapper
    当我们需要在Spring中进行使用时,我们需要指明@Mapper注解中的一个参数:componentModel = "spring"即可

    @Mapper(componentModel = "spring")
    public interface UserConvertMapper {}
    
    • 1
    • 2

    设置好之后就可以在类中使用@AutoWired进行注入
    实质上就是生成了@Component注解,所以说我们还可以通过加@Component实现注入

  • 相关阅读:
    LeetCode 热题 HOT 100 第八十一天 647. 回文子串 用python3求解
    【网络爬虫笔记】爬虫Robots协议语法详解
    39、一篇文章弄懂 Java 正则表达式中的量词、贪婪、勉强、独占和 String 的 matches 方法的底层【个人感觉非常值得学习】
    HDU-1698 Just a Hook(线段树区间更新)
    云原生之容器化:Docker三剑客之Docker Machine
    使用 OpenCV 构建文档扫描仪
    QT小记:QT程序异常结束的可能原因
    Vue复习笔记 (二)SPA单页面应用(优化首屏加载)
    合并区间:解决区间重叠问题的高效算法
    幂等设计的应用
  • 原文地址:https://blog.csdn.net/qq_51553982/article/details/126288390