一、準備工作
1.1、了解@Mapper 注解
從 mybatis3.4.0 開始加入的 @Mapper 注解,目的就是為了不再寫mapper映射文件。
我們只需要在 dao 層定義的接口上使用注解就可以實現sql語句的編寫,例如:
@select("select*fromuserwherename=#{name}")publicUserfind(Stringname);
如上就是一個簡單的使用,雖然簡單,但也確實體現出了這個注解的優越性,至少少寫了一個xml文件。
所以我就只是想說下 @Mapper 注解的 componentmodel 屬性,componentModel 屬性用于指定自動生成的接口實現類的組件類型,這個屬性支持四個值:
default: 這是默認的情況,mapstruct 不使用任何組件類型, 可以通過Mappers.getMapper(Class)方式獲取自動生成的實例對象。
cdi: the generated mapper is an application-scoped CDI bean and can be retrieved via @Inject
spring: 生成的實現類上面會自動添加一個@Component注解,可以通過Spring的 @Autowired方式進行注入
jsr330: 生成的實現類上會添加@javax.inject.Named 和@Singleton注解,可以通過 @Inject注解獲取
1.2、依賴包
首先需要把依賴包導入,主要由兩個包組成:
org.mapstruct:mapstruct:包含了一些必要的注解,例如@Mapping。r若我們使用的JDK版本高于1.8,當我們在pom里面導入依賴時候,建議使用坐標是:org.mapstruct:mapstruct-jdk8,這可以幫助我們利用一些Java8的新特性。
org.mapstruct:mapstruct-processor:注解處理器,根據注解自動生成mapper的實現。
<dependency><groupId>org.mapstruct</groupId><!--jdk8以下就使用mapstruct--><artifactId>mapstruct-jdk8</artifactId><version>1.2.0.Final</version></dependency><dependency><groupId>org.mapstruct</groupId><artifactId>mapstruct-processor</artifactId><version>1.2.0.Final</version></dependency>
好了,準備工作做完了,接下來我們就看看巧媳婦兒巧在什么地方吧。
二、先簡單玩一把
2.1、定義實體類以及被映射類
//實體類@Data@NoArgsConstructor@AllArgsConstructor@BuilderpublicclassUser{privateIntegerid;privateStringname;privateStringcreateTime;privateLocalDateTimeupdateTime;}//被映射類VO1:和實體類一模一樣@Data@NoArgsConstructor@AllArgsConstructor@BuilderpublicclassUserVO1{privateIntegerid;privateStringname;privateStringcreateTime;privateLocalDateTimeupdateTime;}//被映射類VO1:比實體類少一個字段@Data@NoArgsConstructor@AllArgsConstructor@BuilderpublicclassUserVO2{privateIntegerid;privateStringname;privateStringcreateTime;}
2.2、定義接口:
當實體類和被映射對象屬性相同或者被映射對象屬性值少幾個時:
@Mapper(componentModel="spring")publicinterfaceUserCovertBasic{UserCovertBasicINSTANCE=Mappers.getMapper(UserCovertBasic.class);/***字段數量類型數量相同,利用工具BeanUtils也可以實現類似效果*@paramsource*@return*/UserVO1toConvertVO1(Usersource);UserfromConvertEntity1(UserVO1userVO1);/***字段數量類型相同,數量少:僅能讓多的轉換成少的,故沒有fromConvertEntity2*@paramsource*@return*/UserVO2toConvertVO2(Usersource);}
從上面的代碼可以看出:接口中聲明了一個成員變量INSTANCE,母的是讓客戶端可以訪問 Mapper 接口的實現。
2.3、使用
@RestControllerpublicclassTestController{@GetMapping("convert")publicObjectconvertEntity(){Useruser=User.builder().id(1).name("張三").createTime("2020-04-0111:05:07").updateTime(LocalDateTime.now()).build();List<Object>objectList=newArrayList<>();objectList.add(user);//使用mapstructUserVO1userVO1=UserCovertBasic.INSTANCE.toConvertVO1(user);objectList.add("userVO1:"+UserCovertBasic.INSTANCE.toConvertVO1(user));objectList.add("userVO1轉換回實體類user:"+UserCovertBasic.INSTANCE.fromConvertEntity1(userVO1));//輸出轉換結果objectList.add("userVO2:"+"|"+UserCovertBasic.INSTANCE.toConvertVO2(user));//使用BeanUtilsUserVO2userVO22=newUserVO2();BeanUtils.copyProperties(user,userVO22);objectList.add("userVO22:"+"|"+userVO22);returnobjectList;}}
2.4、查看編譯結果
通過IDE的反編譯功能查看編譯后自動生成 UserCovertBasic 的實現類 UserCovertBasicImpl ,內容如下:
@ComponentpublicclassUserCovertBasicImplimplementsUserCovertBasic{publicUserCovertBasicImpl(){}publicUserVO1toConvertVO1(Usersource){if(source==null){returnnull;}else{UserVO1userVO1=newUserVO1();userVO1.setId(source.getId());userVO1.setName(source.getName());userVO1.setCreateTime(source.getCreateTime());userVO1.setUpdateTime(source.getUpdateTime());returnuserVO1;}}publicUserfromConvertEntity1(UserVO1userVO1){if(userVO1==null){returnnull;}else{Useruser=newUser();user.setId(userVO1.getId());user.setName(userVO1.getName());user.setCreateTime(userVO1.getCreateTime());user.setUpdateTime(userVO1.getUpdateTime());returnuser;}}publicUserVO2toConvertVO2(Usersource){if(source==null){returnnull;}else{UserVO2userVO2=newUserVO2();userVO2.setId(source.getId());userVO2.setName(source.getName());userVO2.setCreateTime(source.getCreateTime());returnuserVO2;}}}
2.5、瀏覽器查看結果
好了,一個流程就走完了,是不是感覺賊簡單呢?
而且呀,阿粉溫馨提醒:如果是要轉換一個集合的話,只需要把這里的實體類換成集合就行了,例如:
List<UserVO1>toConvertVOList(List<User>source);
三、不簡單的情況
上面已經把整個流程都給過了一遍了,相信大家對 mapstruct 也有了一個基礎的了解了,所以接下來的情況我們就不展示全部代碼了,畢竟篇幅也有限,所以就直接上關鍵代碼(因為不關鍵的和上面內容一樣,哈哈)
3.1、類型不一致
實體類我們還是沿用 User;被映射對象 UserVO3 改為:
@Data@NoArgsConstructor@AllArgsConstructor@BuilderpublicclassUserVO3{privateStringid;privateStringname;//實體類該屬性是StringprivateLocalDateTimecreateTime;//實體類該屬性是LocalDateTimeprivateStringupdateTime;}
那么我們定義的接口就要稍稍修改一下了:
@Mappings({@Mapping(target="createTime",expression="java(com.java.mmzsblog.util.DateTransform.strToDate(source.getCreateTime()))"),})UserVO3toConvertVO3(Usersource);UserfromConvertEntity3(UserVO3userVO3);
上面 expression 指定的表達式內容如下:
publicclassDateTransform{publicstaticLocalDateTimestrToDate(Stringstr){DateTimeFormatterdf=DateTimeFormatter.ofPattern("yyy-MM-ddHH:mm:ss");returnLocalDateTime.parse("2018-01-1217:07:05",df);}}
通過IDE的反編譯功能查看編譯后的實現類,結果是這樣子的:
從圖中我們可以看到,編譯時使用了expression中定義的表達式對目標字段 createTime 進行了轉換;然后你還會發現 updateTime 字段也被自動從 LocalDateTime 類型轉換成了 String 類型。
阿粉小結:
當字段類型不一致時,以下的類型之間是 mapstruct 自動進行類型轉換的:
1、基本類型及其他們對應的包裝類型。此時 mapstruct 會自動進行拆裝箱。不需要人為的處理
2、基本類型的包裝類型和string類型之間
除此之外的類型轉換我們可以通過定義表達式來進行指定轉換。
3.2、字段名不一致
實體類我們還是沿用 User;被映射對象 UserVO4 改為:
@Data@NoArgsConstructor@AllArgsConstructor@BuilderpublicclassUserVO4{//實體類該屬性名是idprivateStringuserId;//實體類該屬性名是nameprivateStringuserName;privateStringcreateTime;privateStringupdateTime;}
那么我們定義的接口就要稍稍修改一下了:
@Mappings({@Mapping(source="id",target="userId"),@Mapping(source="name",target="userName")})UserVO4toConvertVO(Usersource);UserfromConvertEntity(UserVO4userVO4);
通過IDE的反編譯功能查看編譯后的實現類,編譯后的結果是這樣子的:
小結:
當字段名不一致時,通過使用 @Mappings 注解指定對應關系,編譯后即可實現對應字段的賦值。
很明顯, mapstruct 通過讀取我們配置的字段名對應關系,幫我們把它們賦值在了相對應的位置上,可以說是相當優秀了,但這也僅僅是優秀,而更秀的還請繼續往下看:
3.3、屬性是枚舉類型
實體類我們還是改用 UserEnum:
@Data@NoArgsConstructor@AllArgsConstructor@BuilderpublicclassUserEnum{privateIntegerid;privateStringname;privateUserTypeEnumuserTypeEnum;}
被映射對象 UserVO5 改為:
@Data@NoArgsConstructor@AllArgsConstructor@BuilderpublicclassUserVO5{privateIntegerid;privateStringname;privateStringtype;}
枚舉對象是:
@Getter@AllArgsConstructorpublicenumUserTypeEnum{Java("000","Java開發工程師"),DB("001","數據庫管理員"),LINUX("002","Linux運維員");privateStringvalue;privateStringtitle;}
那么我們定義的接口還是照常定義,不會受到它是枚舉就有所變化:
@Mapping(source="userTypeEnum",target="type")UserVO5toConvertVO5(UserEnumsource);UserEnumfromConvertEntity5(UserVO5userVO5);
通過IDE的反編譯功能查看編譯后的實現類,編譯后的結果是這樣子的:
很明顯, mapstruct 通過枚舉類型的內容,幫我們把枚舉類型轉換成字符串,并給type賦值,可謂是小心使得萬年船啊。
到此,相信大家對“分析mybatis中@Mapper注解的componentModel屬性”有了更深的了解,不妨來實際操作一番吧!這里是本站網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
本文由 貴州做網站公司 整理發布,部分圖文來源于互聯網,如有侵權,請聯系我們刪除,謝謝!
c語言中正確的字符常量是用一對單引號將一個字符括起表示合法的字符常量。例如‘a’。數值包括整型、浮點型。整型可用十進制,八進制,十六進制。八進制前面要加0,后面...
2022年天津專場考試原定于3月19日舉行,受疫情影響確定延期,但目前延期后的考試時間推遲。 符合報名條件的考生,須在規定時間登錄招考資訊網(www.zha...
:喜歡聽,樂意看。指很受歡迎?!巴卣官Y料”喜聞樂見:[ xǐ wén lè jiàn ]詳細解釋1. 【解釋】:喜歡聽,樂意看。指很受歡迎。2. 【示例】:這是...
中信銀行電子賬戶具體含義。中信銀行電子賬戶是指用戶通過電子渠道實名開立的,可以購買投資理財產品等指定金融產品的賬戶,屬于非面對面開立的二類銀行賬戶或三類銀行賬戶。要在中信銀行,開立電子賬戶,您必須年滿16歲,在身份證的正面和背面提供真實、完整和準確的信息,并核實手機號碼必須與綁定到該賬戶的手機號碼一致。中信銀行電子賬戶可以為用戶提供金融產品和服務,但不會向用戶發送紙質票據,用戶只能通過指定的電子渠...
新版人民幣的簡易識別方法是什么?【1】轉動鈔票(適用新版人民幣100、50、20、10、5元)轉動鈔票觀察,票面正面中部面額數字會變色。50、10由綠變藍,100、20、5由金變綠。100、50、20、10票面正面右側的安全線顏色由紅色變為綠色?!?】觸摸多處有凹凸(適用所有新版人民幣紙幣)用手指觸摸票面正面的毛澤東頭像、“中國人民銀行”行名、右上角面額數字、盲文及背面主景...
(資料圖片僅供參考)最近小編看到大家都在討論如何卸載ie9相關的事情,對此呢小編也是非常的感應興趣,那么這件事究竟是怎么發生的呢?具體又是怎么回事呢?下面就是小編搜索到的關于如何卸載ie9事件的相關信息,我們一起來看一下吧!1、打開一個瀏覽器查看當前使用的ie版本,假設為是為ie9的。2、點擊左下角中的“開始”的菜單,彈出了下拉菜單選中“控制面板”選項。3、點擊“程序”。4、選擇“程序和功能”。5...