在各種中臺、微服務、分佈式等互聯網概念盛行的今天,部門承接的項目也逐漸開始採用的微服務框架,前後端分離方式。現在的軟件開發,隨着前後端任務的細分,相應的工作職責也就越來越清晰。現在項目開發的前端的技術棧和相應的生態圈都已經相當成熟,前端開發人員隨之走俏,地位也越來越高。
新開發系統中融合各種微應用的方式來構建生態系統,所以使用SpringBoot2對原有的產品按照微服務的模式進行拆分重構,本文主要介紹在重構過程中微服務Restful API風格,返回接口設計統一返回形式。
系統的整體架構示意圖如下:
※此圖是概要示意圖,省略了網關、消息中間件等,重點用來輔助理解API設計。
接口交互
根據目前發展趨勢來看,隨着前端設備種類的增多,前端和後端進行交互就越來越靈活多樣。因此,最好有一種統一的方式來進行前端設備與後端進行通信。RESTful架構是對MVC架構改進後所形成的一種架構,通過使用事先定義好的接口與不同的服務聯繫起來。在RESTful架構中,客戶端使用POST,DELETE,PUT和GET四種請求方式分別對指定的URI資源進行增刪改查操作。這種對資源的管理訪問方式具有強擴展性、結構清晰等特點,是目前比較成熟的一套互聯網應用程序的API設計架構。本文重點介紹後端服務器接收請求後,如何實現封裝業務數據返回前端。
返回格式
現在開發項目中,前端和後端並不是固定的搭配來同時進行同一個項目,在頻繁交替過程中,不能保證大家保持接口和調用形式的默契行,如果前端和後端,在沒有統一返回數據格式,就會給接口調試帶來較大的麻煩。不同的人員基於自身對RestFul的瞭解,按照自己的喜好來封裝接口返回的數據格式:
-
張三:習慣返回一個編碼(code=0)並返回數據;
-
李四:喜歡直接返回一個布爾類型變量(success=true),然後返回數據;
-
王五:習慣在調用失敗時,返回一個狀態(status=0)並返回數據。
如上三個人的做法基本都沒有大問題,並沒有絕對的誰對誰錯,只要給前端人員正確的接口文檔,前端都可以調用接口。但是,如果沒有同意規則,在同一個項目中任由他們自由生長,隨着功能越來越多,就會帶來很大的麻煩。返回規則不一致,導致同一個前端,需要分別針對不同的接口做各種規則的適配。溝通後臺,每個人都有很多開發完成的接口,修改量巨大,牽一髮而動全身。所以,在項目開發初期,搭建基礎框架時,就要定好標準的接口數據返回格式,定義好全局的狀態碼。在同一個項目,必須遵循同一套接口返回格式,以便降低開發溝通成本。
後端返回給前端返回一般用JSON體方式,定義如下:
/**
* 定義返回的基本數據格式
*
* {status=0, code=1001, msg='查詢成功', data=數據}
* {status=0, code=1002, msg='查詢成功無記錄', data=[]}
* {status=0, code=1003, msg='自定義業務msg', data=這是自定義的數據}
* {status=1, code=5001, msg='參數爲空或格式錯誤', data=[]}
* {status=1, code=5002, msg='查詢失敗', data=[]}
*/
public class BaseResult<T> {
// 處理結果: 0 : 成功 1 : 失敗 。和錯誤編碼區分
// 參數格式錯誤 賦值爲1 發生異常,查詢出錯 賦值爲1 查詢成功 沒有錯誤 都設定爲0
private Integer status;
// 服務器返回的業務編碼
private Integer code;
// 服務器返回的提示信息(包括成功提示消息和錯誤消息)
private String msg;
// 服務器的返回數據(即使出錯,也要返回空對象,不能直接返回null)
private T data;
}
※code返回業務編碼,開發同學們根據實際的業務功能自行封裝,隨着項目的進行逐步添加。例如:接口要返回用戶密碼異常,初始業務編碼可以設定爲1001。接下來有一個參數檢查異常,就加一個1002的狀態碼。這樣前端人員在得到返回值後,根據業務編碼就可以概要知道錯誤是什麼,再根據msg描述能夠快速定位問題,提高開發效率。
當然爲了規範化,我們可以參考HTTP請求返回的狀態碼來定義我們的業務消息:
#1000~1099 表示參數錯誤類信息 #1100~1199 表示XX業務類錯誤 #1200~1299 表示YY業務類異常 …… #9000~9099 表示DB訪問類信息
控制層Controller
通常會在controller層處理業務請求,並將請求結果返回給前端。下面是一個檢索微信公衆號列表信息的返回結果。
@RestController
@RequestMapping("/api/wechat")
public class WechatController {
@Autowired
WechatDataService wechatDataService;
@GetMapping("/docs")
public BaseResult<List<WechatDoc>> getWechatDocs() throws NewsException {
return BaseResponse.makeOKRsp(wechatDataService.searchDocs(docType));
}
}
返回結果
{
"status": 0,
"code": 1001,
"msg": "信息查詢成功",
"data": [
{
"hotsportName": "北京師範大學珠海分校教師XXX",
"urlTime": "2019-11-05 00:54:38",
"siteName": "微信",
"evaluate": "正面"
},
{
"hotsportName": "477名騎士用車輪丈量美麗金灣!多圖回顧“速度與激情”",
"urlTime": "2019-11-03 20:27:43",
"siteName": "微信",
"evaluate": "正面"
},
{
"hotsportName": "科技賦能粵港澳大灣區文創產業發展",
"urlTime": "2019-11-07 09:45:22",
"siteName": "微信",
"evaluate": "正面"
}
]
}
後續優化
Controller中使用封裝的Result類,通過靜態方法的調用使得代碼比較簡化。後續我們可以繼續考慮代碼的優化,在控制層直接返回業務對象,通過攔截器的方式進行統一的返回值的封裝處理。