今天分享一个实习期间遇到的一个将entity实体类转化为dto展示类的Java实体映射工具。
MapStruct允许我们只需要定义一个 Mapper 接口,MapStruct 就会自动实现这个映射接口,避免了复杂繁琐的映射实现。
MapStruct官网地址: http://mapstruct.org/
下面展示下这个工具类的基本功能:
1、创建一个springboot项目
第一步:通过Spring初始化器创建一个springboot项目
第二步:给工程命名和分组——>next:
第三步:我是为项目选择引入了web和lombok模块,你也可以按照自己的需求引入相应的木块模块构建项目——>next
第四步:finish
2、搭建基本的用于测试MapStruct项
(1)poem.xml中引入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.chen</groupId>
<artifactId>test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>test</name>
<description>Demo project for Spring Boot</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<org.mapstruct.version>1.3.1.Final</org.mapstruct.version>
<mybatisplus-spring-boot-starter.version>1.0.4</mybatisplus-spring-boot-starter.version>
<mybatisplus.version>2.3.3</mybatisplus.version>
<lombok.version>1.18.8</lombok.version>
<hutool.version>4.6.17</hutool.version>
<cxf.version>3.1.6</cxf.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- MapStruct -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!--实例转换插件,激活Idea插件-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>${project.build.sourceEncoding}</encoding>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
</annotationProcessorPaths>
<compilerArgs>
<compilerArg>
-Amapstruct.suppressGeneratorTimestamp=false
</compilerArg>
<compilerArg>
-Amapstruct.suppressGeneratorVersionInfoComment=false
</compilerArg>
<compilerArg>
-Amapstruct.defaultComponentModel=spring
</compilerArg>
<compilerArg>
-Amapstruct.unmappedTargetPolicy=IGNORE
</compilerArg>
</compilerArgs>
<compilerArguments>
<extdirs>src\main\webapp\WEB-INF\lib</extdirs>
</compilerArguments>
</configuration>
</plugin>
</plugins>
</build>
</project>
(2)创建实体类和展示类
A、实体类
@Component
@Data
public class DeptCategory {
//部门id
private Integer id;
//部门名称
private String name;
//部门编码
private String code;
//部门类别
private Integer type;
}
B、展示类
@Data
public class DeptCategoryDTO {
//部门id
private Integer deptId;
//部门名称
private String deptName;
//部门编码
private String deptCode;
//部门类别
private Integer deptType;
}
C、MapStruct转化工具类
package com.chen.test.conver;
import com.chen.test.dto.DeptCategoryDTO;
import com.chen.test.entity.DeptCategory;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
@Mapper
public interface DeptCategoryConver extends BaseConver {
//@Mapping(source = "id",target = "deptId")
@Mappings({
@Mapping(source = "id",target = "deptId"),
@Mapping(source = "code",target = "deptCode")
})
DeptCategoryDTO entity2dto(DeptCategory deptCategory);
}
父类BaseConver也是个接口,当转化类比较多时可以用于抽取一些公共功能进行拓展(像时间串格式转化等)。
package com.chen.test.conver;
public interface BaseConver {
}
D、创建测试类
package com.chen.test;
import com.chen.test.conver.DeptCategoryConver;
import com.chen.test.dto.DeptCategoryDTO;
import com.chen.test.entity.DeptCategory;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class TestApplicationTests {
@Autowired
private DeptCategoryConver deptCategoryConver;
@Autowired
private DeptCategory deptCategory;
@Test
void testMapStruct() {
deptCategory.setId(1);
deptCategory.setCode("A1001");
deptCategory.setName("后勤部");
deptCategory.setType(2);
DeptCategoryDTO deptCategoryDTO = deptCategoryConver.entity2dto(deptCategory);
System.out.println(deptCategoryDTO);
}
}
运行结果:
很显然我们在代码编写时并没有对接口DeptCategoryConver
做任何实现类,只是添加了@Mapper
注解代码编译后便可以通过entity2dto()
方法便可以进入到其实现类中:
package com.chen.test.conver;
import com.chen.test.dto.DeptCategoryDTO;
import com.chen.test.entity.DeptCategory;
import javax.annotation.Generated;
import org.springframework.stereotype.Component;
@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2020-11-12T14:38:21+0800",
comments = "version: 1.3.1.Final, compiler: javac, environment: Java 1.8.0_211 (Oracle Corporation)"
)
@Component
public class DeptCategoryConverImpl implements DeptCategoryConver {
@Override
public DeptCategoryDTO entity2dto(DeptCategory deptCategory) {
if ( deptCategory == null ) {
return null;
}
DeptCategoryDTO deptCategoryDTO = new DeptCategoryDTO();
deptCategoryDTO.setDeptId( deptCategory.getId() );
deptCategoryDTO.setDeptCode( deptCategory.getCode() );
return deptCategoryDTO;
}
}
很显然这个类并不是我们编码的而是MapStruct帮我们生成的。这个实现类位于:
下面。
(3)多个entity对一个dto
创建一个Employee类:
@Component
@Data
public class Employee {
//id
private Integer id;
//姓名
private String name;
//性别
private String gender;
//邮箱
private String email;
}
对展示类添加属性:
@Data
public class DeptCategoryDTO {
//部门id
private Integer deptId;
//部门名称
private String deptName;
//部门编码
private String deptCode;
//部门类别
private Integer deptType;
//员工id
private Integer empId;
//员工姓名
private String empName;
//员工性别
private String empGender;
//员工邮箱
private String empEmail;
}
映射接口:
@Mapper
public interface DeptCategoryConver extends BaseConver {
//@Mapping(source = "id",target = "deptId")
@Mappings({
@Mapping(source = "dept.id",target = "deptId"),
@Mapping(source = "dept.code",target = "deptCode"),
@Mapping(source = "dept.name",target = "deptName"),
@Mapping(source = "emp.id",target = "empId"),
@Mapping(source = "emp.name",target = "empName"),
@Mapping(source = "emp.email",target = "empEmail")
})
DeptCategoryDTO entity2dto(DeptCategory dept, Employee emp);
}
当有多个entity时需要在source
属性值指定时用属性名.属性
的方式。
测试结果:
自动生成的实现类:
package com.chen.test.conver;
import com.chen.test.dto.DeptCategoryDTO;
import com.chen.test.entity.DeptCategory;
import com.chen.test.entity.Employee;
import javax.annotation.Generated;
import org.springframework.stereotype.Component;
@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2020-11-12T15:24:49+0800",
comments = "version: 1.3.1.Final, compiler: javac, environment: Java 1.8.0_211 (Oracle Corporation)"
)
@Component
public class DeptCategoryConverImpl implements DeptCategoryConver {
@Override
public DeptCategoryDTO entity2dto(DeptCategory dept, Employee emp) {
if ( dept == null && emp == null ) {
return null;
}
DeptCategoryDTO deptCategoryDTO = new DeptCategoryDTO();
if ( dept != null ) {
deptCategoryDTO.setDeptName( dept.getName() );
deptCategoryDTO.setDeptId( dept.getId() );
deptCategoryDTO.setDeptCode( dept.getCode() );
}
if ( emp != null ) {
deptCategoryDTO.setEmpId( emp.getId() );
deptCategoryDTO.setEmpName( emp.getName() );
deptCategoryDTO.setEmpEmail( emp.getEmail() );
}
return deptCategoryDTO;
}
}
补:
(1)单一属性映射:
@Mapping(source="",target="")
source指定源(entity)中的属性,target指定目标(dto)属性。
(2) 多属性映射:
@Mappings({
@Mapping(source = "dept.id",target = "deptId"),
@Mapping(source = "dept.code",target = "deptCode")
})
多个@Mapping(…)用逗号隔开,最后一个不带逗号