一、名詞解釋
- DTO(Data Transfer Object):數(shù)據(jù)傳輸對象,這個概念來源于J2EE的設(shè)計模式,原來的目的是為了EJB的分布式應(yīng)用提供粗粒度的數(shù)據(jù)實體宜岛,以減少分布式調(diào)用的次數(shù),從而提高分布式調(diào)用的性能和降低網(wǎng)絡(luò)負載功舀,但在這里,我泛指用于展示層與服務(wù)層之間的數(shù)據(jù)傳輸對象身弊。
- DO(Domain Object):領(lǐng)域?qū)ο蟊偬褪菑默F(xiàn)實世界中抽象出來的有形或無形的業(yè)務(wù)實體。
說明:在一個成熟的工程中阱佛,尤其是現(xiàn)在的分布式系統(tǒng)中帖汞,應(yīng)用與應(yīng)用之間,還有單獨的應(yīng)用細分模塊之后凑术,DO 一般不會讓外部依賴翩蘸,這時候需要在提供對外接口的模塊里放 DTO 用于對象傳輸,也即是 DO 對象對內(nèi)淮逊,DTO對象對外催首,DTO 可以根據(jù)業(yè)務(wù)需要變更(只需部分字段或字段名不同等)扶踊,并不需要映射 DO 的全部屬性。
這種 對象與對象之間的互相轉(zhuǎn)換郎任,就需要有一個專門用來解決轉(zhuǎn)換問題的工具秧耗,畢竟每一個字段都 get/set 會很麻煩。
MapStruct 就是這樣的一個屬性映射工具舶治,只需要定義一個 Mapper 接口分井,MapStruct 就會自動實現(xiàn)這個映射接口,避免了復(fù)雜繁瑣的映射實現(xiàn)霉猛。MapStruct官網(wǎng)地址: http://mapstruct.org/
二尺锚、maven配置
<properties>
<mapstruct.version>1.2.0.Final</mapstruct.version>
</properties>
<dependencies>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
<version>${mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</dependency>
</dependencies>
三、基本用法 一對一 DO TO DTO
- 兩個 DO 對象 Person 和 User惜浅,其中 user 是 Person 的一個屬性 瘫辩,一個 DTO 對象 PersonDTO
- DO中的使用Lombok省略get/set/構(gòu)造方法中
@NoArgsConstructor
@AllArgsConstructor
@Data
public class Person {
private Long id;
private String name;
private String email;
private Date birthday;
private User user;
}
@NoArgsConstructor
@AllArgsConstructor
@Data
public class User {
private Integer age;
}
@NoArgsConstructor
@AllArgsConstructor
@Data
public class PersonDTO {
private Long id;
private String name;
/**
* 對應(yīng) Person.user.age
*/
private Integer age;
private String email;
/**
* 與 DO 里面的字段名稱(birthDay)不一致
*/
private Date birth;
/**
* 對 DO 里面的字段(birthDay)進行拓展,dateFormat 的形式
*/
private String birthDateFormat;
/**
* 對 DO 里面的字段(birthDay)進行拓展,expression 的形式
*/
private String birthExpressionFormat;
}
四、多對一用法
說明:
寫一個 Mapper 接口 PersonConverter赡矢,其中兩個方法杭朱,一個是單實體映射,另一個是List映射
對象屬性與目標(biāo)對象屬性名字一致
- 自動映射對應(yīng)屬性吹散,啥也不用改
不一致
1.屬性名不一致:
source---target:
2.類型不一致:
3.不映射弧械,可忽略
@Mapper
public interface PersonConverter {
PersonConverter INSTANCE = Mappers.getMapper(PersonConverter.class);
@Mappings({
@Mapping(source = "birthday", target = "birth"),
@Mapping(source = "birthday", target = "birthDateFormat", dateFormat = "yyyy-MM-dd HH:mm:ss"),
@Mapping(target = "birthExpressionFormat", expression = "java(org.apache.commons.lang3.time.DateFormatUtils.format(person.getBirthday(),\"yyyy-MM-dd HH:mm:ss\"))"),
@Mapping(source = "user.age", target = "age"),
@Mapping(target = "email", ignore = true)
})
PersonDTO domain2dto(Person person);
List<PersonDTO> domain2dto(List<Person> people);
}
五、轉(zhuǎn)換類中添加自定義方法
通過 “默認方法”的方式空民,為轉(zhuǎn)換接口添加自定方法
// 形式如下
default PersonDTO personToPersonDTO(Person person) {
//hand-written mapping logic
}
// 比如在 PersonConverter 里面加入如下
default Boolean convert2Bool(Integer value) {
if (value == null || value < 1) {
return Boolean.FALSE;
} else {
return Boolean.TRUE;
}
}
default Integer convert2Int(Boolean value) {
if (value == null) {
return null;
}
if (Boolean.TRUE.equals(value)) {
return 1;
}
return 0;
}
默認方法參見:https://www.cnblogs.com/sidesky/p/9287710.html
六 @InheritConfiguration 繼承之前方法的配置
比如在 PersonConverter 里面加入如下刃唐,@InheritConfiguration 用于繼承剛才domain2dto方法的配置
@InheritConfiguration(name = "domain2dto")
void update(Person person, @MappingTarget PersonDTO personDTO);
七、注入Spring
默認使用方式
PersonConverter INSTANCE = Mappers.getMapper(PersonConverter.class);
注入Spring方式 @Mapper(componentModel="spring")
@Mapper(componentModel="spring")
public interface PersonConverter {
@Mappings({
@Mapping(source = "birthday", target = "birth"),
@Mapping(source = "birthday", target = "birthDateFormat", dateFormat = "yyyy-MM-dd HH:mm:ss"),
@Mapping(target = "birthExpressionFormat", expression = "java(org.apache.commons.lang3.time.DateFormatUtils.format(person.getBirthday(),\"yyyy-MM-dd HH:mm:ss\"))"),
@Mapping(source = "user.age", target = "age"),
@Mapping(target = "email", ignore = true)
})
PersonDTO domain2dto(Person person);
}
spring 使用
@RunWith(SpringRunner.class)
@SpringBootTest(classes = BaseTestConfiguration.class)
public class PersonConverterTest {
//這里把轉(zhuǎn)換器裝配進來
@Autowired
private PersonConverter personConverter;
@Test
public void test() {
Person person = new Person(1L,"zhige","zhige.me@gmail.com",new Date(),new User(1));
PersonDTO personDTO = personConverter.domain2dto(person);
}
}
八界轩、MapStruct常用注解
@Mapper 只有在接口加上這個注解画饥, MapStruct 才會去實現(xiàn)該接口
@Mapper 里有個 componentModel 屬性,主要是指定實現(xiàn)類的類型浊猾,一般用到兩個
default:默認抖甘,可以通過 Mappers.getMapper(Class) 方式獲取實例對象
spring:在接口的實現(xiàn)類上自動添加注解 @Component,可通過 @Autowired 方式注入
@Mapping:屬性映射葫慎,若源對象屬性與目標(biāo)對象名字一致衔彻,會自動映射對應(yīng)屬性
source:源屬性
target:目標(biāo)屬性
dateFormat:String 到 Date 日期之間相互轉(zhuǎn)換,通過 SimpleDateFormat偷办,該值為 SimpleDateFormat 的日期格式
ignore: 忽略這個字段
@Mappings:配置多個@Mapping
@MappingTarget 用于更新已有對象
@InheritConfiguration 用于繼承配置