Java實體映射工具MapStruct的使用


官網地址:http://mapstruct.org/

MapStruct 是一個代碼生成器,簡化了不同的 Java Bean 之間映射的處理,所謂的映射指的就是從一個實體變化成一個實體。例如我們在實際開發中,DAO 層的實體(PO)和一些數據傳輸對象(DTO),大部分屬性都是相同的,只有少部分的不同,通過 mapStruct,可以讓不同實體之間的轉換變的簡單。我們只需要按照約定的方式進行配置即可。

MapStruct 是一個可以處理注解的 Java 編譯器插件,可以在命令行中使用,也可以在 IDE 中使用。MapStruct 有一些默認配置,但是也為用戶提供了自己進行配置的途徑。

下面進行 MapStruct 的使用。

2. 添加依賴

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>org.mapstruct</groupId>
<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>

3. 創建模擬類

假設數據庫中有 user 表(包含 id ,用戶名,地址,角色這些字段)與 role 表(包含 id ,角色名,描述這些字段)。

假設前端查詢 user 的時候只需要用到 userId 、 userName 、 userAddr 與 role 的 roleId 字段時,如果將整個 user 都輸出到前端會多出許多沒有用的屬性。更通用的方式是需要用到的屬性封裝成一個類( DTO ),通過傳輸這個類的實例來完成數據傳輸。

User.java

1
2
3
4
5
6
7

public class {
private Long id;
private String name;
private String addr;
private Role role;
}

Role.java

1
2
3
4
5
6

public class Role {
private Long id;
private String name;
private String description;
}

UserRoleDto.java

1
2
3
4
5
6
7

public class UserRoleDto {
private Long userId;
private String userName;
private String userAddr;
private String roleName;
}

4. 編寫映射類

新建一個 UserRoleMapper.java ,這個類用來定義 User.java 、 Role.java 和 UserRoleDto.java 之間屬性對應規則。

1
2
3
4
5
6
7
8
9
10
11
@Mapper(componentModel = "spring")
public interface UserMapper {

@Mappings({
@Mapping(source = "id", target = "userId"),
@Mapping(source = "name", target = "userName"),
@Mapping(source = "addr", target = "userAddr"),
@Mapping(source = "role.name", target = "roleName"),
})
UserRoleDto toUserRoleDto(User user);
}

MapStruct中的注解

  • @Mapper:注解在接口、類上,這樣 MapStruct 才會去實現該接口
    • componentModel:該屬性用於指定實現類的類型,有幾個屬性:
      • default:默認,不使用任何組建類型,可以通過Mappers.getMapper(Class) 方式獲取實例對象
      • spring:在實現類上注解 @Component,可通過 @Autowired 方式注入
      • cdi: the generated mapper is an application-scoped CDI bean and can be retrieved via @Inject
      • jsr330:實現類上添加@javax.inject.Named 和@Singleton注解,可以通過 @Inject注解獲取。
  • @Mappings:配置多個@Mapping
  • @Mapping:配置屬性映射,若源對象屬性與目標對象名字一致,會自動映射對應屬性
    • source:源屬性、target:目標屬性
    • dateFormat:可將 String 到 Date 日期之間相互轉換,通過 SimpleDateFormat,該值為 SimpleDateFormat 的日期格式

寫完該映射類后,當啟動 IDE 的時候 IDE 會幫我們編譯, 會自動在 target/classes 下生成對應的實現類,可以查看其實現的方法。

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

@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2019-07-17T21:00:35+0800",
comments = "version: 1.2.0.Final, compiler: javac, environment: Java 1.8.0_191 (Oracle Corporation)"
)
@Component
public class UserMapperImpl implements UserMapper {

@Override
public UserRoleDto toUserRoleDto(User user) {
if ( user == null ) {
return null;
}

UserRoleDto userRoleDto = new UserRoleDto();

String name = userRoleName( user );
if ( name != null ) {
userRoleDto.setRoleName( name );
}
userRoleDto.setUserAddr( user.getAddr() );
userRoleDto.setUserName( user.getName() );
userRoleDto.setUserId( user.getId() );

return userRoleDto;
}

private String userRoleName(User user) {
if ( user == null ) {
return null;
}
Role role = user.getRole();
if ( role == null ) {
return null;
}
String name = role.getName();
if ( name == null ) {
return null;
}
return name;
}
}

5. 測試

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
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringbootMapstructApplicationTests {
大專欄  Java實體映射工具MapStruct的使用
@Autowired
UserMapper userMapper;

User user;

Role role;

@Before
public void before() {
// 模擬數據庫數據
role = new Role(2L, "admin", "管理員哦");
user = new User(1L, "sgh", "China", role);
}

@Test
public void contextLoads() {
System.out.println("----------------user---------------");
System.out.println(user);
UserRoleDto userRoleDto = userMapper.toUserRoleDto(user);
System.out.println("----------------touserDto--------------");
System.out.println(userRoleDto);
}

}

運行結果

1563369041341

可以看到 user.role.name 字段成功映射到了 userRoleDto 的 roleName 字段上。

6. 使用實現類的實例進行轉換

UserRoleMapper.java 類修改如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Mapper
public interface UserRoleMapper {

// 獲取該類自動生成的實現類的實例
UserRoleMapper INSTANCE = Mappers.getMapper(UserRoleMapper.class);

@Mappings({
@Mapping(source = "id", target = "userId"),
@Mapping(source = "name", target = "userName"),
@Mapping(source = "addr", target = "userAddr"),
@Mapping(source = "role.name", target = "roleName"),
})
UserRoleDto toUserRoleDto(User user);
}

Mapper 的 componentModel 屬性使用默認的 default (不寫即為 default)

測試類修改為

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
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringbootMapstructApplicationTests {
User user;

Role role;

@Before
public void before() {
// 模擬數據庫數據
role = new Role(2L, "admin", "管理員哦");
user = new User(1L, "sgh", "China", role);
}

@Test
public void contextLoads() {
System.out.println("----------------user---------------");
System.out.println(user);
UserRoleMapper INSTANCE = UserRoleMapper.INSTANCE;
UserRoleDto userRoleDto = INSTANCE.toUserRoleDto(user);
System.out.println("----------------touserDto--------------");
System.out.println(userRoleDto);
}

}

注意區別,因為映射類的 componentModel 不使用 spring , 因此不能通過 @Autowired 來自動注入,需要使用該類的實例來進行轉換。

具體體現在以下兩行代碼中

UserRoleMapper INSTANCE = UserRoleMapper.INSTANCE;
UserRoleDto userRoleDto = INSTANCE.toUserRoleDto(user);

7. 多個參數

可以綁定多個對象的屬性值到目標對象中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Mapper(componentModel = "spring")
public interface UserRoleMapper {

// 使用單一對象
@Mappings({
@Mapping(source = "id", target = "userId"),
@Mapping(source = "name", target = "userName"),
@Mapping(source = "addr", target = "userAddr"),
@Mapping(source = "role.name", target = "roleName"),
})
UserRoleDto toUserRoleDto(User user);

// 使用兩個對象
@Mappings({
@Mapping(source = "user.id", target = "userId"),
@Mapping(source = "user.name", target = "userName"),
@Mapping(source = "user.addr", target = "userAddr"),
@Mapping(source = "role.name", target = "roleName"),
})
UserRoleDto toUserRoleDto(User user, Role role);
}

測試類修改為

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
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringbootMapstructApplicationTests {

@Autowired
UserRoleMapper userRoleMapper;

User user;

Role role;

@Before
public void before() {
// 模擬數據庫數據
role = new Role(2L, "admin", "管理員哦");
user = new User(1L, "sgh", "China", role);
}

@Test
public void contextLoads() {
System.out.println("----------------user---------------");
System.out.println(user);
UserRoleDto userRoleDto = userRoleMapper.toUserRoleDto(user, role);
System.out.println("----------------touserDto--------------");
System.out.println(userRoleDto);
}

}

這里使用傳兩個參數進行屬性映射,結果一致

項目代碼: https://github.com/ShangguanHong/SpringBootDemo/tree/master/springboot-mapstruct

8. 參考資料

  1. MapStruct超級簡單的學習筆記


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM