注意:我現在所講的內容針對於rest風格的接口服務(請求值和返回值數據都爲json)
首先聲明一下架構觀點:
規範性的公共類:必須封裝,必須使用
便利性的公共類:謹慎封裝,可用可不用
在講述完此節內容後,會對以上觀點進一步說明,相信有更深的感悟
參數規範化
首先說明下在開發中遇到的一些問題,在查詢分頁參數的時候,可能會看到這樣的兩份代碼
張三寫的代碼:
/**
* 分頁查詢用戶列表
* @param pageIndex 頁碼
* @param pageSize 每頁顯示數量
* @return 分頁後的數據(示例用)
*/
public List<Data> queryPagedUserList(Integer pageIndex,Integer pageSize){
//查詢結果並返回
}
李四寫的代碼:
/**
* 分頁查詢消息列表
* @param currentPage 頁碼
* @param count 每頁顯示數量
* @return 分頁後的數據(示例用)
*/
public List<Data> getMessageList(Integer currentPage,Integer count){
//查詢結果並返回
}
仔細對照一下,發現相同的參數含義,兩個人寫出不完全不同的參數名。
張三: 頁碼 pageIndex 分頁大小pageSize
李四: 頁碼 currentPage 分頁大小count
前端在調用這兩個接口的時候,需要根據不同接口選擇不同的參數名,如果不在這方面規範一下,會對前端造成很多困擾,不同的頁面用不同參數名字,即使他們的含義一樣。
怎麼解決這種由於不同人開發造成的命名不規範的問題呢
現在有很多項目,以書面的方式,開會說明參數的命名規範。當後面有新人加入項目後,可能由於講解不到位,又會出現自己命名的情況(我就遇到過這種情況)
下面講的這種方式,叫強制規範化,也就是說你只能這樣命名。
首先分析下前端提交的參數類型:
(1)接口私有查詢參數:和接口業務相關的參數,比如查詢用戶列表有用戶名,查詢消息列表有消息日期
(2)數據列表參數:這種參數一般是用來批量保存數據的,比如說你想批量新增員工,這個參數就是一個list類型的數據
(3)接口私有查詢參數 + 分頁排序參數:這種參數在後臺管理系統用的非常多,規定數據表格按照什麼字段排序,怎麼進行分頁,以什麼條件進行查詢
以上面參數分析爲參照,我們有了這樣一種類圖
下面解釋我大量應用了泛型,對泛型不明白的小夥伴要補補泛型的知識了
BaseRequest定義
public class BaseRequest implements Serializable{
}
可以看到裏面內容是空的,只是實現了Serializable接口,這個接口本身是個空接口,僅僅表明這個類可以通過序列化在網絡上傳輸,在某些框架上必須要求傳輸的Bean實現Serializable接口。
另外:通過讓所有參數繼承BaseRequest的方式,可以全局添加請求參數
(1)第一種參數類型(只包含接口私有參數)
@Data
public class Request<T extends Serializable> extends BaseRequest{
private T param;
}
注:@Data是Lombok註解,lombok主要用來給bean自動生成set/get方法。lombok的詳盡用法請參照資料。
可以看到,我定義了一個泛型,並繼承了BaseRequest,到這裏你可能不太明白,這個到底怎麼用,下面給出使用示例
public List<Data> getMessageList(@RequestBody Request<String> request){
String param = request.getParam();
//查詢結果並返回
}
前端對應的參數爲
注:@RequestBody作用是將前臺傳過來的json轉爲Bean,前提是框架配置好
這裏可以看到我放了一個String類型的參數進去了,表明這個接口接受的參數類型是String,當前端傳遞了一個帶param字段的json對象過來後,後臺轉換成Bean,賦值到Request的param字段上。
當需要傳遞多個參數的時候怎麼辦呢,這時候我們就需要一個bean了,比如這樣
@Data
public class ClientLoginParam implements Serializable{
private String username;
private String password;
}
然後接口定義這麼寫
public List<Data> getMessageList(@RequestBody RestRequest<ClientLoginParam> request){
ClientLoginParam = request.getParam();
}前端對應的參數
當然,接口私有參數可以定義一個全局的BaseParam參數
public class BaseParam implements Serializable{
}
public class ClientLoginParam extends BaseParam //後面省略
(2)第二種參數類型:數據列表參數
@Data
public class ListRequest<T extends Serializable> extends BaseRequest{
private List<T> params;
}
本質上和是Request用法是一樣的,只不過param類型變成了List<T>,用法上這麼用
public List<Data> getMessageList(@RequestBody ListRequest<ClientLoginParam> request){
List<ClientLoginParam> param = request.getParams();
//查詢結果並返回
}
(3)接口私有查詢參數 + 分頁排序參數(這個是重點)
@Data
public class PageRequest<T extends Serializable> extends BaseRequest{
//分頁參數
private PageParam pageParam;
//排序參數
private List<SortParam> sortParams;
//接口私有查詢參數
private T param;
}
@Data
public class PageParam extends BaseParam {
//當前頁
private int currentPage;
//每頁顯示大小
private int pageSize;
//是否分頁
private boolean paging;
}
@Data
public class SortParam extends BaseParam{
//排序字段
private String fieldName;
//排序類型
private String orderType;
}
然後對應的前端參數示例
後臺對應的讀參數方法示例
public List<Data> getMessageList(@RequestBody PageRequest<ClientLoginParam> request){ //獲取接口自定義查詢參數 ClientLoginParam param = request.getParam(); //獲取分頁參數 PageParam pageParam = request.getPageParam(); //獲取排序參數 List<SortParam> sortParamList = request.sortParams(); //查詢結果並返回 }
這裏可以看到,通過Bean定義的方式,確定了前臺的參數格式和參數名稱(配合swagger可以自動生成接口文檔,後面的java架構篇會講解)
這裏有一個很重要的地方要注意,不能用Map接收參數
並不是這種方法不能實現功能,是因爲這種方式給維護代碼帶來很大的不方便性,必須運行時才能確定有哪些參數傳遞過來了,並不能像Bean定義這種方式,通過瀏覽代碼就知道接口主要接收哪些參數。
針對文章剛開始提到的架構觀點
規範性的公共類:必須封裝,必須使用
如果在寫接口的時候,都使用了,基於以上說明的參數類。那麼前端提交的參數格式會非常統一,可維護性大大提高,再也不會出現相同含義的公共參數名稱不同的問題。提高了代碼的整體質量。這就是規範性的東西一定要封裝和使用的原因。