Mapstruct?@Mapper?@Mapping?使用小結(jié)
作用
用于各個(gè)對(duì)象實(shí)體間的相互轉(zhuǎn)換,例如數(shù)據(jù)庫(kù)底層實(shí)體 轉(zhuǎn)為頁(yè)面對(duì)象,Model 轉(zhuǎn)為 DTO(data transfer object 數(shù)據(jù)轉(zhuǎn)換實(shí)體), DTO 轉(zhuǎn)為其他中間對(duì)象, VO 等等,相關(guān)轉(zhuǎn)換代碼為編譯時(shí)自動(dòng)產(chǎn)生的新文件和代碼。
兩個(gè)對(duì)象之間相同屬性名的會(huì)被自動(dòng)轉(zhuǎn)換,指定特殊情況時(shí)需要通過(guò)注解在抽象方法上說(shuō)明不同屬性之間的轉(zhuǎn)換。
轉(zhuǎn)換方法一般均為抽象方法,所以這一類(lèi)文件一般使用 接口 類(lèi),或者抽象類(lèi)均可,官方的介紹一般均使用了接口類(lèi)文件來(lái)完成。如果感興趣可以到官網(wǎng)看看
Maven 依賴(lài)
官方給與的示例配置,建議使用官方推薦的版本
...
<properties>
<org.mapstruct.version>1.5.2.Final</org.mapstruct.version>
</properties>
...
<dependencies>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
</dependencies>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
...在本地經(jīng)過(guò)一些實(shí)驗(yàn)后,發(fā)現(xiàn)這樣也可以
<dependencies>
........
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.4.2.Final</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.2.0.Final</version>
</dependency>
</dependencies>這里我 IDEA 版本為 2020.1
特別注意,mapstruct 以及 mapstruct-processor 不論哪種形式兩個(gè)都需要同時(shí)存在,mapstruct 提供了注解等,mapstruct-processor 會(huì)在編譯時(shí)將相關(guān)接口文件的實(shí)現(xiàn)類(lèi)生成出來(lái),最終完成想要的映射實(shí)現(xiàn)。
若與 lombok 連用
如果同時(shí)使用了另一個(gè) lombok 代碼生成相關(guān)的依賴(lài),那么需要注意lombok maven 依賴(lài)版本需要在 1.16.16 以上,否則可能會(huì)出現(xiàn)
**No property named “XXX“ exists in source parameter(s). Did you mean “null“?**之類(lèi)的錯(cuò)誤
使用示例
1.基本使用
定義兩個(gè)類(lèi)如下:
這里使用了lombok 實(shí)際上僅僅是簡(jiǎn)化了 get set 以及構(gòu)造方法之類(lèi)的。
如果需要,可以看看另一篇關(guān)于 lombok 的介紹@Data 注解使用 lombok插件學(xué)習(xí)總結(jié)
實(shí)體一DTO:
package org.aurora.lombok;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class PersionDTO {
private Long pId;
private String name;
private Integer age;
private String sex;
private String address;
private Float height;
private Float weight;
private Date birthDay;
private String birthLocation;
private Boolean married;
private Boolean hasParents;
private Boolean hasChildren;
private String describe;
}其中
@Data 編譯時(shí)幫助實(shí)現(xiàn)了 get set 方法
@AllArgsConstructor 全參構(gòu)造函數(shù)
@NoArgsConstructor 無(wú)參構(gòu)造函數(shù)
@Builder 允許使用 builder 方式構(gòu)造對(duì)象,其實(shí)和構(gòu)造函數(shù)差不多
另一個(gè)實(shí)體 VO:
package org.aurora.lombok;
import lombok.Data;
import lombok.ToString;
@Data
@ToString
public class PersonVO {
private Long pId;
private String name;
private Integer age;
private String sex;
private String des;
private String birth;
private String choice;
}開(kāi)始加入 MapStruct 的轉(zhuǎn)換相關(guān)的,注意這里我定義的是抽象類(lèi),實(shí)際上使用接口類(lèi)也可以先看看正常的接口類(lèi)
package org.aurora.mapstruct;
import org.aurora.lombok.PersionDTO;
import org.aurora.lombok.PersonVO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
@Mapper
public interface MyMapper {
MyMapper INSTANCE = Mappers.getMapper(MyMapper.class);
@Mapping(source = "describe", target = "des")
PersonVO transToViewObject(PersionDTO persionDTO);
}上面可以如下解釋
@Mapper 當(dāng)前類(lèi)認(rèn)為是要執(zhí)行 MapStruct 相關(guān)操作的類(lèi)
@Mapping 為指定某些特殊映射的注解,沒(méi)有指定的內(nèi)容,當(dāng)源對(duì)象與 目標(biāo)對(duì)象擁有一樣的屬性時(shí)會(huì)自動(dòng)轉(zhuǎn)換
INSTANCE 是為了在外面外面調(diào)用該方法, 接口中的屬性默認(rèn)為靜態(tài)屬性所以可以直接調(diào)用到
@Mapping 中 source 為入?yún)?,源?duì)象的屬性名, target 為目標(biāo)對(duì)象的屬性 source 和 target 沒(méi)有順序之分,按自己的來(lái)即可

生成代碼如下,注意這些代碼是直接生成到 classes 里面的
package org.aurora.mapstruct;
import javax.annotation.Generated;
import org.aurora.lombok.PersionDTO;
import org.aurora.lombok.PersonVO;
@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2022-08-11T16:24:31+0800",
comments = "version: 1.2.0.Final, compiler: javac, environment: Java 1.8.0_211 (Oracle Corporation)"
)
public class MyMapperImpl implements MyMapper {
@Override
public PersonVO transToViewObject(PersionDTO persionDTO) {
if ( persionDTO == null ) {
return null;
}
PersonVO personVO = new PersonVO();
personVO.setDes( persionDTO.getDescribe() );
personVO.setPId( persionDTO.getPId() );
personVO.setName( persionDTO.getName() );
personVO.setAge( persionDTO.getAge() );
personVO.setSex( persionDTO.getSex() );
return personVO;
}
}在Main 中測(cè)試如下:
public static void main(String[] args){
// 其實(shí)就是一個(gè)構(gòu)造方法??梢钥醋鬟B續(xù)的set 屬性。
PersionDTO persionDTO = PersionDTO.builder().pId(1515435488753L).name("小天").age(-2).sex("male").birthDay(new Date()).address("甘雨胡同十六號(hào)").height(18f).weight(4f)
.birthLocation("chinese").describe("嗷嗷嗷").married(false).hasChildren(false).hasParents(true).build();
// 轉(zhuǎn)化
PersonVO personVO = MyMapper.INSTANCE.transToViewObject(persionDTO);
System.out.println(personVO.toString());
}結(jié)果如下
PersonVO(pId=1515435488753, name=小天, age=-2, sex=male, des=嗷嗷嗷, birth=null, choice=null)
可以看出來(lái),當(dāng)兩個(gè)實(shí)體中的參數(shù)中存在一致的屬性時(shí)會(huì)被自動(dòng)轉(zhuǎn)換,屬性名對(duì)不上如果 @Mapping 沒(méi)有指定的處理方式,則不會(huì)處理,實(shí)際上這一條已經(jīng)適用于大多數(shù)場(chǎng)景。
接下來(lái)看下使用抽象類(lèi)的方式,結(jié)果大同小異
轉(zhuǎn)換類(lèi)如下定義:
package org.aurora.mapstruct;
import org.aurora.lombok.PersionDTO;
import org.aurora.lombok.PersonVO;
import org.mapstruct.AfterMapping;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.MappingTarget;
import org.mapstruct.factory.Mappers;
import java.text.SimpleDateFormat;
import java.util.Date;
@Mapper
public abstract class AbstractPersonConverter {
public static final AbstractPersonConverter INSTANCE = Mappers.getMapper(AbstractPersonConverter.class);
/**
* persionDTO 轉(zhuǎn)到 PersonVO
* @param persionDTO
* @return
*/
@Mapping(source = "describe", target = "des")
public abstract PersonVO transToViewObject(PersionDTO persionDTO);
/**
* persionDTO 轉(zhuǎn)到 personVO的后置轉(zhuǎn)換處理
* @param personVO
* @param persionDTO
*/
@AfterMapping
void changeDateIntoStr(@MappingTarget PersonVO personVO, PersionDTO persionDTO ){
Date birthDay = persionDTO.getBirthDay();
if (birthDay != null){
personVO.setBirth(transDate(birthDay));
}
}
/**
* 日期轉(zhuǎn)換
* @param date
* @return
*/
String transDate(Date date){
if (date == null){
return null;
}
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("y-M-d");
String format = simpleDateFormat.format(date);
return format;
}
}生成代碼如下:
package org.aurora.mapstruct;
import javax.annotation.Generated;
import org.aurora.lombok.PersionDTO;
import org.aurora.lombok.PersonVO;
@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2022-08-11T15:11:27+0800",
comments = "version: 1.2.0.Final, compiler: javac, environment: Java 1.8.0_211 (Oracle Corporation)"
)
public class AbstractPersonConverterImpl extends AbstractPersonConverter {
@Override
public PersonVO transToViewObject(PersionDTO persionDTO) {
if ( persionDTO == null ) {
return null;
}
PersonVO personVO = new PersonVO();
personVO.setDes( persionDTO.getDescribe() );
personVO.setPId( persionDTO.getPId() );
personVO.setName( persionDTO.getName() );
personVO.setAge( persionDTO.getAge() );
personVO.setSex( persionDTO.getSex() );
changeDateIntoStr( personVO, persionDTO );
return personVO;
}
}其中
2.@AfterMapping @BeforeMapping
為指定某類(lèi)型換為某一類(lèi)型指定的在一般Mapping 結(jié)束后附加的操作@MappingTarget PersonVO personVO 指定了最終轉(zhuǎn)換結(jié)果為 PersonVO 類(lèi)的對(duì)象,personVO 以及 persionDTO 均為入?yún)?,在這里可以做一些自己的額外操作
實(shí)驗(yàn)代碼:
public static void main(String[] args){
PersionDTO persionDTO = PersionDTO.builder().pId(1515435488753L).name("小天").age(-2).sex("male").birthDay(new Date()).address("甘雨胡同十六號(hào)").height(18f).weight(4f)
.birthLocation("chinese").describe("嗷嗷嗷").married(false).hasChildren(false).hasParents(true).build();
PersonVO personVO = AbstractPersonConverter.INSTANCE.transToViewObject(persionDTO);
System.out.println(personVO.toString());
}最終結(jié)果:
PersonVO(pId=1515435488753, name=小天, age=-2, sex=male, des=嗷嗷嗷, birth=2022-8-11, choice=null)
可以看得出最終的 結(jié)果中對(duì) birth 的特殊操作是成功進(jìn)入了最終的結(jié)果,實(shí)際上這里的時(shí)間轉(zhuǎn)換可以通過(guò) Mapstruct 的注解自帶功能完成。AfterMapping 中支持我們做更多特殊的業(yè)務(wù)操作,@BeforeMapping與 AfterMapping 相反 會(huì)在實(shí)際映射方法前執(zhí)行,但作用一致
3.多個(gè)入?yún)⑥D(zhuǎn)為一個(gè)對(duì)象
上面的方法多添加一個(gè)抽象方法如下:
@Mapping(source = "persionDTO.describe", target = "des")
@Mapping(source = "apee.ap", target = "choice")
public abstract PersonVO transToViewObject(PersionDTO persionDTO, Apee apee);生成的代碼如下:
@Override
public PersonVO transToViewObject(PersionDTO persionDTO, Apee apee) {
if ( persionDTO == null && apee == null ) {
return null;
}
PersonVO personVO = new PersonVO();
if ( persionDTO != null ) {
personVO.setDes( persionDTO.getDescribe() );
personVO.setPId( persionDTO.getPId() );
personVO.setName( persionDTO.getName() );
personVO.setAge( persionDTO.getAge() );
personVO.setSex( persionDTO.getSex() );
}
if ( apee != null ) {
personVO.setChoice( apee.getAp() );
}
changeDateIntoStr( personVO, persionDTO );
return personVO;
}測(cè)試代碼:
public static void main(String[] args){
PersionDTO persionDTO = PersionDTO.builder().pId(1515435488753L).name("小天").age(-2).sex("male").birthDay(new Date()).address("甘雨胡同十六號(hào)").height(18f).weight(4f)
.birthLocation("chinese").describe("嗷嗷嗷").married(false).hasChildren(false).hasParents(true).build();
Apee apee = new Apee();
apee.setAp("hahahahahaha");
PersonVO personVO = AbstractPersonConverter.INSTANCE.transToViewObject(persionDTO, apee);
System.out.println(personVO.toString());
}結(jié)果:
PersonVO(pId=1515435488753, name=小天, age=-2, sex=male, des=嗷嗷嗷, birth=2022-8-11, choice=hahahahahaha)
這里需要注意的是,當(dāng)你的多個(gè)對(duì)象作為入?yún)r(shí),多個(gè)對(duì)象均含有同一個(gè)屬性時(shí)即當(dāng)目標(biāo)對(duì)象與另外多個(gè)入?yún)⒍己幸粋€(gè)或多個(gè)相同屬性時(shí),在mapping 也需要指定,否則不知道拿哪個(gè)屬性會(huì)拋出異常。
4.當(dāng)源屬性沒(méi)有時(shí)指定默認(rèn)值
在Mapping 中添加 default 屬性,給與默認(rèn)值即可,例如:
@Mapping(source = "persionDTO.describe", target = "des")
@Mapping(source = "apee.ap", target = "choice", defaultValue = "給個(gè)默認(rèn)值")
public abstract PersonVO transToViewObject(PersionDTO persionDTO, Apee apee);生成的代碼
@Override
public PersonVO transToViewObject(PersionDTO persionDTO, Apee apee) {
if ( persionDTO == null && apee == null ) {
return null;
}
PersonVO personVO = new PersonVO();
if ( persionDTO != null ) {
personVO.setDes( persionDTO.getDescribe() );
personVO.setPId( persionDTO.getPId() );
personVO.setName( persionDTO.getName() );
personVO.setAge( persionDTO.getAge() );
personVO.setSex( persionDTO.getSex() );
}
if ( apee != null ) {
if ( apee.getAp() != null ) {
personVO.setChoice( apee.getAp() );
}
else {
personVO.setChoice( "給個(gè)默認(rèn)值" );
}
}
changeDateIntoStr( personVO, persionDTO );
return personVO;
}執(zhí)行測(cè)試代碼:
public static void main(String[] args){
PersionDTO persionDTO = PersionDTO.builder().pId(1515435488753L).name("小天").age(-2).sex("male").birthDay(new Date()).address("甘雨胡同十六號(hào)").height(18f).weight(4f)
.birthLocation("chinese").describe("嗷嗷嗷").married(false).hasChildren(false).hasParents(true).build();
Apee apee = new Apee();
// apee.setAp("hahahahahaha");
PersonVO personVO = AbstractPersonConverter.INSTANCE.transToViewObject(persionDTO, apee);
System.out.println(personVO.toString());
}結(jié)果:
PersonVO(pId=1515435488753, name=小天, age=-2, sex=male, des=嗷嗷嗷, birth=2022-8-11, choice=給個(gè)默認(rèn)值)
5.一般的類(lèi)型以及日期轉(zhuǎn)換(dateFormat), 數(shù)字轉(zhuǎn)換(numberFormat)
之前的 Apee 定義如下
package org.aurora.lombok;
import java.util.Date;
public class Apee {
private String ap;
private String cp;
private Date timeAA;
private String strTime;
public String getCp() {
return cp;
}
public void setCp(String cp) {
this.cp = cp;
}
public Date getTimeAA() {
return timeAA;
}
public void setTimeAA(Date timeAA) {
this.timeAA = timeAA;
}
public String getStrTime() {
return strTime;
}
public void setStrTime(String strTime) {
this.strTime = strTime;
}
public Apee() {
}
public Apee(String ap, String cp) {
this.ap = ap;
this.cp = cp;
}
public String getAp() {
return ap;
}
public void setAp(String ap) {
this.ap = ap;
}
@Override
public String toString() {
return "Apee{" +
"ap='" + ap + '\'' +
", cp='" + cp + '\'' +
", timeAA=" + timeAA +
", strTime='" + strTime + '\'' +
'}';
}
}抽象方法定義如下:
@Mapping(source = "persionDTO.birthDay", target = "strTime", dateFormat = "yyyy-MM-dd")
@Mapping(source = "persionDTO.describe", target = "timeAA", dateFormat = "yyyy-MM-dd")
@Mapping(source = "persionDTO.age", target = "ap")
public abstract Apee transDateToApee(PersionDTO persionDTO);生成代碼:
@Override
public Apee transDateToApee(PersionDTO persionDTO) {
if ( persionDTO == null ) {
return null;
}
Apee apee = new Apee();
try {
if ( persionDTO.getDescribe() != null ) {
apee.setTimeAA( new SimpleDateFormat( "yyyy-MM-dd" ).parse( persionDTO.getDescribe() ) );
}
}
catch ( ParseException e ) {
throw new RuntimeException( e );
}
if ( persionDTO.getBirthDay() != null ) {
apee.setStrTime( new SimpleDateFormat( "yyyy-MM-dd" ).format( persionDTO.getBirthDay() ) );
}
if ( persionDTO.getAge() != null ) {
apee.setAp( String.valueOf( persionDTO.getAge() ) );
}
return apee;
}測(cè)試代碼:
public static void main(String[] args){
PersionDTO persionDTO = PersionDTO.builder().pId(1515435488753L).name("小天").age(-2).sex("male").birthDay(new Date()).address("甘雨胡同十六號(hào)").height(18f).weight(4f)
.birthLocation("chinese").describe("2022-07-08").married(false).hasChildren(false).hasParents(true).build();
Apee personVO = AbstractPersonConverter.INSTANCE.transDateToApee(persionDTO);
System.out.println(personVO.toString());
}測(cè)試結(jié)果:
Apee{ap='-2', cp='null', timeAA=Fri Jul 08 00:00:00 CST 2022, strTime='2022-08-11'}
可以看的出當(dāng)指定日期格式 dateFormat 時(shí) 不論是從 String 到 Date 還是 Date 到 String 還是一般的類(lèi)型轉(zhuǎn) String 等等都可以自動(dòng)完成適應(yīng),而且我發(fā)現(xiàn)當(dāng)我提供 日期轉(zhuǎn)換方法時(shí)它竟然自動(dòng)引用了我的方法,當(dāng)我刪除時(shí),它使用了自己生成的代碼
在上方轉(zhuǎn)化代碼中我提供了
/**
* 日期轉(zhuǎn)換
* @param date
* @return
*/
String transDate(Date date){
if (date == null){
return null;
}
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("y-M-d");
String format = simpleDateFormat.format(date);
return format;
}結(jié)果生成的代碼如下:
@Override
public Apee transDateToApee(PersionDTO persionDTO) {
if ( persionDTO == null ) {
return null;
}
Apee apee = new Apee();
try {
if ( persionDTO.getDescribe() != null ) {
apee.setTimeAA( new SimpleDateFormat( "yyyy-MM-dd" ).parse( persionDTO.getDescribe() ) );
}
}
catch ( ParseException e ) {
throw new RuntimeException( e );
}
apee.setStrTime( transDate( persionDTO.getBirthDay() ) );
if ( persionDTO.getAge() != null ) {
apee.setAp( String.valueOf( persionDTO.getAge() ) );
}
return apee;
}官方支持的基本類(lèi)型自動(dòng)轉(zhuǎn)換大致如下:
基本類(lèi)型及其對(duì)應(yīng)的包裝類(lèi)之間:比如, int 和 Integer, float 和 Float, long 和 Long,boolean 和 Boolean 等
任意基本類(lèi)型與任意包裝類(lèi)之間:如 int 和 long, byte 和 Integer 等
所有基本類(lèi)型及包裝類(lèi)與String之間:如 boolean 和 String, Integer 和 String, float 和 String 等枚舉和String之間。
Java大數(shù)類(lèi)型(java.math.BigInteger, java.math.BigDecimal) 和Java基本類(lèi)型(包括其包裝類(lèi))與String之間
數(shù)字轉(zhuǎn)String numberFormat
即 數(shù)字類(lèi)型轉(zhuǎn)String 指定格式下也是支持的
上面方法修改如下:
@Mapping(source = "persionDTO.birthDay", target = "strTime", dateFormat = "yyyy-MM-dd")
@Mapping(source = "persionDTO.describe", target = "timeAA", dateFormat = "yyyy-MM-dd")
@Mapping(source = "persionDTO.age", target = "ap", numberFormat = "#0.00歲")
public abstract Apee transDateToApee(PersionDTO persionDTO);生成的關(guān)鍵代碼:
if ( persionDTO.getAge() != null ) {
apee.setAp( new DecimalFormat( "#0.00歲" ).format( persionDTO.getAge() ) );
}實(shí)際測(cè)試輸出后:
Apee{ap='-2.00歲', cp='null', timeAA=Fri Jul 08 00:00:00 CST 2022, strTime='2022-8-12'}
6.Expression 表達(dá)式以及 Mappings
Expression 可以用來(lái)替代 source 中的一般屬性,允許直接寫(xiě)入一般的 java 表達(dá)式,即自己提供source 的表達(dá)式,但目前支持 Java 一種語(yǔ)言。
Mappings 可以理解為一個(gè) 普通 Mapping 的父標(biāo)簽,允許里面放多個(gè) Mapping 使用 ,分割與直接寫(xiě) 多個(gè)Mapping 沒(méi)什么區(qū)別,
Expression 與 Mappings 沒(méi)必要連用,這里只是為了同時(shí)介紹
示例如下:
@Mappings({
@Mapping(expression = "java( new java.util.Date() )", target = "timeAA"),
@Mapping(source = "persionDTO.age", target = "ap")
})
public abstract Apee transExpressionToApee(PersionDTO persionDTO);生成的代碼如下:
@Override
public Apee transExpressionToApee(PersionDTO persionDTO) {
if ( persionDTO == null ) {
return null;
}
Apee apee = new Apee();
if ( persionDTO.getAge() != null ) {
apee.setAp( String.valueOf( persionDTO.getAge() ) );
}
apee.setTimeAA( new java.util.Date() );
return apee;
}7.轉(zhuǎn)換時(shí) 不使用對(duì)象中的同名屬性 使用指定參數(shù)作為某一屬性的值
當(dāng)我們兩個(gè)對(duì)象中的屬性一樣,但是并不想使用時(shí)可以如下類(lèi)似定義此時(shí) PersonVO PersionDTO均含有PId 但是我并不想使用對(duì)象中的值而是采用我傳入的值,則如下:
/**
* 使用其他值
* @param persionDTO
* @param id
* @return
*/
@Mapping(source = "persionDTO.describe", target = "des")
@Mapping(source = "id", target = "PId")
public abstract PersonVO transToViewObject2(PersionDTO persionDTO, Long id);注意如果有其他值需要特殊處理時(shí) 需要如上指定參數(shù),否則可能編譯時(shí)出現(xiàn)錯(cuò)誤
生成的代碼
@Override
public PersonVO transToViewObject2(PersionDTO persionDTO, Long id) {
if ( persionDTO == null && id == null ) {
return null;
}
PersonVO personVO = new PersonVO();
if ( persionDTO != null ) {
personVO.setDes( persionDTO.getDescribe() );
personVO.setName( persionDTO.getName() );
personVO.setAge( persionDTO.getAge() );
personVO.setSex( persionDTO.getSex() );
}
if ( id != null ) {
personVO.setPId( id );
}
return personVO;
}8.其他類(lèi)作為屬性時(shí)
與一般的引用類(lèi)型一致,當(dāng)兩個(gè)類(lèi)中都含有某一個(gè)同類(lèi)型的同名屬性時(shí),即使是類(lèi)也會(huì)自動(dòng)映射,如果類(lèi)型一致,但是名稱(chēng)不一致,則指定名稱(chēng)后依舊會(huì)自動(dòng)映射上面的兩個(gè)類(lèi)中添加同一類(lèi)型的一個(gè)類(lèi)如下:


轉(zhuǎn)換方法如下定義:
@Mapping(source = "describe", target = "des")
@Mapping(source = "apee", target = "apee2")
public abstract PersonVO transToViewObject(PersionDTO persionDTO);生成代碼如下
@Override
public PersonVO transToViewObject(PersionDTO persionDTO) {
if ( persionDTO == null ) {
return null;
}
PersonVO personVO = new PersonVO();
personVO.setApee2( persionDTO.getApee() );
personVO.setDes( persionDTO.getDescribe() );
personVO.setPId( persionDTO.getPId() );
personVO.setName( persionDTO.getName() );
personVO.setAge( persionDTO.getAge() );
personVO.setSex( persionDTO.getSex() );
return personVO;
}9.逆映射
即 一個(gè)文件內(nèi),兩個(gè)類(lèi)之間互相轉(zhuǎn)換映射時(shí)其實(shí)只要寫(xiě)好其中一個(gè)映射,另一個(gè)可以通過(guò)注解繼承原有映射配置,即原有的 target 與 source 會(huì)互換
@Mapping(source = "describe", target = "des")
@Mapping(source = "apee", target = "apee2")
public abstract PersonVO transToViewObject(PersionDTO persionDTO);
@InheritInverseConfiguration
public abstract PersionDTO transToViewObject(PersonVO personVO);生成代碼:
@Override
public PersonVO transToViewObject(PersionDTO persionDTO) {
if ( persionDTO == null ) {
return null;
}
PersonVO personVO = new PersonVO();
personVO.setApee2( persionDTO.getApee() );
personVO.setDes( persionDTO.getDescribe() );
personVO.setPId( persionDTO.getPId() );
personVO.setName( persionDTO.getName() );
personVO.setAge( persionDTO.getAge() );
personVO.setSex( persionDTO.getSex() );
return personVO;
}
@Override
public PersionDTO transToViewObject(PersonVO personVO) {
if ( personVO == null ) {
return null;
}
PersionDTO persionDTO = new PersionDTO();
persionDTO.setApee( personVO.getApee2() );
persionDTO.setDescribe( personVO.getDes() );
persionDTO.setPId( personVO.getPId() );
persionDTO.setName( personVO.getName() );
persionDTO.setAge( personVO.getAge() );
persionDTO.setSex( personVO.getSex() );
return persionDTO;
}10.支持注入spring
在mapper 上添加注解 類(lèi)似如下:

之后該類(lèi)可通過(guò) @Autowired 注入方式引入到文件中
11. 自定義映射 ,list, Map, 枚舉
以下四種映射案例參考了其他文章的代碼參考博客
自定義映射 @Named
// 自定義的映射方法:轉(zhuǎn)換boolen為String時(shí),做一些判斷然后返回對(duì)應(yīng)的值。
@Named("DoneFormater")
public class DoneFormater {
@Named("DoneFormater")
public String toStr(Boolean isDone) {
if (isDone) {
return "已完成";
} else {
return "未完成";
}
}
@Named("DoneDetailFormater")
public String toDetail(Boolean isDone) {
if (isDone) {
return "該產(chǎn)品已完成";
} else {
return "該產(chǎn)品未完成";
}
}
public Boolean toBoolean(String str) {
if (str.equals("已完成")) {
return true;
} else {
return false;
}
}
}
// 通過(guò)uses 來(lái)導(dǎo)入上面我們寫(xiě)的 自定義映射方法
@Mapper( uses = {DoneFormater.class})
public interface ObjectQualiferMapper {
ObjectQualiferMapper INSTANCE = Mappers.getMapper(ObjectQualiferMapper.class);
// 當(dāng)有多個(gè)方法 擁有一樣的參數(shù)和返回類(lèi)型時(shí),需要指定使用其中的哪一個(gè),使用qualifiedByName指定
@Mapping(source = "isDone", target = "isDone", qualifiedByName = "DoneDetailFormater")
ProductDTO toDto(Product product);
}List 映射
@Mapper(componentModel = "spring")
public interface UserMapping {
/**
* Student 轉(zhuǎn)化為 User
* @param Student
* @return
*/
User studentToUser(Student student);
// 當(dāng)執(zhí)行 下面這個(gè)List的轉(zhuǎn)換時(shí),會(huì)遍歷list: students,
// 然后自動(dòng)調(diào)用上面的Student轉(zhuǎn)User的轉(zhuǎn)換方法,來(lái)進(jìn)行轉(zhuǎn)換
/**
* Students 轉(zhuǎn)化為 Users
* @param Students
* @return
*/
List<user> studentsToUsers(List<student> students);
}map 映射
@Mapper
public interface MapMapper {
MapMapper INSTANCE = Mappers.getMapper(MapMapper.class);
@MapMapping(valueDateFormat = "yyyy-MM-dd HH:mm:ss")
Map<string, string=""> toDTO(Map<long, date=""> map);
}枚舉
public enum E1 {
E1_1,
E1_2,
E1_3
}
public enum E2 {
E2_1,
E2_2,
E2_3
}映射方法:使用@ValueMappings和@ValueMapping ,可以理解成是用if判斷枚舉值,然后返回對(duì)應(yīng)結(jié)果
@Mapper
public interface DataEnumMapper {
DataEnumMapper INSTANCE = Mappers.getMapper(DataEnumMapper.class);
@ValueMappings({
@ValueMapping(target = "E1_1", source = "E2_1"),
@ValueMapping(target = "E1_2", source = "E2_2"),
@ValueMapping(target = MappingConstants.NULL, source = "E2_3") //轉(zhuǎn)換成null
})
E1 toDTO(E2 e2);
}Final. 其他問(wèn)題
出現(xiàn)問(wèn)題 Couldn’t retrieve @Mapper annotation
可能是 項(xiàng)目中使用了swagger,swagger里面也包含mapstruct,排除掉就好
<dependency>
<groupid>io.springfox</groupid>
<artifactid>springfox-swagger2</artifactid>
<version>${swagger2.version}</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<groupid>org.mapstruct</groupid>
<artifactid>mapstruct</artifactid>
</exclusion>
</exclusions>
</dependency>也可能是 導(dǎo)入mapstruct項(xiàng)目時(shí),同時(shí)使用了 mapstruct-jdk8 和 mapstruct-processor 但版本不一致,將版本號(hào)改為一樣即可
更多詳細(xì)說(shuō)明參見(jiàn)官網(wǎng)說(shuō)明文檔
https://mapstruct.org/documentation/stable/reference/html/#defining-mapper
到此這篇關(guān)于Mapstruct @Mapper @Mapping 使用介紹以及總結(jié)的文章就介紹到這了,更多相關(guān)Mapstruct @Mapper @Mapping 使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解如何使用Jersey客戶(hù)端請(qǐng)求Spring Boot(RESTFul)服務(wù)
本篇文章主要介紹了詳解如何使用Jersey客戶(hù)端請(qǐng)求Spring Boot(RESTFul)服務(wù),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-01-01
解決使用this.getClass().getResource()獲取文件時(shí)遇到的坑
這篇文章主要介紹了解決使用this.getClass().getResource()獲取文件時(shí)遇到的坑問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12
詳細(xì)說(shuō)明關(guān)于Java的數(shù)據(jù)庫(kù)連接(JDBC)
這篇文章主要介紹了詳細(xì)說(shuō)明關(guān)于Java的數(shù)據(jù)庫(kù)連接JDBC,JDBC是用Java語(yǔ)言向數(shù)據(jù)庫(kù)發(fā)送SQL語(yǔ)句,需要的朋友可以參考下面文章內(nèi)容2021-09-09

