Graceful Response是一個Spring Boot技術棧下的優雅響應處理器,提供一站式統一返回值封裝、全局異常處理、自定義異常錯誤碼等功能,使用Graceful Response進行web接口開發不僅可以節省大量的時間,還可以提高代碼質量,使代碼邏輯更清晰。
強烈推薦你花3分鐘學會它!
本項目案例工程代碼:https://github.com/feiniaojin/graceful-response-example.git ,注意選擇最新版本的分支。
Spring Boot版本 | Graceful Response版本 | graceful-response-example分支 |
2.x | 3.2.1-boot2 | 3.2.0-boot2 |
3.x | 3.2.1-boot3 | 3.2.0-boot3 |
注意,3.2.1-boot2版本的GracefulResponse源碼由單獨的倉庫進行維護,地址為:https://github.com/feiniaojin/graceful-response-boot2。
3.2.1-boot2和3.2.1-boot3除了支持的SpringBoot版本不一樣,其他實現完全一致,Maven引用時只需要根據對應的SpringBoot版本選擇Graceful Response的version即可,兩者的groupId、artifactId是一致的。
目前,業界使用Spring Boot進行接口開發時,往往存在效率底下、重復勞動、可讀性差等問題。以下偽代碼相信大家非常熟悉,我們大部分項目的Controller接口都是這樣的。
@Controllerpublic class Controller { @GetMapping("/query") @ResponseBody public Response query(Map<String, Object> paramMap) { Response res = new Response(); try { //1.校驗params參數合法性,包括非空校驗、長度校驗等 if (illegal(paramMap)) { res.setCode(1); res.setMsg("error"); return res; } //2.調用Service的一系列操作,得到查詢結果 Object data = service.query(params); //3.將操作結果設置到res對象中 res.setData(data); res.setCode(0); res.setMsg("ok"); return res; } catch (Exception e) { //4.異常處理:一堆丑陋的try...catch,如果有錯誤碼的,還需要手工填充錯誤碼 res.setCode(1); res.setMsg("error"); return res; } }}
這段偽代碼存在什么樣的問題呢?
第一個問題,效率低下。 Controller層的代碼應該盡量簡潔,上面的偽代碼其實只是為了將數據查詢的結果進行封裝,使其以統一的格式進行返回。例如以下格式的響應體:
{ "code": 0, "msg": "ok", "data": { "id": 1, "name": "username" }}
查詢過程中如果發生異常,需要在Controller進行手工捕獲,根據捕獲的異常人工地設置錯誤碼,當然,也用同樣的格式封裝錯誤碼進行返回。
可以看到,除了調用service層的query方法這一行,其他大部分的代碼都執行進行結果的封裝,大量的冗余、低價值的代碼導致我們的開發活動效率很低。
第二個問題,重復勞動。 以上捕獲異常、封裝執行結果的操作,每個接口都會進行一次,因此造成大量重復勞動。
第三個問題,可讀性低。 上面的核心代碼被淹沒在許多冗余代碼中,很難閱讀,如同大海撈針。
我們可以通過Graceful Response這個組件解決這樣的問題。
Graceful Response已發布至maven中央倉庫,我們可以直接引入到項目中。
maven依賴如下:
<dependency> <groupId>com.feiniaojin</groupId> <artifactId>graceful-response</artifactId> <version>{latest.version}</version></dependency>
Spring Boot版本 | Graceful Response最新版本 |
2.x | 3.2.1-boot2 |
3.x | 3.2.1-boot3 |
(2) 啟用Graceful Response
在啟動類中引入@EnableGracefulResponse注解,即可啟用Graceful Response組件。
@EnableGracefulResponse@SpringBootApplicationpublic class ExampleApplication { public static void main(String[] args) { SpringApplication.run(ExampleApplication.class, args); }}
(3) Controller層
引入Graceful Response后,我們不需要再手工進行查詢結果的封裝,直接返回實際結果即可,Graceful Response會自動完成封裝的操作。
Controller層示例如下:
@Controllerpublic class Controller { @RequestMapping("/get") @ResponseBody public UserInfoView get(Long id) { log.info("id={}", id); return UserInfoView.builder().id(id).name("name" + id).build(); }}
在示例代碼中,Controller層的方法直接返回了UserInfoView對象,沒有進行封裝的操作,但經過Graceful Response處理后,我們還是得到了以下的響應結果。
{ "status": { "code": "0", "msg": "ok" }, "payload": { "id": 1, "name": "name1" }}
而對于命令操作(Command)盡量不返回數據,因此command操作的方法的返回值應該是void,Graceful Response對于對于返回值類型void的方法,也會自動進行封裝。
public class Controller { @RequestMapping("/command") @ResponseBody public void command() { //業務操作 }}
成功調用該接口,將得到:
{ "status": { "code": "200", "msg": "success" }, "payload": {}}
(3) Service層
在引入Graceful Response前,有的開發者在定義Service層的方法時,為了在接口中返回異常碼,干脆直接將Service層方法定義為Response,淹沒了方法的正常返回值。
Response的代碼如下。
//lombok注解@Datapublic class Response { private String code; private String msg; private Object data;}
直接返回Response的Service層方法:
/** * 直接返回Reponse的Service * 不規范 */public interface Service { public Reponse commandMethod(Command command);}
Graceful Response引入@ExceptionMapper注解,通過該注解將異常和錯誤碼關聯起來,這樣Service方法就不需要再維護Response的響應碼了,直接拋出業務異常,由Graceful Response進行異常和響應碼的關聯。搜索我是程序汪公眾號,回復“面試寶典”,送你一份Java面試寶典
@ExceptionMapper的用法如下。
/** * NotFoundException的定義,使用@ExceptionMapper注解修飾 * code:代表接口的異常碼 * msg:代表接口的異常提示 */@ExceptionMapper(code = "1404", msg = "找不到對象")public class NotFoundException extends RuntimeException {}
Service接口定義:
public interface QueryService { UserInfoView queryOne(Query query);}
Service接口實現:
public class QueryServiceImpl implements QueryService { @Resource private UserInfoMapper mapper; public UserInfoView queryOne(Query query) { UserInfo userInfo = mapper.findOne(query.getId()); if (Objects.isNull(userInfo)) { //這里直接拋自定義異常 throw new NotFoundException(); } //……后續業務操作 }}
當Service層的queryOne方法拋出NotFoundException時,Graceful Response會進行異常捕獲,并將NotFoundException對應的異常碼和異常信息封裝到統一的響應對象中,最終接口返回以下JSON。
{ "status": { "code": "1404", "msg": "找不到對象" }, "payload": {}}
Graceful Response對JSR-303數據校驗規范和Hibernate Validator進行了增強,Graceful Response自身不提供參數校驗的功能,但是用戶使用了Hibernate Validator后,Graceful Response可以通過@ValidationStatusCode注解為參數校驗結果提供響應碼,并將其統一封裝返回。
例如以下的UserInfoQuery:
@Datapublic class UserInfoQuery { @NotNull(message = "userName is null !") @Length(min = 6, max = 12) @ValidationStatusCode(code = "520") private String userName;}
在上面的UserInfoQuery中由于使用了@ValidationStatusCode注解,并指定異常碼為520,則當userName字段任意校驗不通過時,都會使用異常碼520進行返回,如下:
{ "status": { "code": "520", "msg": "userName is null !" }, "payload": {}}
而對于Controller層直接校驗方法入參的場景,Graceful Response也進行了增強,如以下Controller:
public class Controller { @RequestMapping("/validateMethodParam") @ResponseBody @ValidationStatusCode(code = "1314") public void validateMethodParam( @NotNull(message = "userId不能為空") Long userId, @NotNull(message = "userName不能為空") Long userName) { //省略業務邏輯 }}
如果該方法入參校驗觸發了userId和userName的校驗異常,將以錯誤碼1314進行返回,如下:
{ "status": { "code": "1314", "msg": "userId不能為空" }, "payload": {}}
Graceful Response內置了兩種風格的響應格式,并通過graceful-response.response-style進行配置。
graceful-response.response-style=0,或者不配置(默認情況),將以以下的格式進行返回:
{ "status": { "code": 1007, "msg": "有內鬼,終止交易" }, "payload": { }}
graceful-response.response-style=1,將以以下的格式進行返回:
{ "code": "1404", "msg": "not found", "data": { }}
如果這兩種格式均不滿足業務需要,Graceful Response也支持用戶自定義響應體,關于自定義響應體的技術實現,請到自定義Response格式進行了解。
本項目提供的進階功能,包括:
目前該組件在GitHub上已經有兩百多Star,很多朋友已經開始用了,大家可以通過下方鏈接了解下:https://github.com/feiniaojin/graceful-response。
本文鏈接:http://www.tebozhan.com/showinfo-26-53350-0.html拒絕寫重復代碼,試試這套開源的 SpringBoot 組件,效率翻倍
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com
上一篇: C++函數模板詳解,輕松實現通用函數
下一篇: 使用互斥鎖(Mutex)管理共享資源