简介

MapStruct是一个代码生成器的工具类,简化了不同的Java Bean之间映射的处理,所以映射指的就是从一个实体变化成一个实体。在实际项目中,我们经常会将PO转DTO、DTO转PO等一些实体间的转换。在转换时大部分属性都是相同的,只有少部分的不同,这时我们可以通过mapStruct的一些注解来匹配不同属性,可以让不同实体之间的转换变的简单。
使用MapStruct在编译时会生成响应的转换实现类,所以没有性能损耗。
MapStruct官网地址: http://mapstruct.org/

搭建开发环境 –基于Maven

这里需要在配置文件pom.xml中进行如下配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
...
<properties>
<!-- <org.mapstruct.version>1.1.0.Beta1</org.mapstruct.version>-->
<org.mapstruct.version>1.1.0.Final</org.mapstruct.version>
</properties>
...
<dependencies>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
<!-- <dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>-->
</dependency>
</dependencies>
...
<build>
<plugins>
<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>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
...

MapStruct实体间的转换

下面我们就来看看如何使用MapStruct实现实体之间的映射转换。下面两个类非常相似,有一个号码属性名不一样及在PeopleDTO中有个User对象,而在People中则是两个字符串属性。

PeopleEntity.java

1
2
3
4
5
6
7
8
9
10
public class PeopleEntity {
private Integer age;
private String name;
private String callNumber;
private String address;
private String emile;

//constructor, getters, setters etc.

}

PeopleDTO.java

1
2
3
4
5
6
7
8
public class PeopleDTO {
private String phoneNumber;
private String address;
private String emile;
private User user;

//constructor, getters, setters etc.
}

User.java

1
2
3
4
5
6
public class User {
private Integer age;
private String name;

//constructor, getters, setters etc.
}

Mapper接口
要生成一个PeopleDTO与PeopleEntity对象相互转换的映射器,我们需要定义一个mapper接口。像这两个实体类有些属性不一样时,我们可以通过@Mapping注解来进行转换.

  • @Mapper注解标记这个接口作为一个映射接口,并且是编译时MapStruct处理器的入口。
    只有在接口加上这个注解, MapStruct 才会去实现该接口。
    @Mapper 里有个 componentModel 属性,主要是指定实现类的类型,一般用到两个 default:默认,可以通过 Mappers.getMapper(Class) 方式获取实例对象
    spring:在接口的实现类上自动添加注解,@Component,可通过 @Autowired 方式注入。
  • @Mapping解决源对象和目标对象中,属性名字不同的情况。
  • Mappers.getMapper自动生成的接口的实现可以通过Mapper的class对象获取,从而让客户端可以访问Mapper接口的实现。
  • source:源属性
  • target:目标属性
  • dateFormat:String 到 Date 日期之间相互转换,通过 SimpleDateFormat,该值为SimpleDateFormat的日期格式
  • ignore: 忽略这个字段
  • @Mappings:配置多个@Mapping
  • @MappingTarget 用于更新已有对象
  • @InheritConfiguration 用于继承配置
    这里只是列举了常用的字段和注解,详细的参考官方文档:http://mapstruct.org/documentation/stable/reference/html/

PeopleMapper.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@Mapper
public interface PeopleMapper {
PeopleMapper INSTANCE = Mappers.getMapper(PeopleMapper.class);

/**
* PO转DTO
*
* @param entity PO
* @return DTO
*/
@Mapping(target = "phoneNumber", source = "callNumber")
@Mapping(target = "user.name", source = "name")
@Mapping(target = "user.age", source = "age")
PeopleDTO entityToDTO(PeopleEntity entity);

/**
* DTO转PO
*
* @param peopleDTO DTO
* @param entity PO
*/
@Mapping(target = "callNumber", source = "phoneNumber")
@Mapping(target = "name", source = "user.name")
@Mapping(target = "age", source = "user.age")
// @MappingTarget告诉MapStruct在现有对象(PeopleEntity)上进行更新,而不是new一个新对象。
void updateEntityFromDto(PeopleDTO peopleDTO, @MappingTarget PeopleEntity entity);

}

编译MapStruct

MapStruct是以Java编译器插件的形式来处理注解,生成mapper接口的实现。因此在使用之前我们要手工编译或启动程序时IDEA也会帮我们编译了,这里最好还是手动编译。

1
2
mvn compile
// 有的IDEA是 mvnw compile

编译完后的实现类可以到target目录看到PeopleMapperImpl.Java,如下图:

这时你也可以点进看里面代码的实现PeopleMapperImpl.Java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
public class PeopleMapperImpl implements PeopleMapper {
public PeopleMapperImpl() {
}

public PeopleDTO entityToDTO(PeopleEntity entity) {
if(entity == null) {
return null;
} else {
PeopleDTO peopleDTO = new PeopleDTO();
User user = new User();
peopleDTO.setUser(user);
user.setAge(entity.getAge());
user.setName(entity.getName());
peopleDTO.setPhoneNumber(entity.getCallNumber());
peopleDTO.setAddress(entity.getAddress());
peopleDTO.setEmile(entity.getEmile());
return peopleDTO;
}
}

public void updateEntityFromDto(PeopleDTO peopleDTO, PeopleEntity entity) {
if(peopleDTO != null) {
entity.setName(this.peopleDTOUserName(peopleDTO));
entity.setCallNumber(peopleDTO.getPhoneNumber());
entity.setAge(this.peopleDTOUserAge(peopleDTO));
entity.setAddress(peopleDTO.getAddress());
entity.setEmile(peopleDTO.getEmile());
}
}

private String peopleDTOUserName(PeopleDTO peopleDTO) {
if(peopleDTO == null) {
return null;
} else {
User user = peopleDTO.getUser();
if(user == null) {
return null;
} else {
String name = user.getName();
return name == null?null:name;
}
}
}

private Integer peopleDTOUserAge(PeopleDTO peopleDTO) {
if(peopleDTO == null) {
return null;
} else {
User user = peopleDTO.getUser();
if(user == null) {
return null;
} else {
Integer age = user.getAge();
return age == null?null:age;
}
}
}
}

Mapper使用

最后我们就来看看Mapper的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@SpringBootApplication
public class MapperTestApplication {
private static final Logger LOGGER = LoggerFactory.getLogger(MapperTestApplication.class);

public static void main(String[] args) {

//PO转DTO
PeopleEntity peopleEntity = new PeopleEntity(18, "yoyo", "13215849",
"shanghai ", "fdhf@163.com");
PeopleDTO peopleDTO = PeopleMapper.INSTANCE.entityToDTO(peopleEntity);

//DTO转PO
User user = new User(21, "jack");
PeopleDTO newP = new PeopleDTO("000000",
"changsha ", "jack@163.com", user);
PeopleEntity newEntity = new PeopleEntity();
PeopleMapper.INSTANCE.updateEntityFromDto(newP, newEntity);


LOGGER.info("PO转DTO peopleEntity==>" + peopleEntity.toString() + "\n peopleDTO==>" + peopleDTO.toString());
LOGGER.info("DTO转PO PeopleDTO==>" + newP.toString() + "\n peopleDTO==>" + newEntity.toString());

SpringApplication.run(MapperTestApplication.class, args);
}
}

启动之后你可以在后台看到如下的输出

1
2
3
4
11:12:28.602 [main] INFO com.example.demo.MapperTestApplication - PO转DTO peopleEntity==>PeopleEntity{age=18, name='yoyo', callNumber='13215849', address='shanghai ', emile='fdhf@163.com'}
peopleDTO==>PeopleDTO{phoneNumber='13215849', address='shanghai ', emile='fdhf@163.com', user=User{age=18, name='yoyo'}}
11:12:28.604 [main] INFO com.example.demo.MapperTestApplication - DTO转PO PeopleDTO==>PeopleDTO{phoneNumber='000000', address='changsha ', emile='jack@163.com', user=User{age=21, name='jack'}}
peopleDTO==>PeopleEntity{age=21, name='jack', callNumber='000000', address='changsha ', emile='jack@163.com'}

通过从上面后台输出的数据我们可以看出,对于属性名称不同的情况、以及属性类型不同都自动帮助我们转换了,是不是感觉很神奇,是不是感觉很强大.再也不用自己写大量的代码进行实体间的转换了。

本文转载于:https://blog.csdn.net/lx_yoyo/article/details/75061614