先來看一段十分基礎的業務代碼前端
Map<String, Object> map = service.getDataByName("悟空GoKu");
Long userId = (Long)map.get("userId");
String phone = (String)map.get("phone");
複製代碼
每次我寫這種map獲取返回數據老是感受十分別扭web
放了什麼key
。
強轉
一下,有點麻煩。
類型轉換異常發生
。
首先要確定的是用map來傳輸參數(前端http請求後端接口)真的是方便
,不須要額外去定義一個類,想往裏面塞什麼數據就塞什麼,就以下面的例子,不須要爲每一個接口都定義一個RequestVo類,統一map接收數據庫
@PostMapping(value = "/map")
public ApiResponse testMap(@RequestBody Map<String, Object> map) {
//獲取map中的數據
Long userId = (Long)map.get("userId");
String phone = (String)map.get("phone");
//業務代碼...
return ApiResponse.ok();
}
複製代碼
上面說了我不喜歡這樣獲取數據,但也不喜歡定義一個類來接收,由於這樣會形成類數量激增
,可能一個請求接口就得對應建立一個請求類。編程
有人說不定義成類,有些額外的功能就沒法使用:json
不想用swagger,代碼侵入性太強,樣式、目錄展現也通常,接口文檔推薦開源yapi後端
swagger有時確實方便,增長參數時,代碼跟文檔同時更新,沒必要額外維護文檔,但我仍是不喜歡將文檔跟代碼耦合在一塊兒。api
驗證邏輯我仍是喜歡寫在controller,邏輯更清晰。緩存
原來的註解不必定適合某些複雜驗證,那豈不是要自定義註解,又回到了類激增的問題app
說回了map,map.get(key)這樣獲取數據確實彆扭,但咱們能夠封裝請求
啊, 例如上一篇文章<<當技術leader說要把接口設計成RESTful,我拒絕了>>提到的ApiRequest。編輯器
public class ApiRequest implements Serializable {
//....省略部分代碼
private Map<String, Object> data; //經過攔截器處理後請求參數已存放在這裏
public Long getDataParamAsLong(String name, Long defaultValue) {
Long i = defaultValue;
try{
i = StringUtils.isNotEmpty(getDataParamAsString(name)) ?
Long.valueOf(getDataParamAsString(name)) : defaultValue;
}catch (Exception e){
e.printStackTrace();
}
return i;
}
}
複製代碼
@PostMapping(value = "/test")
public ApiResponse test(ApiRequest apiRequest) {
Long userId = apiRequest.getDataParamAsLong("userId", 0L);
//省略部分代碼....
ApiResponse response = ApiResponse.ok()
return response;
}
複製代碼
這裏已是
面向json編程
了,而不是以往的面向對象。
對於返回數據,我通常會在controller層拿到service的數據後再根據業務需求來處理數據(結構修改,數據整合),最終用map整合再response,給前端一個合適的結構, 而不是數據庫查到什麼就整個類對象返回
。
當前有些返回數據我也會定義一個類ReponseVo封裝,最後return給前端
你這先後矛盾啊,以前還說不要面向對象。
這裏主要考慮的有些場景下,多個接口返回的數據徹底同樣,能夠共用。 對於部分app開發者來講,他們會依賴後臺的接口來定義本身的model,類似的數據會要求後臺返回的字段命名和結構同樣,以便他們能共用model。
這.......其實他們能夠本身定義屬於他們的model,而不是
徹底依賴
後臺字段命名。
前面說的是前端/移動端http請求咱們的網關接口,這裏是說咱們服務端之間
的遠程方法調用/本地方法調用,也能夠理解成service層方法調用。若是是多個參數的話,須要封裝一個DTO,這裏最好不用map。
數據反序列化問題(劃重點)
。
若是某個方法內部使用了緩存,且經過json反序列化後才返回,容易引起調用方發生異常
//set
@PostMapping(value = "/setData")
public ApiResponse setData(ApiRequest request) {
//省略部分代碼...
Map<String, Object> map = new HashMap<>();
map.put("id", 123L);
map.put("name", "悟空GoKu");
stringRedisTemplate.set("KEY_GOKU", JsonUtil.toJsonString(map));
return ApiResponse.ok();
}
//get
@PostMapping(value = "/getData")
public ApiResponse getData(ApiRequest request) {
Map<String, Object> map = stringRedisTemplate.get("KEY_GOKU", Map.class);
Long id = (Long)map.get("id"); //會發生異常ClassCastException
return ApiResponse.ok();
}
複製代碼
json 反序列化 map 時若是原來的整數值小於 int 最大值,
反序列化後本來爲 Long 類型的字段,會變爲 Integer 類型
。
json 序列化的優點在於可讀性更強。但
沒有攜帶類型信息
,只有提供了準確的類型信息才能準確地進行反序列化,這點也特別容易引起線上問題。
最後來幾句總結闡述下本文的觀點,僅表明我的見解
特別想diss那些字段不寫註釋、代碼加了字段又不一樣步到文檔的後端開發者hhh