Mapstruct?@Mapper?@Mapping?使用小結(jié)
作用
用于各個對象實體間的相互轉(zhuǎn)換,例如數(shù)據(jù)庫底層實體 轉(zhuǎn)為頁面對象,Model 轉(zhuǎn)為 DTO(data transfer object 數(shù)據(jù)轉(zhuǎn)換實體), DTO 轉(zhuǎn)為其他中間對象, VO 等等,相關(guān)轉(zhuǎn)換代碼為編譯時自動產(chǎn)生的新文件和代碼。
兩個對象之間相同屬性名的會被自動轉(zhuǎn)換,指定特殊情況時需要通過注解在抽象方法上說明不同屬性之間的轉(zhuǎn)換。
轉(zhuǎn)換方法一般均為抽象方法,所以這一類文件一般使用 接口 類,或者抽象類均可,官方的介紹一般均使用了接口類文件來完成。如果感興趣可以到官網(wǎng)看看
Maven 依賴
官方給與的示例配置,建議使用官方推薦的版本
...
<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)過一些實驗后,發(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 不論哪種形式兩個都需要同時存在,mapstruct 提供了注解等,mapstruct-processor 會在編譯時將相關(guān)接口文件的實現(xiàn)類生成出來,最終完成想要的映射實現(xiàn)。
若與 lombok 連用
如果同時使用了另一個 lombok 代碼生成相關(guān)的依賴,那么需要注意lombok maven 依賴版本需要在 1.16.16 以上,否則可能會出現(xiàn)
**No property named “XXX“ exists in source parameter(s). Did you mean “null“?**之類的錯誤
使用示例
1.基本使用
定義兩個類如下:
這里使用了lombok 實際上僅僅是簡化了 get set 以及構(gòu)造方法之類的。
如果需要,可以看看另一篇關(guān)于 lombok 的介紹@Data 注解使用 lombok插件學(xué)習(xí)總結(jié)
實體一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 編譯時幫助實現(xiàn)了 get set 方法
@AllArgsConstructor 全參構(gòu)造函數(shù)
@NoArgsConstructor 無參構(gòu)造函數(shù)
@Builder 允許使用 builder 方式構(gòu)造對象,其實和構(gòu)造函數(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;
}開始加入 MapStruct 的轉(zhuǎn)換相關(guān)的,注意這里我定義的是抽象類,實際上使用接口類也可以先看看正常的接口類
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)前類認(rèn)為是要執(zhí)行 MapStruct 相關(guān)操作的類
@Mapping 為指定某些特殊映射的注解,沒有指定的內(nèi)容,當(dāng)源對象與 目標(biāo)對象擁有一樣的屬性時會自動轉(zhuǎn)換
INSTANCE 是為了在外面外面調(diào)用該方法, 接口中的屬性默認(rèn)為靜態(tài)屬性所以可以直接調(diào)用到
@Mapping 中 source 為入?yún)?,源對象的屬性名?target 為目標(biāo)對象的屬性 source 和 target 沒有順序之分,按自己的來即可

生成代碼如下,注意這些代碼是直接生成到 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 中測試如下:
public static void main(String[] args){
// 其實就是一個構(gòu)造方法??梢钥醋鬟B續(xù)的set 屬性。
PersionDTO persionDTO = PersionDTO.builder().pId(1515435488753L).name("小天").age(-2).sex("male").birthDay(new Date()).address("甘雨胡同十六號").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)
可以看出來,當(dāng)兩個實體中的參數(shù)中存在一致的屬性時會被自動轉(zhuǎn)換,屬性名對不上如果 @Mapping 沒有指定的處理方式,則不會處理,實際上這一條已經(jīng)適用于大多數(shù)場景。
接下來看下使用抽象類的方式,結(jié)果大同小異
轉(zhuǎn)換類如下定義:
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
為指定某類型換為某一類型指定的在一般Mapping 結(jié)束后附加的操作@MappingTarget PersonVO personVO 指定了最終轉(zhuǎn)換結(jié)果為 PersonVO 類的對象,personVO 以及 persionDTO 均為入?yún)?,在這里可以做一些自己的額外操作
實驗代碼:
public static void main(String[] args){
PersionDTO persionDTO = PersionDTO.builder().pId(1515435488753L).name("小天").age(-2).sex("male").birthDay(new Date()).address("甘雨胡同十六號").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é)果中對 birth 的特殊操作是成功進(jìn)入了最終的結(jié)果,實際上這里的時間轉(zhuǎn)換可以通過 Mapstruct 的注解自帶功能完成。AfterMapping 中支持我們做更多特殊的業(yè)務(wù)操作,@BeforeMapping與 AfterMapping 相反 會在實際映射方法前執(zhí)行,但作用一致
3.多個入?yún)⑥D(zhuǎn)為一個對象
上面的方法多添加一個抽象方法如下:
@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;
}測試代碼:
public static void main(String[] args){
PersionDTO persionDTO = PersionDTO.builder().pId(1515435488753L).name("小天").age(-2).sex("male").birthDay(new Date()).address("甘雨胡同十六號").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)你的多個對象作為入?yún)r,多個對象均含有同一個屬性時即當(dāng)目標(biāo)對象與另外多個入?yún)⒍己幸粋€或多個相同屬性時,在mapping 也需要指定,否則不知道拿哪個屬性會拋出異常。
4.當(dāng)源屬性沒有時指定默認(rèn)值
在Mapping 中添加 default 屬性,給與默認(rèn)值即可,例如:
@Mapping(source = "persionDTO.describe", target = "des")
@Mapping(source = "apee.ap", target = "choice", defaultValue = "給個默認(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( "給個默認(rèn)值" );
}
}
changeDateIntoStr( personVO, persionDTO );
return personVO;
}執(zhí)行測試代碼:
public static void main(String[] args){
PersionDTO persionDTO = PersionDTO.builder().pId(1515435488753L).name("小天").age(-2).sex("male").birthDay(new Date()).address("甘雨胡同十六號").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=給個默認(rèn)值)
5.一般的類型以及日期轉(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;
}測試代碼:
public static void main(String[] args){
PersionDTO persionDTO = PersionDTO.builder().pId(1515435488753L).name("小天").age(-2).sex("male").birthDay(new Date()).address("甘雨胡同十六號").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());
}測試結(jié)果:
Apee{ap='-2', cp='null', timeAA=Fri Jul 08 00:00:00 CST 2022, strTime='2022-08-11'}
可以看的出當(dāng)指定日期格式 dateFormat 時 不論是從 String 到 Date 還是 Date 到 String 還是一般的類型轉(zhuǎn) String 等等都可以自動完成適應(yīng),而且我發(fā)現(xiàn)當(dāng)我提供 日期轉(zhuǎn)換方法時它竟然自動引用了我的方法,當(dāng)我刪除時,它使用了自己生成的代碼
在上方轉(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;
}官方支持的基本類型自動轉(zhuǎn)換大致如下:
基本類型及其對應(yīng)的包裝類之間:比如, int 和 Integer, float 和 Float, long 和 Long,boolean 和 Boolean 等
任意基本類型與任意包裝類之間:如 int 和 long, byte 和 Integer 等
所有基本類型及包裝類與String之間:如 boolean 和 String, Integer 和 String, float 和 String 等枚舉和String之間。
Java大數(shù)類型(java.math.BigInteger, java.math.BigDecimal) 和Java基本類型(包括其包裝類)與String之間
數(shù)字轉(zhuǎn)String numberFormat
即 數(shù)字類型轉(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() ) );
}實際測試輸出后:
Apee{ap='-2.00歲', cp='null', timeAA=Fri Jul 08 00:00:00 CST 2022, strTime='2022-8-12'}
6.Expression 表達(dá)式以及 Mappings
Expression 可以用來替代 source 中的一般屬性,允許直接寫入一般的 java 表達(dá)式,即自己提供source 的表達(dá)式,但目前支持 Java 一種語言。
Mappings 可以理解為一個 普通 Mapping 的父標(biāo)簽,允許里面放多個 Mapping 使用 ,分割與直接寫 多個Mapping 沒什么區(qū)別,
Expression 與 Mappings 沒必要連用,這里只是為了同時介紹
示例如下:
@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ù)作為某一屬性的值
當(dāng)我們兩個對象中的屬性一樣,但是并不想使用時可以如下類似定義此時 PersonVO PersionDTO均含有PId 但是我并不想使用對象中的值而是采用我傳入的值,則如下:
/**
* 使用其他值
* @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ù),否則可能編譯時出現(xiàn)錯誤
生成的代碼
@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.其他類作為屬性時
與一般的引用類型一致,當(dāng)兩個類中都含有某一個同類型的同名屬性時,即使是類也會自動映射,如果類型一致,但是名稱不一致,則指定名稱后依舊會自動映射上面的兩個類中添加同一類型的一個類如下:


轉(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.逆映射
即 一個文件內(nèi),兩個類之間互相轉(zhuǎn)換映射時其實只要寫好其中一個映射,另一個可以通過注解繼承原有映射配置,即原有的 target 與 source 會互換
@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 上添加注解 類似如下:

之后該類可通過 @Autowired 注入方式引入到文件中
11. 自定義映射 ,list, Map, 枚舉
以下四種映射案例參考了其他文章的代碼參考博客
自定義映射 @Named
// 自定義的映射方法:轉(zhuǎn)換boolen為String時,做一些判斷然后返回對應(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;
}
}
}
// 通過uses 來導(dǎo)入上面我們寫的 自定義映射方法
@Mapper( uses = {DoneFormater.class})
public interface ObjectQualiferMapper {
ObjectQualiferMapper INSTANCE = Mappers.getMapper(ObjectQualiferMapper.class);
// 當(dāng)有多個方法 擁有一樣的參數(shù)和返回類型時,需要指定使用其中的哪一個,使用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í)行 下面這個List的轉(zhuǎn)換時,會遍歷list: students,
// 然后自動調(diào)用上面的Student轉(zhuǎn)User的轉(zhuǎn)換方法,來進(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判斷枚舉值,然后返回對應(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. 其他問題
出現(xiàn)問題 Couldn’t retrieve @Mapper annotation
可能是 項目中使用了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項目時,同時使用了 mapstruct-jdk8 和 mapstruct-processor 但版本不一致,將版本號改為一樣即可
更多詳細(xì)說明參見官網(wǎng)說明文檔
https://mapstruct.org/documentation/stable/reference/html/#defining-mapper
到此這篇關(guān)于Mapstruct @Mapper @Mapping 使用介紹以及總結(jié)的文章就介紹到這了,更多相關(guān)Mapstruct @Mapper @Mapping 使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解如何使用Jersey客戶端請求Spring Boot(RESTFul)服務(wù)
本篇文章主要介紹了詳解如何使用Jersey客戶端請求Spring Boot(RESTFul)服務(wù),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-01-01
解決使用this.getClass().getResource()獲取文件時遇到的坑
這篇文章主要介紹了解決使用this.getClass().getResource()獲取文件時遇到的坑問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-12-12
詳細(xì)說明關(guān)于Java的數(shù)據(jù)庫連接(JDBC)
這篇文章主要介紹了詳細(xì)說明關(guān)于Java的數(shù)據(jù)庫連接JDBC,JDBC是用Java語言向數(shù)據(jù)庫發(fā)送SQL語句,需要的朋友可以參考下面文章內(nèi)容2021-09-09

