今天就跟大家聊聊有關(guān)mapStruct java bean映射工具怎么用,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。
站在用戶的角度思考問(wèn)題,與客戶深入溝通,找到平羅網(wǎng)站設(shè)計(jì)與平羅網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗(yàn),讓設(shè)計(jì)與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個(gè)性化、用戶體驗(yàn)好的作品,建站類型包括:網(wǎng)站建設(shè)、成都網(wǎng)站設(shè)計(jì)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣、申請(qǐng)域名、網(wǎng)站空間、企業(yè)郵箱。業(yè)務(wù)覆蓋平羅地區(qū)。
在一個(gè)成熟的工程中,尤其是現(xiàn)在的分布式系統(tǒng)中,應(yīng)用與應(yīng)用之間,還有單獨(dú)的應(yīng)用細(xì)分模塊之后,DO 一般不會(huì)讓外部依賴,這時(shí)候需要在提供對(duì)外接口的模塊里放 DTO 用于對(duì)象傳輸,也即是 DO 對(duì)象對(duì)內(nèi),DTO對(duì)象對(duì)外,DTO 可以根據(jù)業(yè)務(wù)需要變更,并不需要映射 DO 的全部屬性。
這種 對(duì)象與對(duì)象之間的互相轉(zhuǎn)換,就需要有一個(gè)專門(mén)用來(lái)解決轉(zhuǎn)換問(wèn)題的工具,畢竟每一個(gè)字段都 get/set 會(huì)很麻煩。
MapStruct 就是這樣的一個(gè)屬性映射工具,只需要定義一個(gè) Mapper 接口,MapStruct 就會(huì)自動(dòng)實(shí)現(xiàn)這個(gè)映射接口,避免了復(fù)雜繁瑣的映射實(shí)現(xiàn)。
1.2.0.Final org.mapstruct mapstruct-jdk8 ${mapstruct.version} org.mapstruct mapstruct-processor ${mapstruct.version}
這里定義兩個(gè) DO 對(duì)象 Person 和 User,其中 user 是 Person 的一個(gè)屬性 ,一個(gè) DTO 對(duì)象 PersonDTO。
JavaBean:
@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; /** * 對(duì)應(yīng) Person.user.age */ private Integer age; private String email; /** * 與 DO 里面的字段名稱(birthDay)不一致 */ private Date birth; /** * 對(duì) DO 里面的字段(birthDay)進(jìn)行拓展,dateFormat 的形式 */ private String birthDateFormat; /** * 對(duì) DO 里面的字段(birthDay)進(jìn)行拓展,expression 的形式 */ private String birthExpressionFormat; }
寫(xiě)一個(gè) Mapper 接口 PersonConverter,其中兩個(gè)方法,一個(gè)是單實(shí)體映射,另一個(gè)是List映射。
若源對(duì)象屬性與目標(biāo)對(duì)象屬性名字一致,會(huì)自動(dòng)映射對(duì)應(yīng)屬性,不一樣的需要指定,也可以用 format 轉(zhuǎn)成自己想要的類型,也支持表達(dá)式的方式,可以看到像 id、name、email這些名詞一致的我并沒(méi)有指定 source-target,而birthday-birth指定了,轉(zhuǎn)換格式的 birthDateFormat 加了dateFormat 或者 birthExpressionFormat 加了 expression,如果某個(gè)屬性你不想映射,可以加個(gè) ignore=true。
MapSruct的Mapper(映射類):
@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); Listdomain2dto(List people); }
編譯MapStruct之后,手工編譯或者啟動(dòng) IDE 的時(shí)候 IDE 也會(huì)幫我們編譯, 會(huì)自動(dòng)在 target/classes 下生成對(duì)應(yīng)的實(shí)現(xiàn)類。
手工編譯命令 mvn compile
注意?。?!下面這個(gè) PersonConverterImpl 是自動(dòng)生成的,不是自己寫(xiě)的!
public class PersonConverterImpl implements PersonConverter { public PersonConverterImpl() { } public PersonDTO domain2dto(Person person) { if (person == null) { return null; } else { PersonDTO personDTO = new PersonDTO(); personDTO.setBirth(person.getBirthday()); if (person.getBirthday() != null) { personDTO.setBirthDateFormat((new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")).format(person.getBirthday())); } Integer age = this.personUserAge(person); if (age != null) { personDTO.setAge(age); } personDTO.setId(person.getId()); personDTO.setName(person.getName()); personDTO.setBirthExpressionFormat(DateFormatUtils.format(person.getBirthday(), "yyyy-MM-dd HH:mm:ss")); return personDTO; } } public Listdomain2dto(List people) { if (people == null) { return null; } else { List list = new ArrayList(people.size()); Iterator var3 = people.iterator(); while(var3.hasNext()) { Person person = (Person)var3.next(); list.add(this.domain2dto(person)); } return list; } } private Integer personUserAge(Person person) { if (person == null) { return null; } else { User user = person.getUser(); if (user == null) { return null; } else { Integer age = user.getAge(); return age == null ? null : age; } } } }
寫(xiě)一個(gè)單元測(cè)試類 PersonConverterTest 測(cè)試一下,看看效果。
public class PersonConverterTest { @Test public void test() { Person person = new Person(1L,"zhige","zhige.me@gmail.com",new Date(),new User(1)); PersonDTO personDTO = PersonConverter.INSTANCE.domain2dto(person); assertNotNull(personDTO); assertEquals(personDTO.getId(), person.getId()); assertEquals(personDTO.getName(), person.getName()); assertEquals(personDTO.getBirth(), person.getBirthday()); String format = DateFormatUtils.format(personDTO.getBirth(), "yyyy-MM-dd HH:mm:ss"); assertEquals(personDTO.getBirthDateFormat(),format); assertEquals(personDTO.getBirthExpressionFormat(),format); Listpeople = new ArrayList<>(); people.add(person); List personDTOs = PersonConverter.INSTANCE.domain2dto(people); assertNotNull(personDTOs); } }
MapStruct 可以將幾種類型的對(duì)象映射為另外一種類型,比如將多個(gè) DO 對(duì)象轉(zhuǎn)換為 DTO。
例子:
兩個(gè) DO 對(duì)象 Item 和 Sku,一個(gè) DTO 對(duì)象 SkuDTO
@NoArgsConstructor @AllArgsConstructor @Data public class Item { private Long id; private String title; } @NoArgsConstructor @AllArgsConstructor @Data public class Sku { private Long id; private String code; private Integer price; } @NoArgsConstructor @AllArgsConstructor @Data public class SkuDTO { private Long skuId; private String skuCode; private Integer skuPrice; private Long itemId; private String itemName; }
創(chuàng)建 ItemConverter(映射)接口,MapStruct 就會(huì)自動(dòng)實(shí)現(xiàn)該接口。
@Mapper public interface ItemConverter { ItemConverter INSTANCE = Mappers.getMapper(ItemConverter.class); @Mappings({ @Mapping(source = "sku.id",target = "skuId"), @Mapping(source = "sku.code",target = "skuCode"), @Mapping(source = "sku.price",target = "skuPrice"), @Mapping(source = "item.id",target = "itemId"), @Mapping(source = "item.title",target = "itemName") }) SkuDTO domain2dto(Item item, Sku sku); }
創(chuàng)建測(cè)試類,講 Item 和 Sku 兩個(gè) DO對(duì)象,映射成一個(gè) DTO 對(duì)象 SkuDTO
public class ItemConverterTest { @Test public void test() { Item item = new Item(1L, "iPhone X"); Sku sku = new Sku(2L, "phone12345", 1000000); SkuDTO skuDTO = ItemConverter.INSTANCE.domain2dto(item, sku); assertNotNull(skuDTO); assertEquals(skuDTO.getSkuId(),sku.getId()); assertEquals(skuDTO.getSkuCode(),sku.getCode()); assertEquals(skuDTO.getSkuPrice(),sku.getPrice()); assertEquals(skuDTO.getItemId(),item.getId()); assertEquals(skuDTO.getItemName(),item.getTitle()); } }
// 形式如下 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; } // 測(cè)試類 PersonConverterTest 加入 assertTrue(PersonConverter.INSTANCE.convert2Bool(1)); assertEquals((int)PersonConverter.INSTANCE.convert2Int(true),1);
// 剛才一直寫(xiě)的例子是默認(rèn)的方式 PersonConverter INSTANCE = Mappers.getMapper(PersonConverter.class);
還有一種常用的方式,是和常用的框架 Spring 結(jié)合,在 @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); }
這時(shí)候測(cè)試類改一下,我用的 spring boot 的形式。
@RunWith(SpringRunner.class) @SpringBootTest(classes = BaseTestConfiguration.class) public class PersonConverterTest { //這里把轉(zhuǎn)換器裝配進(jìn)來(lái) @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); assertNotNull(personDTO); assertEquals(personDTO.getId(), person.getId()); assertEquals(personDTO.getName(), person.getName()); assertEquals(personDTO.getBirth(), person.getBirthday()); String format = DateFormatUtils.format(personDTO.getBirth(), "yyyy-MM-dd HH:mm:ss"); assertEquals(personDTO.getBirthDateFormat(),format); assertEquals(personDTO.getBirthExpressionFormat(),format); } }
@Mapper 只有在接口加上這個(gè)注解, MapStruct 才會(huì)去實(shí)現(xiàn)該接口 @Mapper 里有個(gè) componentModel 屬性,主要是指定實(shí)現(xiàn)類的類型,一般用到兩個(gè) default:默認(rèn),可以通過(guò) Mappers.getMapper(Class) 方式獲取實(shí)例對(duì)象 spring:在接口的實(shí)現(xiàn)類上自動(dòng)添加注解 @Component,可通過(guò) @Autowired 方式注入 @Mapping:屬性映射,若源對(duì)象屬性與目標(biāo)對(duì)象名字一致,會(huì)自動(dòng)映射對(duì)應(yīng)屬性 source:源屬性 target:目標(biāo)屬性 dateFormat:String 到 Date 日期之間相互轉(zhuǎn)換,通過(guò) SimpleDateFormat,該值為 SimpleDateFormat 的日期格式 ignore: 忽略這個(gè)字段 @Mappings:配置多個(gè)@Mapping @MappingTarget 用于更新已有對(duì)象 @InheritConfiguration 用于繼承配置
看完上述內(nèi)容,你們對(duì)mapStruct java bean映射工具怎么用有進(jìn)一步的了解嗎?如果還想了解更多知識(shí)或者相關(guān)內(nèi)容,請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝大家的支持。