MapStruct---多级嵌套结构的例子

        大家都知道MapStruct

在Java中用来做不同对象之间的转换(DTO,DO,BO,VO...),使用方式简单,只需要按规则写一个相关接口,甚至不需要实现(较类似于jpa的JpaRepository接口的使用方式),就能直接完成对象间的转换。

今天一起聊一下多级嵌套映射的例子
以下是官方介绍(摘要):官方文档链接 MapStruct官网

MapStruct 是一个 Java 注释处理器,用于生成类型安全的 bean 映射类。
您所要做的就是定义一个映射器接口,该接口可以声明任何您所需的映射方法。在编译期间,MapStruct 将生成此接口的实现。这个实现使用普通的 Java 方法调用(get,set方法)来映射源对象和目标对象,而不是使用反射

优点:

  1. 与手动编写映射代码相比,MapStruct 通过生成编写繁琐且容易出错的代码来节省时间。
  2. 编译时类型安全:只能映射相互映射的对象和属性,不能将订单实体意外映射到客户 DTO 等。
  3. 当出现以下情况,程序在编译期间就会给出提示。
           映射不完整(并非所有目标属性都被映射)
           映射不正确(找不到合适的映射方法或类型转换)

引入依赖(maven)

这里需要注意:idea版本不同,引入的依赖和配置也有一些小差别,这里我的idea版本是 2019.3,其他版本idea可以先按着这个配置写,有问题的话,参考文末"常见问题"一节,若无法解决,可以在百度或google以下具体原因.
MapStruct主要依赖:其他依赖管理工具(Ant,Gradle)的导入,可见 官方文档链接



    1.4.2.Final
  	1.18.12



    
        org.mapstruct
        mapstruct
        ${org.mapstruct.version}
    



    
        
            org.apache.maven.plugins
            maven-compiler-plugin
            3.8.1
            
                1.8
                1.8
                
                    
                        org.mapstruct
                        mapstruct-processor
                        ${org.mapstruct.version}
                    
                  	
                    
                          org.projectlombok
                          lombok
                          ${lombok.version}
                      
                
            
        
    


Lombok依赖:(版本最好在1.16.16以上,否则会出现问题)通常是和lombok一起使用的

        
            org.projectlombok
            lombok
            ${lombok.version}
          	// 版本号 1.18.12
        

调用方式

  1. spring注入方式:在Mapper中加入 componentModel="spring"

@Mapper(componentModel="spring")
写上之后,可以通过 @autowire 注解来注入这个工具类

  1. 默认方式

在类中写上CarConverter INSTANCE = Mappers.getMapper(CarConverter.class);
其中 CarConverter 是类名;

一个多级嵌套结构的例子

这是我们要生成的DTO,其中包含一个List,在MenusBean中又包含一个List,这样的映射关系,参考下面的代码:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class RespLoginDTO {

    private String id;
    private String username;
    private String cname;
    private String sex;
    private String mobile;
    private String email;
    private String token;
    private String description;
    private String roleName;
    private String roleId;
    private List menus;

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class MenusBean {
       
        private int id;
        private String title;
        private String icon;
        private List children;


        @Data
        @AllArgsConstructor
        @NoArgsConstructor
        public static class ChildrenBean {
      
            private int id;
            private String title;
            private String path;


        }
    }
}


转换类:

@Mapper(componentModel = "spring")
public interface RespLoginDtoConverter {

    RespLoginDtoConverter INSTANCE = Mappers.getMapper(RespLoginDtoConverter.class);

    @Mappings({
            @Mapping(source = "user.userId", target = "id"),
            @Mapping(source = "userPerms", target = "menus")
    })
    RespLoginDTO createRespLoginDTO(User user, Role role, List userPerms, String token);


    // 下面的几个方法都是为了辅组完成上面的那个createRespLoginDTO转换而写的
    List createMenusBeans(List userPerms);

    @Mappings({
            @Mapping(source = "mainPerm.permId", target = "id"),
            @Mapping(source = "mainPerm.permTitle", target = "title"),
            @Mapping(source = "mainPerm.permIcon", target = "icon"),
            @Mapping(source = "childrenPrem", target = "children")
            //@Mapping(source = "userPerms.mainPerm", target = "menus"),
    })
    RespLoginDTO.MenusBean createMenusBean(UserPerm userPerm);

    List createMenusBeanChildrenBeans(List perms);

    @Mappings({
            @Mapping(source = "permId", target = "id"),
            @Mapping(source = "permTitle", target = "title"),
            @Mapping(source = "permPath", target = "path")
            //@Mapping(source = "userPerms.mainPerm", target = "menus"),
    })
    RespLoginDTO.MenusBean.ChildrenBean createChildrenBean(Perm perm);

}

其中User,Role 是常规的映射,不多解释,主要是要生成的DTO中的List menusList userPerms 间的映射,下面是UserPerm类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserPerm {
    /**
     * 主权限
     */
    private Perm mainPerm;
    /**
     * 子权限
     */
    private List childrenPrem;
}
@Data
@EqualsAndHashCode(callSuper = false)
public class Perm implements Serializable {
    private static final long serialVersionUID = 1L;
    private Long permId;
    private Long parentId;
    private String permCode;
    private String permName;
    private LocalDateTime createDate;
    private String permPath;
    private String permTitle;
    private String permIcon;
    private Boolean permType;
}

当执行List userPerms 转换成List menus时,会自动找到 MenusBeanUserPerm的方法,然后在MenusBeanUserPerm的过程中,又需要找到List转成 List 的方法,然后再List转成 List 的过程中,又要找到PermChildrenBean的方法,如此循环无限套娃,就完成了最初的多个对象转换成一个RespLoginDTO对象的功能。

常见问题

写一下自己遇到的几个问题:

No property named “XXX“ exists in source parameter(s). Did you mean “null“?

根本原因:看一下项目的/classes里面,看对应的类是不是编译生成了,或者说类是有的,但是里面没有geter/setter等方法(主要是Lombok的版本原因)。
情况一、可能是idea版本的问题:idea 2018 之前的版本需要添加下面的配置,后期的版本就不需要了,我自己用的2019.3,不需要这个依赖也能跑 ,如果加上,一定要注意这个依赖的版本,需要和 org.mapstruct:mapstruct 包的版本完全一致,否则报错

		
          org.mapstruct
          mapstruct-processor
          ${org.mapstruct.version}
     			
          provided
    

情况二、可能是没写maven插件: 在biuld里面加上(注意这里maven-compiler-plugin的版本要在3.6以上),最好和下面的版本一致,否则可能仍然会报错


    
        
            org.apache.maven.plugins
            maven-compiler-plugin
            3.8.1
            
                1.8
                1.8
                
                    
                        org.mapstruct
                        mapstruct-processor
                        ${org.mapstruct.version}
                      	
                    
                  	
                        org.projectlombok
                        lombok
                        1.18.12
                    
                
            
        
    

Couldn’t retrieve @Mapper annotation

情况一、包冲突:项目中使用了swagger,swagger里面也包含mapstruct,排除掉就好


    io.springfox
    springfox-swagger2
    ${swagger2.version}
    compile
    
        
          org.mapstruct
          mapstruct
        
    


情况二、导入mapstruct项目时,同时使用了 mapstruct-jdk8 和 mapstruct-processor 但是版本不一致,将版本号改为一样即可。


    org.mapstruct
    mapstruct-jdk8
    1.2.0.Final


    org.mapstruct
    mapstruct-processor
    1.2.0.Final

 

你可能感兴趣的:(java,开发语言)