亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java?MapStruct優(yōu)雅地實(shí)現(xiàn)對(duì)象轉(zhuǎn)換

 更新時(shí)間:2023年06月05日 14:12:05   作者:Java小蟲(chóng)  
MapSturct?是一個(gè)生成類型安全,高性能且無(wú)依賴的?JavaBean?映射代碼的注解處理器,用它可以輕松實(shí)現(xiàn)對(duì)象轉(zhuǎn)換,下面就來(lái)和大家聊聊具體操作吧

1、什么是MapStruct

1.1 JavaBean 的困擾

對(duì)于代碼中 JavaBean之間的轉(zhuǎn)換, 一直是困擾我很久的事情。在開(kāi)發(fā)的時(shí)候我看到業(yè)務(wù)代碼之間有很多的 JavaBean 之間的相互轉(zhuǎn)化, 非常的影響觀感,卻又不得不存在。我后來(lái)想的一個(gè)辦法就是通過(guò)反射,或者自己寫(xiě)很多的轉(zhuǎn)換器。

第一種通過(guò)反射的方法確實(shí)比較方便,但是現(xiàn)在無(wú)論是 BeanUtils, BeanCopier 等在使用反射的時(shí)候都會(huì)影響到性能。雖然我們可以進(jìn)行反射信息的緩存來(lái)提高性能。但是像這種的話,需要類型和名稱都一樣才會(huì)進(jìn)行映射,有很多時(shí)候,由于不同的團(tuán)隊(duì)之間使用的名詞不一樣,還是需要很多的手動(dòng) set/get 等功能。

第二種的話就是會(huì)很浪費(fèi)時(shí)間,而且在添加新的字段的時(shí)候也要進(jìn)行方法的修改。不過(guò),由于不需要進(jìn)行反射,其性能是很高的。

1.2 MapStruct 帶來(lái)的改變

MapSturct 是一個(gè)生成類型安全,高性能且無(wú)依賴的 JavaBean 映射代碼的注解處理器(annotation processor)。

  • 注解處理器
  • 可以生成 JavaBean 之間那的映射代碼
  • 類型安全,高性能,無(wú)依賴性

2、MapStruct 入門(mén)

2.1 添加依賴

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.1.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>

2.2 po類

@Data
publicclass User {
private Integer id;
private String name;
private String address;
private Date birth;
}

2.3 dto類

@Data
publicclass UserDto implements Serializable {
private Integer id;
private String name;
private String address;
private Date birth;
}

2.4 創(chuàng)建轉(zhuǎn)換接口

//可以使用abstract class代替接口
@Mapper
publicinterface UserMapper {
UserDto userToUserDto(User user);
//集合
List<UserDto> userToUserDto(List<User> users);
}

2.5 測(cè)試方法

@Test
public void userPoToUserDto() {
 User user =new User();
 user.setId(1);
 user.setName("myx");
 user.setAddress("河北滄州");
 user.setBirth(new Date());
 UserMapper mapper = Mappers.getMapper(UserMapper.class);
 UserDto userDto = mapper.userToUserDto(user);
 System.out.println(userDto);
}

2.6 運(yùn)行效果

2.7 查看編譯的class

底層通過(guò)自動(dòng)取值賦值操作完成

3、MapStruct優(yōu)點(diǎn)分析

3.1 性能高

這是相對(duì)反射來(lái)說(shuō)的,反射需要去讀取字節(jié)碼的內(nèi)容,花銷會(huì)比較大。而通過(guò) MapStruct 來(lái)生成的代碼,其類似于人手寫(xiě)。速度上可以得到保證。

3.2 使用簡(jiǎn)單

如果是完全映射的,使用起來(lái)肯定沒(méi)有反射簡(jiǎn)單。用類似 BeanUtils 這些工具一條語(yǔ)句就搞定了。但是,如果需要進(jìn)行特殊的匹配(特殊類型轉(zhuǎn)換,多對(duì)一轉(zhuǎn)換等),其相對(duì)來(lái)說(shuō)也是比較簡(jiǎn)單的。

基本上,使用的時(shí)候,我們只需要聲明一個(gè)接口,接口下寫(xiě)對(duì)應(yīng)的方法,就可以使用了。當(dāng)然,如果有特殊情況,是需要額外處理的。

3.3 代碼獨(dú)立

生成的代碼是對(duì)立的,沒(méi)有運(yùn)行時(shí)的依賴。

3.4 易于 debug

在我們生成的代碼中,我們可以輕易的進(jìn)行 debug。

4、MapStruct使用案例

4.1 屬性名稱相同

在實(shí)現(xiàn)類的時(shí)候,如果屬性名稱相同,則會(huì)進(jìn)行對(duì)應(yīng)的轉(zhuǎn)化。通過(guò)此種方式,我們可以快速的編寫(xiě)出轉(zhuǎn)換的方法。(入門(mén)案例)

4.2 屬性名不相同

屬性名不相同,在需要進(jìn)行互相轉(zhuǎn)化的時(shí)候,則我們可以通過(guò)@Mapping 注解來(lái)進(jìn)行轉(zhuǎn)化。

@Data
publicclass UserDto implements Serializable {
private Integer id;
private String name;
private String address;
private Date birth;
private String password;
}
@Data
publicclass User {
private Integer id;
private String name;
private String address;
private Date birth;
private String pwd;
}
@Mapper
publicinterface UserMapper {
//單個(gè)屬性
//@Mapping(source = "pwd",target = "password")
//多個(gè)屬性
@Mappings({
@Mapping(source = "pwd",target = "password")
 })
UserDto userToUserDto(User user);
}
  • source 需要轉(zhuǎn)換的對(duì)接,通常是入?yún)?/li>
  • target 轉(zhuǎn)換的對(duì)接,通常是出參
  • ignore 忽略,默認(rèn)false不忽略,需要忽略設(shè)置為true
  • defaultValue 默認(rèn)值
  • expressions 可以通過(guò)表達(dá)式來(lái)構(gòu)造一些簡(jiǎn)單的轉(zhuǎn)化關(guān)系。雖然設(shè)計(jì)的時(shí)候想兼容很多語(yǔ)言,不過(guò)目前只能寫(xiě)Java代碼。
@Mappings({
@Mapping(source = "birthdate", target = "birth"),//屬性名不一致映射
@Mapping(target = "birthformat", expression = "java(org.apache.commons.lang3.time.DateFormatUtils.format(person.getBirthdate(),"yyyy-MM-dd HH:mm:ss"))"),//自定義屬性通過(guò)java代碼映射
 })
public PersonVo PersonToPersonVo(Person person);

這里用到演示了如何使用TimeAndFormat對(duì)time和format操作,這里必須要指定需要使用的Java類的完整包名,不然編譯的時(shí)候不知道你使用哪個(gè)Java類,會(huì)報(bào)錯(cuò)。

@Test
public void userPoToUserDto() {
 User user =new User();
 user.setId(1);
 user.setName("myx");
 user.setAddress("河北滄州");
 user.setBirth(new Date());
 user.setPwd("123456");
 UserMapper mapper = Mappers.getMapper(UserMapper.class);
 UserDto userDto = mapper.userToUserDto(user);
 System.out.println(userDto);
}

4.3 轉(zhuǎn)換非基礎(chǔ)類型屬性

如果subUser與subUserDto字段名稱相同直接配置即可完成(對(duì)象類型,包括list)

@Data
publicclass UserDto implements Serializable {
private Integer id;
private String name;
private String address;
private Date birth;
private String password;
private List<SubUserDto> subUserDto;
}
@Data
publicclass User {
private Integer id;
private String name;
private String address;
private Date birth;
private String pwd;
private List<SubUser> subUser;
}
@Mappings({
@Mapping(source = "pwd",target = "password"),
@Mapping(source = "subUser", target = "subUserDto")
})
UserDto userToUserDto(User user);

4.4 Mapper 中使用自定義的轉(zhuǎn)換

有時(shí)候,對(duì)于某些類型,無(wú)法通過(guò)代碼生成器的形式來(lái)進(jìn)行處理。那么, 就需要自定義的方法來(lái)進(jìn)行轉(zhuǎn)換。這時(shí)候,我們可以在接口(同一個(gè)接口,后續(xù)還有調(diào)用別的 Mapper 的方法)中定義默認(rèn)方法(Java8及之后)。

@Data
publicclass UserDto implements Serializable {
private Integer id;
private String name;
private String address;
private Date birth;
private String password;
private SubUserDto subUserDto;
}
@Data
publicclass SubUserDto {
private Boolean result;
private String name;
}
@Data
publicclass User {
private Integer id;
private String name;
private String address;
private Date birth;
private String pwd;
private SubUser subUser;
}
@Data
publicclass SubUser {
private Integer deleted;
private String name;
}
@Mapper
publicinterface UserMapper {
@Mappings({
@Mapping(source = "pwd",target = "password"),
@Mapping(source = "subUser", target = "subUserDto")
 })
UserDto userToUserDto(User user);
default SubUserDto subSource2subTarget(SubUser subUser) {
if (subUser == ) {
return;
 }
 SubUserDto subUserDto = new SubUserDto();
 subUserDto.setResult(!subUser.getDeleted().equals(0));
 subUserDto.setName(subUser.getName()==?"":subUser.getName());
return subUserDto;
 }
}

只能存在一個(gè)default修飾的方法

@Test
public void userPoToUserDto() {
 User user =new User();
 user.setId(1);
 user.setName("myx");
 user.setAddress("河北滄州");
 user.setBirth(new Date());
 user.setPwd("123456");
 SubUser subUser =new SubUser();
 subUser.setDeleted(0);
 subUser.setName("rkw");
 user.setSubUser(subUser);
 UserMapper mapper = Mappers.getMapper(UserMapper.class);
 UserDto userDto = mapper.userToUserDto(user);
 System.out.println(userDto);
}

4.5 多轉(zhuǎn)一

我們?cè)趯?shí)際的業(yè)務(wù)中少不了將多個(gè)對(duì)象轉(zhuǎn)換成一個(gè)的場(chǎng)景。MapStruct 當(dāng)然也支持多轉(zhuǎn)一的操作。

@Data
publicclass SubUser {
private Integer deleted;
private String name;
}
@Data
publicclass User {
private Integer id;
private String name;
private String address;
private Date birth;
private String pwd;
}
@Mapper
publicinterface UserMapper {
@Mappings({
@Mapping(source = "user.pwd",target = "password"),
@Mapping(source = "subUser.name", target = "name")
 })
NewUserDto userToUserDto(User user,SubUser subUser);
}
@Test
public void userPoToUserDto() {
 User user =new User();
 user.setId(1);
 user.setName("myx");
 user.setAddress("河北滄州");
 user.setBirth(new Date());
 user.setPwd("123456");
 SubUser subUser =new SubUser();
 subUser.setDeleted(0);
 subUser.setName("rkw");
 UserMapper mapper = Mappers.getMapper(UserMapper.class);
 NewUserDto userDto = mapper.userToUserDto(user,subUser);
 System.out.println(userDto);
}

4.5.1 遵循原則

  • 當(dāng)多個(gè)對(duì)象中, 有其中一個(gè)為 , 則會(huì)直接返回
  • 如一對(duì)一轉(zhuǎn)換一樣, 屬性通過(guò)名字來(lái)自動(dòng)匹配。因此, 名稱和類型相同的不需要進(jìn)行特殊處理
  • 當(dāng)多個(gè)原對(duì)象中,有相同名字的屬性時(shí),需要通過(guò) @Mapping 注解來(lái)具體的指定, 以免出現(xiàn)歧義(不指定會(huì)報(bào)錯(cuò))。如上面的 name

屬性也可以直接從傳入的參數(shù)來(lái)賦值

@Mapping(source = "person.description", target = "description")
@Mapping(source = "name", target = "name")
DeliveryAddress personAndAddressToDeliveryAddressDto(Person person, String name);

4.6 更新 Bean 對(duì)象

有時(shí)候,我們不是想返回一個(gè)新的 Bean 對(duì)象,而是希望更新傳入對(duì)象的一些屬性。這個(gè)在實(shí)際的時(shí)候也會(huì)經(jīng)常使用到。

@Mapper
publicinterface UserMapper {
NewUserDto userToNewUserDto(User user);
/**
 * 更新, 注意注解 @MappingTarget
 * 注解 @MappingTarget后面跟的對(duì)象會(huì)被更新。
 */
void updateDeliveryAddressFromAddress(SubUser subUser,@MappingTarget NewUserDto newUserDto);
}
@Test
public void userPoToUserDto() {
 User user =new User();
 user.setId(1);
 user.setName("myx");
 user.setAddress("河北滄州");
 user.setBirth(new Date());
 SubUser subUser =new SubUser();
 subUser.setDeleted(0);
 subUser.setName("rkw");
 UserMapper mapper = Mappers.getMapper(UserMapper.class);
 NewUserDto userDto = mapper.userToNewUserDto(user);
 mapper.updateDeliveryAddressFromAddress(subUser,userDto);
 System.out.println(userDto);
}

4.7 map映射

@MapMapping(valueDateFormat ="yyyy-MM-dd HH:mm:ss")
public Map<String ,String> DateMapToStringMap(Map<String,Date> sourceMap);
@Test
public void mapMappingTest(){
 Map<String,Date> map=new HashMap<>();
 map.put("key1",new Date());
 map.put("key2",new Date(new Date().getTime()+9800000));
 Map<String, String> stringObjectMap = TestMapper.MAPPER.DateMapToStringMap(map);
}

4.8 多級(jí)嵌套

只需要在mapper接口中定義相關(guān)的類型轉(zhuǎn)換方法即可,list類型也適用

4.8.1 方式1

@Data
publicclass User {
private Integer id;
private String name;
private String address;
private Date birth;
private Boolean isDisable;
private List<SubUser> user;
}
@Data
publicclass SubUser {
private Integer deleted;
private String name;
private List<SubSubUser> subUser;
}
@Data
publicclass SubSubUser {
private String aaa;
private String ccc;
}
@Data
publicclass UserDto implements Serializable {
private Integer id;
private String name;
private String address;
private Date birth;
private String isDisable;
private List<SubUserDto> user;
}
@Data
publicclass SubUserDto {
private Integer deleted;
private String name;
private List<SubSubUserDto> subUser;
}
@Data
publicclass SubSubUserDto {
private String aaa;
private String bbb;
}
@Mapper
publicinterface UserMapper {
UserDto userToNewUserDto(User user);
//子集字段相同方法不用編寫(xiě)會(huì)自動(dòng)生成
//孫子集字段不相同(list會(huì)自動(dòng)讀取此方法生成list)
@Mapping(source = "ccc",target = "bbb")
SubSubUserDto bbb(SubSubUser subSubUser);
}

4.8.2 方式2

通過(guò)uses配置類型轉(zhuǎn)換

@Mapper(uses = {TestMapper.class})
public interface UserMapper {
UserDto userToNewUserDto(User user);
}
@Mapper
publicinterface TestMapper {
@Mapping(source = "ccc",target = "bbb")
SubSubUserDto bbb(SubSubUser subSubUser);
}

5、獲取 mapper

5.1 通過(guò) Mapper 工廠獲取

我們都是通過(guò) Mappers.getMapper(xxx.class) 的方式來(lái)進(jìn)行對(duì)應(yīng) Mapper 的獲取。此種方法為通過(guò) Mapper 工廠獲取。

如果是此種方法,約定俗成的是在接口內(nèi)定義一個(gè)接口本身的實(shí)例 INSTANCE, 以方便獲取對(duì)應(yīng)的實(shí)例。

@Mapper
publicinterface SourceMapper {
 SourceMapper INSTANCE = Mappers.getMapper(SourceMapper.class);
// ......
}

這樣在調(diào)用的時(shí)候,我們就不需要在重復(fù)的去實(shí)例化對(duì)象了。類似下面

Target target = SourceMapper.INSTANCE.source2target(source);

5.2 使用依賴注入

對(duì)于 Web 開(kāi)發(fā),依賴注入應(yīng)該很熟悉。MapSturct 也支持使用依賴注入,同時(shí)也推薦使用依賴注入。

@Mapper(componentModel = "spring")

5.3 依賴注入策略

可以選擇是通過(guò)構(gòu)造方法或者屬性注入,默認(rèn)是屬性注入。

publicenum InjectionStrategy {
/** Annotations are written on the field **/
 FIELD,
/** Annotations are written on the constructor **/
 CONSTRUCTOR
}

類似如此使用

@Mapper(componentModel = "cdi" injectionStrategy = InjectionStrategy.CONSTRUCTOR)

5.4 自定義類型轉(zhuǎn)換

有時(shí)候,在對(duì)象轉(zhuǎn)換的時(shí)候可能會(huì)出現(xiàn)這樣一個(gè)問(wèn)題,就是源對(duì)象中的類型是Boolean類型,而目標(biāo)對(duì)象類型是String類型,這種情況可以通過(guò)@Mapper的uses屬性來(lái)實(shí)現(xiàn):

@Data
publicclass User {
private Integer id;
private String name;
private String address;
private Date birth;
private Boolean isDisable;
}
@Data
publicclass UserDto implements Serializable {
private Integer id;
private String name;
private String address;
private Date birth;
private String isDisable;
}
@Mapper(uses = {BooleanStrFormat.class})
public interface UserMapper {
UserDto userToNewUserDto(User user);
}
publicclass BooleanStrFormat {
public String toStr(Boolean isDisable) {
if (isDisable) {
return"Y";
 } else {
return"N";
 }
 }
public Boolean toBoolean(String str) {
if (str.equals("Y")) {
returntrue;
 } else {
returnfalse;
 }
 }
}

要注意的是,如果使用了例如像spring這樣的環(huán)境,Mapper引入uses類實(shí)例的方式將是自動(dòng)注入,那么這個(gè)類也應(yīng)該納入Spring容器

@Test
public void userPoToUserDto() {
 User user =new User();
 user.setId(1);
 user.setName("myx");
 user.setAddress("河北滄州");
 user.setBirth(new Date());
 user.setIsDisable(true);
 SubUser subUser =new SubUser();
 subUser.setDeleted(0);
 subUser.setName("rkw");
 UserMapper mapper = Mappers.getMapper(UserMapper.class);
 UserDto userDto = mapper.userToNewUserDto(user);
 System.out.println(userDto);
}

以上就是Java MapStruct優(yōu)雅地實(shí)現(xiàn)對(duì)象轉(zhuǎn)換的詳細(xì)內(nèi)容,更多關(guān)于Java MapStruct的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java設(shè)計(jì)模式之模板方法模式詳解

    Java設(shè)計(jì)模式之模板方法模式詳解

    這篇文章主要為大家詳細(xì)介紹了Java設(shè)計(jì)模式之模板方法模式,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2022-03-03
  • java遠(yuǎn)程調(diào)用接口、URL的方式代碼

    java遠(yuǎn)程調(diào)用接口、URL的方式代碼

    我們都知道接口有自己本地的,也有遠(yuǎn)程別人寫(xiě)好的,而調(diào)用遠(yuǎn)程接口的就需要使用遠(yuǎn)程調(diào)用啦,這篇文章主要給大家介紹了關(guān)于java遠(yuǎn)程調(diào)用接口、URL的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-11-11
  • java 使用POI合并兩個(gè)word文檔

    java 使用POI合并兩個(gè)word文檔

    這篇文章主要介紹了java 使用POI合并兩個(gè)word文檔的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • MybatisPlus自動(dòng)填充時(shí)間的配置類實(shí)現(xiàn)

    MybatisPlus自動(dòng)填充時(shí)間的配置類實(shí)現(xiàn)

    本文介紹了如何在MyBatis-Plus中實(shí)現(xiàn)自動(dòng)填充時(shí)間的功能,通過(guò)實(shí)現(xiàn)MetaObjectHandler接口,重寫(xiě)insertFill()和updateFill()方法,分別在插入和更新時(shí)填充創(chuàng)建時(shí)間和更新時(shí)間,感興趣的可以了解一下
    2024-12-12
  • Java封裝公共Result結(jié)果返回類的實(shí)現(xiàn)

    Java封裝公共Result結(jié)果返回類的實(shí)現(xiàn)

    在使用Java開(kāi)發(fā)接口請(qǐng)求中,我們需要對(duì)請(qǐng)求進(jìn)行進(jìn)行統(tǒng)一返回值,這時(shí)候我們自己封裝一個(gè)統(tǒng)一的Result返回類,本文主要介紹了Java封裝公共Result結(jié)果返回類的實(shí)現(xiàn),感興趣的可以了解一下
    2023-01-01
  • SpringMVC如何獲取表單數(shù)據(jù)(radio和checkbox)

    SpringMVC如何獲取表單數(shù)據(jù)(radio和checkbox)

    這篇文章主要介紹了SpringMVC如何獲取表單數(shù)據(jù)(radio和checkbox)的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • IDEA設(shè)置JVM可分配內(nèi)存大小和其他參數(shù)的教程

    IDEA設(shè)置JVM可分配內(nèi)存大小和其他參數(shù)的教程

    這篇文章主要介紹了IDEA設(shè)置JVM可分配內(nèi)存大小和其他參數(shù)的教程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-01-01
  • Java超級(jí)實(shí)用的Freemarker工具類

    Java超級(jí)實(shí)用的Freemarker工具類

    這篇文章主要介紹了Java超級(jí)實(shí)用的Freemarker工具類,文章圍繞相關(guān)資料介紹以及代碼描述非常詳細(xì),需要的小伙伴可以參考一下,希望對(duì)你得學(xué)習(xí)有所幫助
    2022-02-02
  • java自定義JDBC實(shí)現(xiàn)連接池

    java自定義JDBC實(shí)現(xiàn)連接池

    本文主要介紹了java自定義JDBC實(shí)現(xiàn)連接池,包含實(shí)現(xiàn)JDBC連接池以及SQLException?異常的處理,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-02-02
  • Java IO 之文件讀寫(xiě)簡(jiǎn)單實(shí)例

    Java IO 之文件讀寫(xiě)簡(jiǎn)單實(shí)例

    這篇文章主要介紹了Java IO 之文件讀寫(xiě)簡(jiǎn)單實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2017-06-06

最新評(píng)論