場景一:一般我們遇到需要新建model宗兼,常規(guī)做法就是創(chuàng)建一個類躏鱼,老老實實的定義好model中的所有屬性氮采,一般來說屬性對應(yīng)的set方法和get方法都是少不了的殷绍,有時候還需要toString甚至equals和hashCode方法。
現(xiàn)在的IDE已經(jīng)很成熟了鹊漠,一般不會手寫set和get方法主到,采用IDE自帶的快捷方式自動生成居多茶行。如下圖所示
該方式相對手寫方法來說,效率已經(jīng)有了很大的提升登钥,但還是有進一步的提升空間(下文會介紹)畔师。而且該種方式維護性較差,當需要修改某個屬性名稱或者屬性類型時牧牢,對應(yīng)的set和get方法以及toString都需要調(diào)整看锉。
場景二:大部分時候,我們都是基于當前流行的微服務(wù)架構(gòu)和SSM(Spring+Spring MVC + Mybatis)框架進行開發(fā)塔鳍,這時候我個人經(jīng)常遇到一個問題就是model的轉(zhuǎn)換問題伯铣。
不同層會有不同的model,比如DAO層的model轮纫,service層的model腔寡,對外API接口的model,還有更上層的controller層的model以及提供給前端的View model掌唾。
為了能夠是接口正常調(diào)用放前,我們不得不處理這些model的轉(zhuǎn)換,沒有一個稱手的工具糯彬,我們只能手寫轉(zhuǎn)換類凭语,通過一個又一個的set和get方法來完成model的轉(zhuǎn)換。
有時候情连,我們在測試接口的時候發(fā)現(xiàn)有些屬性沒有值叽粹,調(diào)試半天才發(fā)現(xiàn),是因為其中一個屬性忘記寫set方法了却舀。我們明知道這些工作并不需要太多的思考虫几,但是卻不得不小心翼翼的對待。
那么挽拔,是否有更加優(yōu)雅的處理方式辆脸,請看下文介紹
Lombok
這是一個插件,能夠很好的解決場景一中的難題
下載安裝
我用的IDE是Intellij idea螃诅,可以在Preferences->Plugins中找到相應(yīng)的插件安裝并重啟即可啡氢。
該插件的實現(xiàn)已經(jīng)放在github上,有興趣可以到https://github.com/mplushnikov/lombok-intellij-plugin查看
lombok使用
添加jar包依賴
在你需要的項目的pom文件中添加如下的依賴
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.18</version> </dependency>
編寫model
package com.jackie.wowjava.best.practice.java.orika.model;
import java.util.Date;
public class AuthorDTO { private String name;
private Date birthday;
}
添加需要的注解
Lombok可以通過注解的方式實現(xiàn)你需要添加的方法术裸,比如你需要添加這些屬性對應(yīng)的set方法倘是,那么只要在model類上添加注解@Setter
即可,相應(yīng)的袭艺,如果需要get方法添加@Getter
搀崭。
此外還有@ToString
,@NoArgsConstructor
猾编,@AllArgsConstructor
等方便使用的注解瘤睹。
事實上升敲,我們真的只需要這樣添加注解的方式,就能夠?qū)崿F(xiàn)輕松調(diào)用set和get方法的需要轰传。這樣驴党,以后如果model的屬性有改變,我們只需要直接改相應(yīng)的屬性即可获茬,不再需要做任何一點多余的操作港庄。
將注解還原為具體方法
Lombok為我們提供可以將對應(yīng)注解還原為對應(yīng)方法的功能。
點擊Refactor->Delombok選擇想還原的方法即可
是不是很好用恕曲?
Orika
Orika是一個簡單快速的model拷貝框架攘轩。
Orika使用
添加jar包依賴
在需要使用的項目的pom文件中添加如下依賴
<dependency> <groupId>ma.glasnost.orika</groupId> <artifactId>orika-core</artifactId> <version>1.5.2</version> </dependency>
創(chuàng)建兩個需要轉(zhuǎn)換的model
BookEntity
package com.jackie.wowjava.best.practice.java.orika.model;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.util.Date;
@Setter @Getter @AllArgsConstructor @NoArgsConstructor public class BookEntity { private String bookName;
private String authorName;
private Date authorBirthday;
private String bookInformation;
private Integer type;
}
BookDTO
package com.jackie.wowjava.best.practice.java.orika.model;
import lombok.Getter;
import lombok.Setter;
@Setter @Getter public class BookDTO { private String bookName;
private AuthorDTO author;
private BookType bookType;
private BookInfo bookInfo;
}
備注:這里的AuthorDTO、BookType和BookInfo如下
package com.jackie.wowjava.best.practice.java.orika.model;
import lombok.*;
import java.util.Date;
@Setter @Getter @ToString @NoArgsConstructor @AllArgsConstructor public class AuthorDTO { private String name;
private Date birthday;
}
package com.jackie.wowjava.best.practice.java.orika.model;
public enum BookType {
NOVEL(1),
ESSAY(2);
private int value;
BookType(int value) {
this.value = value;
} public static BookType getBookType(int value) {
BookType bookType = null;
switch (value) {
case 1:
bookType = NOVEL;
break;
case 2:
bookType = ESSAY;
break;
default:
break;
}
return bookType;
} public int getValue() {
return value;
} }
package com.jackie.wowjava.best.practice.java.orika.model;
import lombok.Getter;
import lombok.Setter;
@Setter @Getter public class BookInfo { private String ISBN;
private int page;
}
你沒看錯码俩,就是BookDTO和BookEntity這兩個model度帮,需要相互轉(zhuǎn)換,Orika可以幫你搞定稿存,具體看下面是如何實現(xiàn)的笨篷。
model轉(zhuǎn)換
我們看到兩個model中包含了多種情況
屬性名稱完全一樣的,比如bookName
一個屬性對應(yīng)一個對象的瓣履,BookDTO中的AuthorDTO對應(yīng)BookEntity中的authorName以及authorBirthday
枚舉類型的率翅,比如BookEntity的type和BookDTO的BookType
JSON類型的,比如BookEntity的bookInformation和BookDTO的bookInfo
1袖迎、屬性名稱完全一樣的屬性拷貝
新建測試類OrikaTest
package com.jackie.wowjava.best.practice.java.orika;
import com.alibaba.fastjson.JSON;
import com.jackie.wowjava.best.practice.java.orika.model.BookDTO;
import com.jackie.wowjava.best.practice.java.orika.model.BookEntity;
import com.jackie.wowjava.best.practice.java.orika.model.BookInfo;
import com.jackie.wowjava.best.practice.java.orika.model.BookType;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.MappingContext;
import ma.glasnost.orika.converter.BidirectionalConverter;
import ma.glasnost.orika.impl.DefaultMapperFactory;
import ma.glasnost.orika.metadata.Type;
import java.time.LocalDate;
import java.time.Month;
import java.time.ZoneId;
import java.util.Date;
public class OrikaTest { private static final MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
public static void main(String[] args) { BookEntity bookEntity = new BookEntity(
"銀河系漫游指南",
"道格拉斯·亞當斯",
Date.from(LocalDate.of(1952, Month.MARCH, 11).atStartOfDay(ZoneId.systemDefault()).toInstant()),
"{\"ISBN\": \"9787532754687\", \n \"page\": 279\n }",
1);
BookDTO bookDTO = mapperFactory.getMapperFacade().map(bookEntity, BookDTO.class);
System.out.println(JSON.toJSONString(bookDTO));
} }
運行結(jié)果如下
{"bookName":"銀河系漫游指南"}
沒錯冕臭,只有名稱相同的屬性被轉(zhuǎn)換了。
從代碼來看燕锥,我們不需要做任何特殊化處理就能做到這一點辜贵,因為Orika默認就是按照名稱相同就拷貝進行處理的。
2归形、一個屬性對應(yīng)一個對象的屬性拷貝
這里我們是想BookDTO中的AuthorDTO對應(yīng)BookEntity中的authorName以及authorBirthday托慨。
我們只需要添加如下代碼即可實現(xiàn)。
mapperFactory.classMap(BookDTO.class, BookEntity.class)
.field("author.name", "authorName")
.field("author.birthday", "authorBirthday")
.byDefault()
.register();
運行結(jié)果如下
{"author":{"birthday":-562060800000,"name":"道格拉斯·亞當斯"},"bookName":"銀河系漫游指南"}
3暇榴、枚舉類型的屬性拷貝
這時候我們需要新建一個轉(zhuǎn)換器并注冊到mapperFactory上厚棵。
注冊轉(zhuǎn)換器代碼如下
mapperFactory.getConverterFactory().registerConverter("bookTypeConvert", new BidirectionalConverter<BookType, Integer>() {
@Override
public Integer convertTo(BookType bookType, Type<Integer> type, MappingContext mappingContext) {
return bookType.getValue();
} @Override
public BookType convertFrom(Integer value, Type<BookType> type, MappingContext mappingContext) {
return BookType.getBookType(value);
} });
注冊轉(zhuǎn)換器代碼如下
mapperFactory.classMap(BookDTO.class, BookEntity.class)
.field("author.name", "authorName")
.field("author.birthday", "authorBirthday")
.fieldMap("bookType", "type").converter("bookTypeConvert").add()
.byDefault()
.register();
運行結(jié)果如下:
{"author":{"birthday":-562060800000,"name":"道格拉斯·亞當斯"},"bookName":"銀河系漫游指南","bookType":"NOVEL"}
4、JSON類型的屬性轉(zhuǎn)換
該屬性的轉(zhuǎn)換原理和上述的枚舉類型轉(zhuǎn)換相同蔼紧,需要創(chuàng)建轉(zhuǎn)換器并注冊使用
mapperFactory.getConverterFactory().registerConverter("bookInfoConvert", new BidirectionalConverter<BookInfo, String>() {
@Override
public String convertTo(BookInfo bookInfo, Type<String> type, MappingContext mappingContext) {
return JSON.toJSONString(bookInfo);
} @Override
public BookInfo convertFrom(String s, Type<BookInfo> type, MappingContext mappingContext) {
return JSON.parseObject(s, BookInfo.class);
} });
mapperFactory.classMap(BookDTO.class, BookEntity.class)
.field("author.name", "authorName")
.field("author.birthday", "authorBirthday")
.fieldMap("bookType", "type").converter("bookTypeConvert").add()
.fieldMap("bookInfo", "bookInformation").converter("bookInfoConvert").add()
.byDefault()
.register();
運行結(jié)果如下
{"author":{"birthday":-562060800000,"name":"道格拉斯·亞當斯"},"bookInfo":{"iSBN":"9787532754687","page":279},"bookName":"銀河系漫游指南","bookType":"NOVEL"}
是不是很神奇婆硬?
?
總結(jié)
相信有了這兩大神奇Lombok和Orika,基本上實現(xiàn)了和set和get的真正告別奸例。