目录
在我们日常的开发中,会遇到各种DTO或者是VO以及其他的划分,而这些统称为POJO,这些是基于当前业务而衍生出来的类,用来做数据的传输,因此我们都会经历一个必要的阶段,那就是实体类跟DTO或者是其他类型进行一个转换,在我以前接触的项目中发现很多代码是使用get/set来进行转换的,大量的这种冗余代码,看着头都大,比较好的一种方式是使用BeanUtil,但是这种方式也有缺陷,可能会要求变量名一致或者是数据类型一致,要是后期把某个字段的数据类型改了,可能会出现莫名其妙的问题!而mapstruct就是来解决上面所描述的一系列问题!!!
- <dependency>
- <groupId>org.mapstructgroupId>
- <artifactId>mapstructartifactId>
- <version>1.5.2.Finalversion>
- dependency>
- import java.util.Date;
-
- /**
- * 用户实体类
- *
- * @author 小乘字节
- * @date 2022/08/02
- */
- public class User {
-
- /**
- * id
- */
- private Integer id;
- /**
- * 用户名
- */
- private String username;
- /**
- * 创建时间
- */
- private Date createTime;
- /**
- * 更新时间
- */
- private Date updateTime;
-
- public Integer getId() {
- return id;
- }
-
- public void setId(Integer id) {
- this.id = id;
- }
-
- public String getUsername() {
- return username;
- }
-
- public void setUsername(String username) {
- this.username = username;
- }
-
- public Date getCreateTime() {
- return createTime;
- }
-
- public void setCreateTime(Date createTime) {
- this.createTime = createTime;
- }
-
- public Date getUpdateTime() {
- return updateTime;
- }
-
- public void setUpdateTime(Date updateTime) {
- this.updateTime = updateTime;
- }
-
- @Override
- public String toString() {
- return "User{" +
- "id=" + id +
- ", username='" + username + '\'' +
- ", createTime=" + createTime +
- ", updateTime=" + updateTime +
- '}';
- }
- }
- /**
- * 用户传输对象
- *
- * @author 小乘字节
- * @date 2022/08/02
- */
-
- public class UserDTO {
-
- /**
- * id
- */
- private Integer id;
- /**
- * 用户名
- */
- private String name;
- /**
- * 创建时间
- */
- private String createTime;
- /**
- * 更新时间
- */
- private String updateTime;
-
- public Integer getId() {
- return id;
- }
-
- public void setId(Integer id) {
- this.id = id;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public String getCreateTime() {
- return createTime;
- }
-
- public void setCreateTime(String createTime) {
- this.createTime = createTime;
- }
-
- public String getUpdateTime() {
- return updateTime;
- }
-
- public void setUpdateTime(String updateTime) {
- this.updateTime = updateTime;
- }
-
- @Override
- public String toString() {
- return "UserDTO{" + "id=" + id + ", name='" + name + '\'' + ", createTime='" + createTime + '\''
- + ", updateTime='" + updateTime + '\'' + '}';
- }
- }
注意看User和UserDTO两个类的区别,包含了变量名不一致和数据类型不一致的情况!
- import org.mapstruct.Mapper;
- import org.mapstruct.Mapping;
- import org.mapstruct.MappingConstants;
- import org.mapstruct.Mappings;
-
- import com.ai.dto.UserDTO;
- import com.ai.entity.User;
-
- /**
- * 用户转换
- *
- * @author 小乘字节
- * @date 2022/08/02
- */
- @Mapper(componentModel = MappingConstants.ComponentModel.SPRING)
- public interface UserConvert {
-
- /**
- * User转换UserDTO
- *
- * @param userDTO 用户dto
- * @return {@link User} Mappings是对字段名不一致的字段进行映射
- *
- * Mapping可以处理变量名不一致映射关系以及指定日期格式等等
- */
- @Mappings({@Mapping(target = "username", source = "name"),
- @Mapping(target = "createTime", dateFormat = "yyyy-MM-dd"),
- @Mapping(target = "updateTime", dateFormat = "yyyy-MM-dd")})
- User userDtoToUser(UserDTO userDTO);
-
- /**
- * UserDTO转换User
- *
- * @param user 用户
- * @return {@link UserDTO}
- */
- @Mappings({@Mapping(target = "name", source = "username"),
- @Mapping(target = "createTime", dateFormat = "yyyy-MM-dd"),
- @Mapping(target = "updateTime", dateFormat = "yyyy-MM-dd")})
- UserDTO userToUserDto(User user);
- }
- import org.junit.jupiter.api.Test;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.boot.test.context.SpringBootTest;
-
- import com.ai.AiApplication;
- import com.ai.convert.UserConvert;
- import com.ai.dto.UserDTO;
- import com.ai.entity.User;
-
- @SpringBootTest(classes = AiApplication.class)
- public class UserConvertTest {
-
- @Autowired
- private UserConvert userConvert;
-
- @Test
- public void m1() {
- UserDTO userDTO = new UserDTO();
- userDTO.setId(1111);
- userDTO.setName("张三");
- userDTO.setCreateTime("2020-08-03");
- userDTO.setUpdateTime("2020-08-03");
-
- System.out.println("转换前:" + userDTO);
- User user = userConvert.userDtoToUser(userDTO);
- System.out.println("转换后:" + user);
- }
- }
输出结果:
转换前:UserDTO{id=1111, name='张三', createTime='2020-08-03', updateTime='2020-08-03'}
转换后:User{id=1111, username='张三', createTime=Mon Aug 03 00:00:00 CST 2020, updateTime=Mon Aug 03 00:00:00 CST 2020}
通过打印结果可以看到不管是数据类型不一致又或者是变量名不一致的情况,都能成功的进行转换!
那么mapstruct是如何去进行转换的呢?我们提供了一个转换的接口,而这个接口将由mapstruct进行实现,那么我们来借助反编译工具来看下实现类都做了什么处理吧!
反编译工具:
jadx下载地址:点击下载
jadx源码仓库地址:点击跳转
找到编译文件内接口的实现类,一般跟接口同包:

把实现类丢到打开的反编译工具里面,反编译结果如下:
通过反编译工具可以看得出来本质上还是由get/set来进行的转换,只是这些代码不需要我们手动写了,但是编译后还是会存在!
很重要:要注意Lombok的版本必须是1.18.16及以上,还需要添加lombok-mapstruct-binding的依赖以使 Lombok 和 MapStruct 一起工作,如果使用的是老版本的Lombok,那么在结合MapStruct使用的过程中会报 xxxx does not have an accessible constructor.的错误!如果要非要适用老版本的Lombok和MapStruct结合适用的话,官网给出的解决方案是:将要由 Lombok 修改的 JavaBean 和要由 MapStruct 处理的映射器接口放入项目的两个单独模块中。
- <dependency>
- <groupId>org.projectlombokgroupId>
- <artifactId>lombokartifactId>
- <version>1.18.16version>
- <scope>providedscope>
- dependency>
-
- <dependency>
- <groupId>org.projectlombokgroupId>
- <artifactId>lombok-mapstruct-bindingartifactId>
- <version>0.2.0version>
- dependency>
-
- <dependency>
- <groupId>org.mapstructgroupId>
- <artifactId>mapstructartifactId>
- <version>1.5.2.Finalversion>
- dependency>
- import lombok.Data;
-
- import java.util.Date;
-
- /**
- * 用户实体类
- *
- * @author 小乘字节
- * @date 2022/08/02
- */
- @Data
- public class User {
-
- /**
- * id
- */
- private Integer id;
- /**
- * 用户名
- */
- private String username;
- /**
- * 创建时间
- */
- private Date createTime;
- /**
- * 更新时间
- */
- private Date updateTime;
- }
- import lombok.Data;
-
- /**
- * 用户传输对象
- *
- * @author 小乘字节
- * @date 2022/08/02
- */
- @Data
- public class UserDTO {
-
- /**
- * id
- */
- private Integer id;
- /**
- * 用户名
- */
- private String name;
- /**
- * 创建时间
- */
- private String createTime;
- /**
- * 更新时间
- */
- private String updateTime;
- }
- import org.mapstruct.Mapper;
- import org.mapstruct.Mapping;
- import org.mapstruct.MappingConstants;
- import org.mapstruct.Mappings;
-
- import com.ai.dto.UserDTO;
- import com.ai.entity.User;
-
- /**
- * 用户转换
- *
- * @author 小乘字节
- * @date 2022/08/02
- */
- @Mapper(componentModel = MappingConstants.ComponentModel.SPRING)
- public interface UserConvert {
-
- /**
- * User转换UserDTO
- *
- * @param userDTO 用户dto
- * @return {@link User} Mappings是对字段名不一致的字段进行映射
- *
- * Mapping可以处理变量名不一致映射关系以及指定日期格式等等
- */
- @Mappings({@Mapping(target = "username", source = "name"),
- @Mapping(target = "createTime", dateFormat = "yyyy-MM-dd"),
- @Mapping(target = "updateTime", dateFormat = "yyyy-MM-dd")})
- User userDtoToUser(UserDTO userDTO);
-
- /**
- * UserDTO转换User
- *
- * @param user 用户
- * @return {@link UserDTO}
- */
- @Mappings({@Mapping(target = "name", source = "username"),
- @Mapping(target = "createTime", dateFormat = "yyyy-MM-dd"),
- @Mapping(target = "updateTime", dateFormat = "yyyy-MM-dd")})
- UserDTO userToUserDto(User user);
- }
- import org.junit.jupiter.api.Test;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.boot.test.context.SpringBootTest;
-
- import com.ai.AiApplication;
- import com.ai.convert.UserConvert;
- import com.ai.dto.UserDTO;
- import com.ai.entity.User;
-
- @SpringBootTest(classes = AiApplication.class)
- public class UserConvertTest {
-
- @Autowired
- private UserConvert userConvert;
-
- @Test
- public void m1() {
- UserDTO userDTO = new UserDTO();
- userDTO.setId(1111);
- userDTO.setName("张三");
- userDTO.setCreateTime("2020-08-03");
- userDTO.setUpdateTime("2020-08-03");
-
- System.out.println("转换前:" + userDTO);
- User user = userConvert.userDtoToUser(userDTO);
- System.out.println("转换后:" + user);
- }
- }
打印结果:
转换前:UserDTO(id=1111, name=张三, createTime=2020-08-03, updateTime=2020-08-03)
转换后:User(id=1111, username=张三, createTime=Mon Aug 03 00:00:00 CST 2020, updateTime=Mon Aug 03 00:00:00 CST 2020)
想要了解更多可以到官网看看:MapStruct – Java bean mappings, the easy way!
官方文档:MapStruct 1.5.2.Final Reference Guide
MapStruct仓库:GitHub - mapstruct/mapstruct: An annotation processor for generating type-safe bean mappers
在加入了Lombok之后只是简化了实体类,其他地方都没有变,重要的事情说三遍:
注意Lombok版本号! 注意Lombok版本号!注意Lombok版本号!
今天就到这里啦~
🥇原创不易,还希望各位大佬支持一下!
👍点赞,你的认可是我创作的动力 !
🌟收藏,你的青睐是我努力的方向!
✏️评论,你的意见是我进步的财富!