官網地址: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); } }
運行結果
可以看到 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. 參考資料
MapStruct超級簡單的學習筆記