日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

mapstruct详解

發布時間:2024/4/13 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mapstruct详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 功能介紹
    • mapStruct是什么
    • mapStruct有哪些功能
  • 整合到spring中
    • 基本使用
      • 引入
      • 示例
        • 基礎映射
        • 多個對象轉換為1個對象
        • 自定義轉換器
      • mapper使用方式
        • 建議按以下方式使用
      • 更多控制
    • 問題總結
  • 注解說明
    • 精細控制
  • 參考

功能介紹

mapStruct是什么

MapStruct是基于JSR 269的Java注解處理器,因此可以在命令行構建中使用(javac、Ant、Maven等等),可以在IDE內使用。用于生成類型安全的bean映射類的Java注解處理器。屬于編譯時注解,如果轉換bean內容有變化。需要手動clean下才能將變化的內容體現到class文件中。說白了就是通過注解的形式幫我們生成set,get方法。

mapStruct有哪些功能

最大的功能就是為我們轉換兩個不同的bean,或者List,比如拿java的代碼規范來說。客戶端入參–>系統的業務層入參—>db數據庫的入參;就對這3個層次來說。一個req絕對是不能透傳到db層的。為什么呢?就是為了降低耦合。提高業務的單一性,那么某一層參數有改變不會影響其他層。

整合到spring中

基本使用

接口注入靜態方法調用

引入

<!-- https://mvnrepository.com/artifact/org.mapstruct/mapstruct --> <dependency><groupId>org.mapstruct</groupId><artifactId>mapstruct</artifactId><version>1.3.1.Final</version> </dependency> <dependency><groupId>org.mapstruct</groupId><artifactId>mapstruct-processor</artifactId><version>1.3.1.Final</version> </dependency>

示例

基礎映射

@Data public class PersonDto {private String name;private String sex;private Date birthday;private int age;private Double money;private String password;private Date createTime;} //----------------------------------- @Data public class PersonVo {private String fullName;private String sex;private String birthday;private int age;private Double money;private String password; } //----------------------------------- @Mapper public interface PersonMapper {PersonMapper INSTANCE = Mappers.getMapper( PersonMapper.class );@Mapping( source = "fullName",target ="name")@Mapping( target ="birthday", dateFormat = "yyyy-MM-dd")PersonDto vo2dto(PersonVo vo);@Mapping( source = "name",target ="fullName")@Mapping( target ="birthday", dateFormat = "yyyy-MM-dd")@Mapping( target ="password",ignore = true)PersonVo dto2vo(PersonDto dto);}//----------------------------------- ublic static void test1() {PersonDto dto = new PersonDto();dto.setAge(10);dto.setBirthday(Date.from(Instant.now()));dto.setMoney(2.543D);dto.setName("john");dto.setSex("F");dto.setPassword("password");dto.setCreateTime(new Date());System.out.println("dto:::" + dto.toString());PersonVo vo = PersonMapper.INSTANCE.dto2vo(dto);System.out.println("vo:::" + vo.toString());PersonDto dto2 = PersonMapper.INSTANCE.vo2dto(vo);System.out.println("dto2:::" + dto2.toString());} //--------------OUTPUT: dto:::PersonDto(name=john, sex=F, birthday=Wed Apr 07 11:53:05 CST 2021, age=10, money=2.543, password=password, createTime=Wed Apr 07 11:53:05 CST 2021) vo:::PersonVo(fullName=john, sex=F, birthday=2021-04-07, age=10, money=2.543, password=null) dto2:::PersonDto(name=john, sex=F, birthday=Wed Apr 07 00:00:00 CST 2021, age=10, money=2.543, password=null, createTime=null)

處理了以下幾種情況:

  • 相同屬性名稱自動隱式映射
  • 屬性名不同,需要指定@mapping
  • 類型不同,需要指定轉換格式
  • 不需要設置的字段,使用ignore。如果字段在目標對象上不匹配的,則會自動忽略。

自動生成代碼

package demon.study.mapstruct;import java.text.ParseException; import java.text.SimpleDateFormat; import javax.annotation.Generated;@Generated(value = "org.mapstruct.ap.MappingProcessor",date = "2021-04-07T11:51:35+0800",comments = "version: 1.3.1.Final, compiler: javac, environment: Java 1.8.0_181 (Oracle Corporation)" ) public class PersonMapperImpl implements PersonMapper {@Overridepublic PersonDto vo2dto(PersonVo vo) {if ( vo == null ) {return null;}PersonDto personDto = new PersonDto();personDto.setName( vo.getFullName() );personDto.setSex( vo.getSex() );try {if ( vo.getBirthday() != null ) {personDto.setBirthday( new SimpleDateFormat( "yyyy-MM-dd" ).parse( vo.getBirthday() ) );}}catch ( ParseException e ) {throw new RuntimeException( e );}personDto.setAge( vo.getAge() );personDto.setMoney( vo.getMoney() );personDto.setPassword( vo.getPassword() );return personDto;}@Overridepublic PersonVo dto2vo(PersonDto dto) {if ( dto == null ) {return null;}PersonVo personVo = new PersonVo();personVo.setFullName( dto.getName() );personVo.setSex( dto.getSex() );if ( dto.getBirthday() != null ) {personVo.setBirthday( new SimpleDateFormat( "yyyy-MM-dd" ).format( dto.getBirthday() ) );}personVo.setAge( dto.getAge() );personVo.setMoney( dto.getMoney() );return personVo;} }

多個對象轉換為1個對象

@Data public class A1 {private String a;private String b; }@Data public class A2 {private String c; }@Data public class A {private String a;private String b;private String c; }@Mapper public interface AMapper {AMapper INSTANCE = Mappers.getMapper( AMapper.class );@Mapping(source = "a1.a", target = "a")@Mapping(source = "a1.b", target = "b")@Mapping(source = "a2.c", target = "c")A two2one(A1 a1,A2 a2 ); }//-----------------output:

自動生成代碼

public class AMapperImpl implements AMapper {@Overridepublic A two2one(A1 a1, A2 a2) {if ( a1 == null && a2 == null ) {return null;}A a = new A();if ( a1 != null ) {a.setA( a1.getA() );a.setB( a1.getB() );}if ( a2 != null ) {a.setC( a2.getC() );}return a;} }

自定義轉換器

枚舉與Integer型不能互相轉換,需要自定義(枚舉與String 可能會轉換正確,Int向枚舉也可能轉換正確)。

不兼容的類型需要自定義轉換。

可以使用@mapper(uses),@mapping(expression)實現

@mapping(expression) 主要用于多個屬性與一個屬性的映射

public class Custom {@Getterpublic enum CustomType {EMPTY(0, "EMPTY"),A(1, "A"),B(2, "B");private Integer code;private String desc;CustomType(Integer code, String desc) {this.code = code;this.desc = desc;}@Overridepublic String toString() {return String.format("{%s,%s}", code, desc);}public static CustomType from(Integer code) {switch (code) {case 1:return CustomType.A;case 2:return CustomType.B;default:return CustomType.EMPTY;}}}@Datapublic static class CustomDto {private Date birthday;private CustomType customA;private CustomType customB;private CustomType customC;}@Datapublic static class CustomVo {private long birthday;private String customA;private Integer customB;private Integer customC;private int all;}@Mapper(uses = {Date2IntHandler.class})public interface CustomMapper {CustomMapper INSTANCE = Mappers.getMapper(CustomMapper.class);@Mapping(target = "all", expression = "java(enum2Int(dto.getCustomB()) + enum2Int(dto.getCustomA()) )")CustomVo dto2vo(CustomDto dto);CustomDto vo2dto(CustomVo vo);default CustomType int2Enum(Integer code) {return CustomType.from(code);}default Integer enum2Int(CustomType type) {return type.getCode();}}public static class Date2IntHandler {public static Date int2Date(long i) {return new Date(i);}public static long date2Int(Date date) {return date.getTime();}}public static void main(String[] args) {test();}public static void test() {CustomDto dto = new CustomDto();dto.setBirthday(Date.from(Instant.now().minus(Period.ofDays(1000))));dto.setCustomA(CustomType.A);dto.setCustomB(CustomType.B);dto.setCustomC(CustomType.B);System.out.println("dto:::" + dto.toString());CustomVo vo = CustomMapper.INSTANCE.dto2vo(dto);System.out.println("vo:::" + vo.toString());CustomDto dto2 = CustomMapper.INSTANCE.vo2dto(vo);System.out.println("dto2:::" + dto2.toString());} }

輸出:

dto:::Custom.CustomDto(birthday=Thu Jul 12 14:38:04 CST 2018, customA={1,A}, customB={2,B}, customC={2,B}) vo:::Custom.CustomVo(birthday=1531377484863, customA=A, customB=2, customC=2, all=3) dto2:::Custom.CustomDto(birthday=Thu Jul 12 14:38:04 CST 2018, customA={1,A}, customB={2,B}, customC={2,B})

自動生成代碼

public class Custom$CustomMapperImpl implements CustomMapper {@Overridepublic CustomVo dto2vo(CustomDto dto) {if ( dto == null ) {return null;}CustomVo customVo = new CustomVo();customVo.setBirthday( Date2IntHandler.date2Int( dto.getBirthday() ) );if ( dto.getCustomA() != null ) {customVo.setCustomA( dto.getCustomA().name() );}customVo.setCustomB( enum2Int( dto.getCustomB() ) );customVo.setCustomC( enum2Int( dto.getCustomC() ) );customVo.setAll( enum2Int(dto.getCustomB()) + enum2Int(dto.getCustomA()) );return customVo;}@Overridepublic CustomDto vo2dto(CustomVo vo) {if ( vo == null ) {return null;}CustomDto customDto = new CustomDto();customDto.setBirthday( Date2IntHandler.int2Date( vo.getBirthday() ) );if ( vo.getCustomA() != null ) {customDto.setCustomA( Enum.valueOf( CustomType.class, vo.getCustomA() ) );}customDto.setCustomB( int2Enum( vo.getCustomB() ) );customDto.setCustomC( int2Enum( vo.getCustomC() ) );return customDto;} }

注意:

@mapping的屬性,source 和 expression 不能同時定義,因為expression中使用了表達式。

Maper中定義的轉換函數 ,會被自動應用到相同類型屬性的轉換上,可能會導致非期望結果。

mapper使用方式

1、接口注入方式

mapStruct接口類的聲明

//使用@Mapper(componentModel = "spring") 整合 @Mapper(componentModel = "spring") public interface ItemInfoConvert {} //------------------------------------------------------ //調用: //直接接口注入,方法調用即可@Autowiredprivate ItemInfoConvert itemInfoConvert;Person person = itemInfoConvert.deliveryDO2DTO(cart);

2、靜態方法調用

mapStruct接口類的聲明

public interface ItemInfoConvert {//靜態方法ItemInfoConvert INSTANCE = Mappers.getMapper(ItemInfoConvert.class); } //--------------------------------------------- //調用: Person person= ItemInfoConvert.INSTANCE.deliveryDO2DTO(cart);

建議按以下方式使用

@Data public class PersonDto {....../*** 輸入為null,輸出則為null* 為什么名字為toVo0?其實類是支持重載(overload),但是在使用stream時,區分不了是想用實例方法,還是類方法。* @param dto* @return*/public static PersonVo toVo0(PersonDto dto) {return PersonMapper.INSTANCE.dto2vo(dto);}public PersonVo toVo() {return PersonMapper.INSTANCE.dto2vo(this);}public static PersonDto from(PersonVo vo) {if (vo == null) {return null;}return PersonMapper.INSTANCE.vo2dto(vo);} } //------------------------------------ @Data public class PersonVo { ... ... public static PersonDto toDto0(PersonVo vo) {if (vo == null){return null;}return PersonMapper.INSTANCE.vo2dto(vo);}public PersonDto toDto(){return PersonMapper.INSTANCE.vo2dto(this);}public static PersonVo from(PersonDto dto){if (dto == null){return null;}return PersonMapper.INSTANCE.dto2vo(dto);} }//------------------------------------public static void test0() {PersonDto dto1 = new PersonDto();dto1.setAge(10);dto1.setBirthday(Date.from(Instant.now()));dto1.setMoney(2.543D);dto1.setName("john");dto1.setSex("F");dto1.setPassword("password");dto1.setCreateTime(new Date());PersonDto dto2 = new PersonDto();dto2.setAge(20);dto2.setBirthday(Date.from(Instant.now()));dto2.setMoney(7.543D);dto2.setName("tom");dto2.setSex("M");dto2.setPassword("password");dto2.setCreateTime(new Date());List<PersonDto> list = Arrays.asList(dto1, null, dto2);//未考慮空引用List<PersonVo> list2 = list.stream().map(dto -> dto.toVo()).collect(Collectors.toList());//考慮了空引用List<PersonVo> list3 = list.stream().map(PersonDto::toVo0).collect(Collectors.toList());} //------------------------------------

更多控制

見官方文檔,可以實現:

  • 內嵌屬性
  • collection,maps,list,stream等
  • defaultvalue等

問題總結

  • 保證相同的數據結構,即參數的類型相同,同string 或者同Integer,類型不同無法轉換

    Exception in thread "main" java.lang.NoSuchMethodError: demon.study.mapstruct.PersonVo.setBirthday(Ljava/util/Date;)V

    必須要使用@Mapping來解決此類問題。

  • 避開關鍵字,比如:delete等

  • 如果項目中也同時使用到了 Lombok,一定要注意 Lombok的版本要等于或者高于1.18.10,否則會有編譯不通過的情況發生

  • 注解說明

    • @Mapper:注解在接口、類上,這樣 MapStruct 才會去實現該接口

      屬性componentModel:該屬性用于指定實現類的類型,有幾個屬性值:

      • default:默認,不使用任何組建類型,可以通過Mappers.getMapper(Class) 方式獲取實例對象
      • spring:在實現類上注解 @Component,可通過 @Autowired 方式注入
      • jsr330:實現類上添加@javax.inject.Named 和@Singleton注解,可以通過 @Inject注解獲取。
    • @Mappings:配置多個@Mapping

    • @Mapping:配置屬性映射,若源對象屬性與目標對象名字一致,會自動映射對應屬性

      • source:源屬性、target:目標屬性
      • dateFormat:可將 String 到 Date 日期之間相互轉換,通過 SimpleDateFormat,該值為 SimpleDateFormat 的日期格式
      • ignore: 忽略這個字段

    精細控制

    控制拷貝屬性時,源字段為null時,是否覆蓋目標對象。

    @Mapper(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE, nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS) //進行null 檢查,如果為null,則不復制屬性值。nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.SET_TO_DEFAULT //賦值 默認值 nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE //忽略,保持目標對象屬性值

    The strategy works in a hierarchical fashion. @Mapping#nullValueCheckStrategy will override @BeanMapping#nullValueCheckStrategy, @BeanMapping#nullValueCheckStrategy will override @Mapper#nullValueCheckStrategy and @Mapper#nullValueCheckStrategy will override @MaperConfig#nullValueCheckStrategy.

    NullValuePropertyMappingStrategy also applies when the presence checker returns not present.

    參考

    • MapStruct 官網:https://mapstruct.org/
    • MapStruct 官方文檔:https://mapstruct.org/documentation/reference-guide/ , https://mapstruct.org/documentation/1.3/reference/html/#expressions
    • MapStruct maven 地址:https://mvnrepository.com/artifact/org.mapstruct/mapstruct
    • MapStruct github 地址:https://github.com/mapstruct/mapstruct/
    • https://www.cnblogs.com/javaguide/p/11861749.html
    超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生

    總結

    以上是生活随笔為你收集整理的mapstruct详解的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。