一篇理解MapStruct领域转换工具!

MapStruct 介绍:

在我们日常开发的分层结构的应用程序中,为了各层之间互相解耦,一般都会定义不同的对象用来在不同层之间传递数据,因此,就有了各种 XXXDTOXXXVOXXXBO 等基于数据库对象派生出来的对象,当在不同层之间传输数据时,不可避免地经常需要将这些对象进行相互转换。

此时一般处理两种处理方式:① 直接使用 SetterGetter 方法转换、② 使用一些工具类进行转换(e.g. BeanUtil.copyProperties)。第一种方式如果对象属性比较多时,需要写很多的 Getter/Setter 代码。第二种方式看起来虽然比第一种方式要简单很多,但是因为其使用了反射,性能不太好,而且在使用中也有很多陷阱。而今天要介绍的主角 MapStruct 在不影响性能的情况下,同时解决了这两种方式存在的缺点。

MapStruct 是什么:

MapStruct 是一个代码生成器,它基于约定优于配置方法极大地简化了 Java bean 类型之间映射的实现。自动生成的映射转换代码只使用简单的方法调用,因此速度快、类型安全而且易于理解阅读,源码仓库 Github 地址 MapStruct。总的来说,有如下三个特点:

1.基于注解

2.在编译期自动生成映射转换代码

3.类型安全,高性能,无依赖

1.引入pom依赖:

        
            org.mapstruct
            mapstruct
            1.4.1.Final
            compile
        

        
            org.mapstruct
            mapstruct-processor
            1.4.1.Final
            compile
        

现在有一个场景,从数据库查询出来一个user对象(包含id,用户名,密码,手机号,邮箱,角色这些字段)和一个对应的角色对象role(包含id,角色名,角色描述这些字段),现在在controller需要用到user对象id,用户名和角色对象的角色名三个属性。

一种方式是直接把两个对象传入controller层,但是这样会多出很多没用的属性。

更通用的方式是需要用到的属性封装成一个类(DTO),通过传输这个类的实例来完成数据传输。

测试第一种情况:

User.java

@AllArgsConstructor  
@Data  
public class User {  
    private Long id;  
    private String username;  
    private String password;  
    private String phoneNum;  
    private String email;  
    private Role role;  
}  

Role.java

@AllArgsConstructor  
@Data  
public class Role {  
    private Long id;  
    private String roleName;  
    private String description;  
}  

UserRoleDto.java

@Data  
public class UserRoleDto {  
    /**  
     * 用户id  
     */  
    private Long userId;  
    /**  
     * 用户名  
     */  
    private String name;  
    /**  
     * 角色名  
     */  
    private String roleName;  
}  

MainTest.java

public class MainTest {  
    User user = null;  
  
    /**  
     * 模拟从数据库中查出user对象  
     */  
    @Before  
    public void before() {  
       Role role  = new Role(2L, "administrator", "超级管理员");  
       user  = new User(1L, "zhangsan", "12345", "17677778888", "[email protected]", role);  
    }  
  
    /**  
     * 模拟把user对象转换成UserRoleDto对象  
     */  
    @Test  
    public void test1() {  
        UserRoleDto userRoleDto = new UserRoleDto();  
        userRoleDto.setUserId(user.getId());  
        userRoleDto.setName(user.getUsername());  
        userRoleDto.setRoleName(user.getRole().getRoleName());  
        System.out.println(userRoleDto);  
    }  
}  

使用MapStruct解决上述问题:

这里我们沿用User.java、Role.java、UserRoleDto.java。

新建一个UserRoleMapper.java,这个来用来定义User.java、Role.java和UserRoleDto.java之间属性对应规则:

UserRoleMapper.java

import org.mapstruct.Mapper;  
import org.mapstruct.Mapping;  
import org.mapstruct.Mappings;  
import org.mapstruct.factory.Mappers;  
  
/**  
 * @Mapper 定义这是一个MapStruct对象属性转换接口,在这个类里面规定转换规则  
 *          在项目构建时,会自动生成改接口的实现类,这个实现类将实现对象属性值复制  
 * componentModel 在编译期自动生成转换器实现类放入target文件夹中
 * nullValueCheckStrategy 可以自动省略null的赋值
 * nullValueMappingStrategy 原语返回缺省bean,而不是空值null
 */  
@Mapper(componentModel = "spring", nullValueCheckStrategy = ALWAYS,nullValueMappingStrategy = RETURN_DEFAULT)
public interface UserRoleMapper {  
  
    /**  
     * 获取该类自动生成的实现类的实例  
     * 接口中的属性都是 public static final 的 方法都是public abstract的  
     */  
    UserRoleMapper INSTANCES = Mappers.getMapper(UserRoleMapper.class);  
  
    /**  
     * 这个方法就是用于实现对象属性复制的方法  
     *  
     * @Mapping 用来定义属性复制规则 source 指定源对象属性 target指定目标对象属性  
     *  
     * @param user 这个参数就是源对象,也就是需要被复制的对象  
     * @return 返回的是目标对象,就是最终的结果对象  
     */  
    @Mappings({  
            @Mapping(source = "id", target = "userId"),  
            @Mapping(source = "username", target = "name"),  
            @Mapping(source = "role.roleName", target = "roleName")  
    })  
    UserRoleDto toUserRoleDto(User user);  

    @Mappings({  
            @Mapping(source = "id", target = "userId"),  
            @Mapping(source = "username", target = "name"),  
            @Mapping(source = "role.roleName", target = "roleName")  
    })  
    List convertList(List list);
  
}  

在测试类中测试:

通过上面的例子可以看出,使用MapStruct方便许多。

你可能感兴趣的:(java,大数据)