MapStruct,对象装载结构工具
阿昌 Java小菜鸡
工具名为`MapStruct`,用于对象与对象之间的互相转换,避免每一个字段都 get/set 造成麻烦。

MapStruct官网地址: http://mapstruct.org/

如下的演示使用到了Lombok工具,如果不熟悉的请自行了解,这里就不说了。

一、引包

1
2
3
4
5
6
7
8
9
10
11
12
<!--mapstruct-->
<dependency>
<groupId>org.mapstruct</groupId>
<!-- jdk8以下就使用mapstruct -->
<artifactId>mapstruct-jdk8</artifactId>
<version>1.2.0.Final</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.2.0.Final</version>
</dependency>

二、demo

1、当对象属性==相同==时

  • source源对象
1
2
3
4
5
6
7
8
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Person{
private String name;
private Integer age;
}
  • target目标对象
1
2
3
4
5
6
7
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PersonVo{
private String name;
private Integer age;
}
  • MapStructMapper接口
1
2
3
4
5
6
7
8
import org.mapstruct.Mapper;

@Mapper
public interface PersonMapMapper {
PersonMapMapper INSTANCE = Mappers.getMapper(PersonMapMapper.class);

PersonVo toPersonVo(Person person);
}
  • 他会自动在target/classes下生成对应MapStructMapper接口的实现类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class PersonMapMapperImpl implements PersonMapMapper {
public PersonMapMapperImpl() {
}

public PersonVo toPersonVo(Person person) {
if (person == null) {
return null;
} else {
PersonVo personVo = new PersonVo();
personVo.setName(person.getName());
personVo.setAge(person.getAge());
return personVo;
}
}
}
  • 测试
1
2
3
4
5
6
7
public class test {
public static void main(String[] args) {
Person person = Person.builder().age(1).name("阿昌").build();
PersonVo personVo = PersonMapMapper.INSTANCE.toPersonVo(person);
System.out.println(personVo);
}
}

image


2、当对象属性==不同==时

  • source源对象
1
2
3
4
5
6
7
8
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Person{
private String name;
private Integer age;
}
  • target目标对象
1
2
3
4
5
6
7
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PersonVo{
private String name123;
private Integer age123;
}
  • MapStructMapper接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;

@Mapper
public interface PersonMapMapper {
PersonMapMapper INSTANCE = Mappers.getMapper(PersonMapMapper.class);

@Mappings({
@Mapping(source = "name",target = "name123"),
@Mapping(source = "age",target = "age123")
})
PersonVo toPersonVo(Person person);
}
  • 他会自动在target/classes下生成对应MapStructMapper接口的实现类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.achang.fmService.testMapStruct;

public class PersonMapMapperImpl implements PersonMapMapper {
public PersonMapMapperImpl() {
}

public PersonVo toPersonVo(Person person) {
if (person == null) {
return null;
} else {
PersonVo personVo = new PersonVo();
personVo.setName123(person.getName());
personVo.setAge123(person.getAge());
return personVo;
}
}
}
  • 测试
1
2
3
4
5
6
7
public class test {
public static void main(String[] args) {
Person person = Person.builder().age(1).name("阿昌").build();
PersonVo personVo = PersonMapMapper.INSTANCE.toPersonVo(person);
System.out.println(personVo);
}
}

image


3、如何结合springIoc容器?

添加==@Mapper(componentModel = “spring”)==

1
2
3
4
5
6
7
8
9
10
@Mapper(componentModel = "spring")//通过componentModel属性来指定环境为spirng
public interface PersonMapMapper {
PersonMapMapper INSTANCE = Mappers.getMapper(PersonMapMapper.class);

@Mappings({
@Mapping(source = "name",target = "name123"),
@Mapping(source = "age",target = "age123")
})
PersonVo toPersonVo(Person person);
}
  • 生成的Impl文件

发现自动生成了@Component

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Component //发现出现了@Component
public class PersonMapMapperImpl implements PersonMapMapper {
public PersonMapMapperImpl() {
}

public PersonVo toPersonVo(Person person) {
if (person == null) {
return null;
} else {
PersonVo personVo = new PersonVo();
personVo.setName123(person.getName());
personVo.setAge123(person.getAge());
return personVo;
}
}
}

下次就可以直接通过@Autowired注入使用

1
2
3
4
5
6
7
8
9
10
// 注入Mapper
@Autowired
private PersonMapMapper mapper;

@GetMapping("/test")
public String test() {
Person person = new Person("阿昌", 1);
PersonVo personVo = mapper.toPersonVo(person);
return personVo.toString();
}

4、如果对象里面还有对象的情况,和多参数情况,和传入参数情况

通过Mapping中source属性中指定源对象里面属性的对象,用来隔开指定

1
2
3
4
5
6
@Mappings({
@Mapping(source = "user.id", target = "userId"), // 指定对象里面的属性
@Mapping(source = "role.name", target = "roleName"), // 指定对象里面的属性
@Mapping(source = "myRoleDesc", target = "myRoleDesc") //使用参数既可
})
UserRoleDto toUserRoleDto(User user, Role role,String myRoleDesc);

5、更新对象属性

MapStruct提供了另外一种方式来更新一个对象中的属性。@MappingTarget

1
2
3
4
5
6
@Mappings({
@Mapping(source = "id", target = "userId"),
@Mapping(source = "username", target = "name"),
@Mapping(source = "role.roleName", target = "roleName")
})
void update(User user, @MappingTarget UserRoleDto userRoleDto);

通过@MappingTarget来指定目标类是谁(谁的属性需要被更新)。@Mapping还是用来定义属性对应规则。

上面的演示就是说,从user对象中的id属性,更新到userRoleDto对象中的userId属性


6、自定义类型转换

有时候,在对象转换的时候可能会出现这样一个问题,就是源对象中的类型是Boolean类型,而目标对象类型是String类型,这种情况可以通过@Mapper的uses属性来实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Customer {
private Long id;
private String name;
private Boolean isDisable;
}

@Data
public class CustomerDto {
private Long id;
private String customerName;
private String disable;
}

定义转换规则的类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class BooleanStrFormat {
public String toStr(Boolean isDisable) {
if (isDisable) {
return "Y";
} else {
return "N";
}
}
public Boolean toBoolean(String str) {
if (str.equals("Y")) {
return true;
} else {
return false;
}
}
}

定义Mapper,@Mapper( uses = { BooleanStrFormat.class}),注意,这里的users属性用于引用之前定义的转换规则的类:

1
2
3
4
5
6
7
8
9
10
11
@Mapper( uses = { BooleanStrFormat.class})//使用我们自定义的转换类型规则
public interface CustomerMapper {

CustomerMapper INSTANCES = Mappers.getMapper(CustomerMapper.class);

@Mappings({
@Mapping(source = "name", target = " customerName"),
@Mapping(source = "isDisable", target = "disable")
})
CustomerDto toCustomerDto(Customer customer);
}

 请作者喝咖啡