前言
具体为啥要用就不说了,请看下文。
我们知道,随着项目规模的扩大,清晰的模块划分和项目层次划分是势在必行的,如此我们不仅可以实现高效开发,还能实现代码之间的解耦合。
在一个成熟的项目工程中,常见的,一般会划分多个 DO
、VO
、DTO
对象,DO一般指的是我们的业务实体对象,可以理解成我们对数据库关系的映射;VO一般指的是我们业务需要返回给前端的一些字段(显然,我们返回给前端的字段不可能是和数据库中一一对应,针对不同的业务我们或许会做一些增删或者增强的操作);而DTO在我的理解,如分布式应用或者第三方服务之间的对象传递,也可以理解成在后端传递的对象,对我们的前台业务没有影响。
如上,我们的项目划分了如此多的层,那么针对各个对象字段间的转换,就会相对麻烦。在之前我们或许会使用 BeanUtils
这样的工具,但是它相对于 Mapsruct
而言的话,所支持的功能就太少了,而且并不安全,它只能同属性映射,遇到被映射的数属性数据类型被修改或者字段名被修改的时候,也会导致映射失败,总之风险性极高。而 MapStruct
就解决了这一系列的问题。
优点
- 和手动生成映射代码来对比,更加节省时间并且提高准确率。
- 简单泛型智能转换
- 效率高
- 性能高,仅仅使用简单的 Java 方法来调用来替代传统的反射映射
- 编译时类型安全,只能映射相同名称或者带有映射标记的属性
- 编译时产生异常,如果映射不完整或者不正确,那么会在编译时抛出异常
Maven依赖
<!-- https://mvnrepository.com/artifact/org.mapstruct/mapstruct-jdk8 -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
<version>1.3.1.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mapstruct/mapstruct-processor -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.3.1.Final</version>
</dependency>
我们可以导入Maven仓库的稳定版本,如果我们使用的 JDK 版本高于1.8,那么我们可以使用如上所示的包,这样可以帮助我们利用一些 Java8 中所提供的新特性。
而 processor
库则是注解处理器,根据注解自动生成 Mapper 的实现。
在SpringBoot中使用
关于报错
在使用 IDEA2020.3 版本作为集成开发环境的时候,编译过程或许会出现空指针异常错误。
解决方法:
Setting —>Build,Execution,Deployment —>Compiler —>User-local build
加上参数: -Djps.track.ap.dependencies=false
定义接口
package com.imsle.mapstructexample.common.mapper;
import com.imsle.mapstructexample.common.dto.UserDTO1;
import com.imsle.mapstructexample.common.dto.UserDTO2;
import com.imsle.mapstructexample.common.dto.UserDTO3;
import com.imsle.mapstructexample.common.po.UserPO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
/**
* @作者: Seale
* @时间: 2021/07/22 5:00 下午
* @说明:
* @类名: UserPOToUserDTO
*/
@Mapper
public interface UserPOToUserDTO {
// ClassLoader 加载方式
UserPOToUserDTO INSTANCE = Mappers.getMapper(UserPOToUserDTO.class);
// 字段类型相同
UserDTO1 userPoToUserDto1(UserPO userPO);
UserPO userDto1ToUserPo(UserDTO1 userDTO1);
// 字段类型数量不一致
UserDTO2 userPoToUserDto2(UserPO userPO);
// 字段名称不一致
@Mappings({
@Mapping(source = "name", target = "frontName"),
@Mapping(source = "id", target = "frontId"),
@Mapping(source = "createTime", target = "frontCreateTime")
})
UserDTO3 userPoToUserDto3(UserPO userPO);
@Mappings({
@Mapping(source = "frontName", target = "name"),
@Mapping(source = "frontId", target = "id"),
@Mapping(source = "frontCreateTime", target = "createTime")
})
UserPO userDto3ToUserPo(UserDTO3 userDTO3);
}
package com.imsle.mapstructexample.common.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @作者: Seale
* @时间: 2021/07/22 4:51 下午
* @说明: 被映射的UserDTO对象,和实体类的每一个属性名都不一样
* @类名: UserDTO3
*/
@Data
@Accessors(chain = true)
public class UserDTO3 {
@JsonProperty("front_id")
private Integer frontId;
@JsonProperty("front_name")
private String frontName;
@JsonProperty("front_create_time")
private String frontCreateTime;
}
package com.imsle.mapstructexample.common.po;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @作者: Seale
* @时间: 2021/07/22 4:49 下午
* @说明: UserDO 对象
* @类名: UserDO
*/
@Data
@Accessors(chain = true)
public class UserPO {
private Integer id;
private String name;
private String createTime;
}
进行测试
在这里我就没有使用 Junit 进行测试了,直接使用一个 Controller 进行测试。
package com.imsle.mapstructexample.controller;
import com.imsle.mapstructexample.common.dto.UserDTO3;
import com.imsle.mapstructexample.common.mapper.UserPOToUserDTO;
import com.imsle.mapstructexample.common.po.UserPO;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
/**
* @作者: Seale
* @时间: 2021/07/22 5:25 下午
* @说明:
* @类名: TestController
*/
@RestController
public class TestController {
@GetMapping("/test")
public Object poToDto(){
UserPO userPO = new UserPO();
userPO.setId(1)
.setCreateTime("测试时间")
.setName("测试姓名");
// 添加结果列表
List<Object> objects = new ArrayList<>();
objects.add(userPO);
// 使用mapStruct转换
UserDTO3 userDTO3 = UserPOToUserDTO.INSTANCE.userPoToUserDto3(userPO);
objects.add(userDTO3);
return objects;
}
}
结果
后续
对于 MapStruct 本篇博文只是做简单入门介绍和使用教程,它的强大远不止于此,更多可以关注官网中的文档。
One comment
牛啊