1.情景展示
請求入參:
這是一個對外提供的請求總入口,入參interfaceMethod對應不同的接口名稱,具體的接口請求參數封裝到xcParams里面。
對外只提供這一個接口,而不是不同接口提供不同地址,這樣一來,無論是接口提供方還是接口調用方只要遵循這種規范,就可以完成不同接口的調用,也利於后期接口的啟用、禁用、擴展新接口,提高系統的可維護性。
像這樣,用實體類接收到請求入參,獲取將要調取的接口方法,根據不同接口名稱匹配調用不同的業務實現類進行業務處理。
2.現狀分析
在實際開發過程中,公司與公司之間或者公司內部項目與項目之間往往會存在這種需求,公司A提供接口,公司B調用接口,如果是多個接口,那么就可以像上面那樣搞一個總入口:
使用switch判斷具體需要調用哪一個接口,以及負責處理的業務實現類就可以了。
以上的代碼是完全沒有問題的,已經滿足了實際業務需要,這種入門級的代碼,基本不要動什么腦子;
但是,如果我們想要使用高逼格的代碼實現這種功能,能夠讓我們用更多java知識應用到實際開發過程中,學以致用,使自己的能力得到升華,換句話說就是:想裝X,請欣賞下面的高逼格代碼。
(其實,對於產品來說,不管你是低級代碼還是高級代碼實現,只要能滿足產品需求就是OK的,這一點我們一定要擺好自己位置,不能沾沾自喜)
3.高級代碼實現
先看效果
請求入參使用了泛型控制,不同接口自動映射到對應的實體類去接收(上圖)
調對應接口時,一行代碼搞定,無需手動加判斷該調哪個業務實現類。
想實現這種效果,就繼續往下看哈。
用實體類接收請求入參是本文的重中之重,先來看一下
第一,注解@Getter、@Setter;
使用的是lombok插件,其作用是生成私有屬性的Get、Set方法,不想用或者沒有的,自己手動生成替代就可以了(類的屬性私有化,再對外提供Get和Set方法,其實就是java三大特性之一:封裝)。
第二,注解@ApiModelProperty;
對請求參數進行介紹,使用的是knife4j,為接口提供的API文檔,最終效果如下圖所示:
這樣一來,接口的請求參數、響應參數都有詳細介紹,與別人對接接口的時候再也不用一遍一遍的跟不同的人解釋了,把文檔地址扔給他,清晰明了。
注意:這不是本文介紹的重點,心有余力的,見文末推薦文章。
第三,注解@JsonProperty;
反序列化:將json對象的key與實體類的指定屬性對照起來,並完成賦值操作;
@JsonProperty,隸屬於Jackson,springboot內部集成,請求入參轉實體類默認使用的就是Jackson;
由於將請求參數與泛型進行映射,所以,每個屬性都需要加上@JsonProperty注解進行對照。
第四,注解@NotBlank
字符串非空校驗:只用在String上,表示傳進來的值不能為null,而且調用trim()后,長度必須大於0,即:必須有實際字符。
說明:泛型無法使用注解進行非空校驗,所以,上圖中的注解@NotNull無效
第五,用枚舉類來接收請求入參的其中一個參數值;
在這里,使用枚舉類CzInterfaceEnum來接收請求參數InterfaceMethod的值,這個說法並不對,因為枚舉類往往不止有一個屬性,而InterfaceMethod卻只有一個值,按正常邏輯來想,json是完全不能實現發序列化的。
這我們就不得不提及注解@JsonValue啦
被加上注解@JsonValue的屬性,將會完成值的映射,也就是InterfaceMethod的值最終會被賦值到枚舉類的interfaceName屬性上,這樣就沒有一點問題了。
第六,往枚舉類注入對象;
如果枚舉類只有這一點點作用,那我們也不用廢這么大勁用它接收,干脆用String類來接收豈不方便?
如果這樣想,就大錯特錯了,再來回想一下,如果我們用String類來接收InterfaceMethod的值,那我們豈不是又回到了原點:后續還得用switch來判斷,進而調用不同的業務實現類。
之所以想用枚舉類來接收InterfaceMethod,是因為,這個時候,我們已經拿到了InterfaceMethod的值,換句話說,我們這個時候就已經知道,它調用的是哪個接口,該用哪個接口實現類來處理!
難點在於:如何往枚舉類注入對象?
見文末推薦。
第七,不同接口的請求參數使用不同實體類接收;
通過注解@JsonTypeInfo和@JsonSubTypes結合實現
由最開始的時候,我們得知:不同的接口雖然請求參數不同,但都會塞到CzParams這個參數中,所以,我們就能根據參數InterfaceMethod來判斷當前請求該用哪個請求實體類來接收;
所以,CzParams的類型只能用泛型來接收(只有在運行調用的時候,才能知道它是誰);
這樣一來,請求實體類只需繼承抽象類CzRequestParams,並在該父類中設置@JsonSubType.Type注解即可。
如此,就能實現剛開始提到的效果;
對於高頻接口,還可以開啟多線程,解決並發問題(本文未做展示)。
4.多態的另一種用法
2020-12-15
關於用泛型接收類的方式,其實也是可以去掉的,只是,可能會讓看代碼的人一臉懵逼。
上面說的很清楚,這個地方用的是泛型,並在class類上用了泛型限定<T extends CzRequestParams>,這樣方便其它人員維護,看到立馬就知道實際接收參數的是CzRequestParams的子類。
既然是子類,那我們何不用的干脆一點?
把泛型干掉,直接用父類接收完事(向上泛型),實際負責接收的還是那些子類。
5.嵌套實體類校驗不生效問題
2020-12-16
使用@Valid或@Validator注解進行相關檢驗時,會造成嵌套類上相關校驗不生效的問題(嵌套驗證),比如:
CzRequestDto類能夠使用注解進行校驗,這沒有一點問題。
問題是:CzRequestDto類里又使用其他實體類接收請求參數,例如:上圖中的泛型,它對應的其中一個實體類是下面這個類,
這就是所謂的嵌套。
在這個類里面,使用參數校驗注解,不會生效。
如何解決這個問題?
這個問題困擾了我很久,其實很簡單,在嵌套實體類的地方,再次聲明校驗注解就完事了。
寫在最后
哪位大佬如若發現文章存在紕漏之處或需要補充更多內容,歡迎留言!!!
相關推薦: