javascript
SpringBoot实战 之 异常处理篇
在互聯(lián)網(wǎng)時(shí)代,我們所開發(fā)的應(yīng)用大多是直面用戶的,程序中的任何一點(diǎn)小疏忽都可能導(dǎo)致用戶的流失,而程序出現(xiàn)異常往往又是不可避免的,那該如何減少程序異常對(duì)用戶體驗(yàn)的影響呢?其實(shí)方法很簡(jiǎn)單,對(duì)異常進(jìn)行捕獲,然后給予相應(yīng)的處理即可。但實(shí)現(xiàn)的方式卻有好多種,例如:
try {... } catch (Exception e) {doSomeThing(); }像這種標(biāo)準(zhǔn)的 try-catch 是可以解決問題,但如果讓你在每個(gè)接口實(shí)現(xiàn)里面都 try-catch 一下,我想你應(yīng)該是不太愿意的。那么下面來介紹下 SpringBoot 為我們提供的處理方式。
1. ErrorController 應(yīng)用
首先,我們來模擬一下,出現(xiàn)異常的場(chǎng)景,方式比較簡(jiǎn)單,直接在正常的代碼里面拋出一個(gè)異常即可。
在上面的示例中,調(diào)用接口時(shí),出現(xiàn)了異常,但客戶端卻收到一個(gè)相對(duì)正常的響應(yīng),這是因?yàn)?SpringBoot 默認(rèn)提供了一個(gè) /error 的映射,該映射被注冊(cè)為 Servlet 容器中的一個(gè)全局錯(cuò)誤頁面用來合理處理所有的異常情況。但示例中的響應(yīng)報(bào)文不符合我們定義的數(shù)據(jù)規(guī)范,想要使其滿足自己的數(shù)據(jù)規(guī)范,可以自己定義一個(gè)新的 ErrorController,代碼如下:
@Controller @RequestMapping("${server.error.path:${error.path:/error}}") public class FundaErrorController implements ErrorController {@Overridepublic String getErrorPath() {return "/error";}@RequestMapping@ResponseBodypublic Result doHandleError() {return new Result(ResultCode.WEAK_NET_WORK);} }當(dāng)我們?cè)俅卧L問該接口的時(shí)候會(huì)返回:
{"code": -1,"msg": "網(wǎng)絡(luò)異常,請(qǐng)稍后重試","data": null }2. ExceptionHandler 應(yīng)用
熟悉 SpringMVC 的人應(yīng)該都知道 @ExceptionHandler 這個(gè)注解,在 SpringBoot 里面,我們同樣可以使用它來做異常捕獲。
2.1. 單一 Controller 異常處理
這種方式使用場(chǎng)景較少,但作為學(xué)習(xí) @ExceptionHandler 入門示例還是非常不錯(cuò)的,直接在對(duì)應(yīng)的 Controller 里面增加一個(gè)異常處理的方法,并使用 @ExceptionHandler 標(biāo)識(shí)它即可。
@ExceptionHandler(Exception.class) public Result handleException() {return new Result(ResultCode.WEAK_NET_WORK); }客戶端得到的效果與使用 ErrorController 完全一致,但對(duì)于服務(wù)端來說卻不太一樣,如果仔細(xì)觀察這兩種方式的日志輸出的話,會(huì)發(fā)現(xiàn)使用 ErrorController 時(shí),后臺(tái)會(huì)打印出異常堆棧信息,而使用 @ExceptionHandler 卻不會(huì),這是因?yàn)檫@兩種處理方式的流程存在著本質(zhì)的差別。
ErrorController:?調(diào)用 UserController 拋出異常時(shí),自身沒有做任何處理,所以會(huì)打印出堆棧信息,但這個(gè)異常會(huì)被 Servlet 容器捕捉到,Servlet 容器再將請(qǐng)求轉(zhuǎn)發(fā)給注冊(cè)好的異常處理映射 /error 做處理,客戶端收到的實(shí)際是 ErrorController 的處理結(jié)果,而不是 UserController 的。
ExceptionHandler:?異常的處理方法直接被定義在 UserController 里面,也就是說,在異常拋出的時(shí)候,UserController 會(huì)使用自己的方法去做異常處理,而不會(huì)拋出給 Servlet 容器,所以這個(gè)地方?jīng)]有打印堆棧信息。
如果想要在后臺(tái)添加堆棧信息的輸出也非常簡(jiǎn)單,只需要將該異常作為一個(gè)參數(shù)傳遞給異常處理方法,然后在處理方法里面做相應(yīng)的操作即可。
@ExceptionHandler(Exception.class) public Result handleException(Exception e) {e.printStackTrace();return new Result(ResultCode.WEAK_NET_WORK); }2.2. 父級(jí) Controller 異常處理
項(xiàng)目的往往存在著多個(gè) Controller,而它們?cè)诋惓L幚矸矫嬗写嬖谥芏嗟墓残?#xff0c;這樣就不太適合在每一個(gè) Controller 里面都編寫一個(gè)對(duì)應(yīng)的異常處理方法。可以將異常處理方法向上挪移到父類中,然后所有的 Controller 統(tǒng)一繼承父類即可。
定義父類 BaseController:
public class BaseController {@ExceptionHandler(Exception.class)public Result handleException(Exception e) {e.printStackTrace();return new Result(ResultCode.WEAK_NET_WORK);}}?
UserController 通過繼承 BaseController 完成異常處理:
@RestController @RequestMapping("/sys/user") public class UserController extends BaseController {... }2.3. Advice 異常處理
對(duì)于使用父級(jí) Controller 完成異常處理也有著它自己的缺點(diǎn),那就是代碼耦合嚴(yán)重,一旦哪天忘記繼承 BaseController,異常又會(huì)直達(dá)客戶了。想要解除這種耦合關(guān)系,可以使用 @ControllerAdvice 來協(xié)助處理。
@ControllerAdvice @ResponseBody public class ExceptionHandlerAdvice {@ExceptionHandler(Exception.class)public Result handleException(Exception e) {e.printStackTrace();return new Result(ResultCode.WEAK_NET_WORK);}}3. 多類別異常處理
實(shí)際的開發(fā)場(chǎng)景中,異常是區(qū)分很多類別的,不同類別的異常需要給用戶不同的反饋。例如,在?SpringBoot實(shí)戰(zhàn) 之 數(shù)據(jù)交互篇?中有使用到注解式參數(shù)校驗(yàn),但校驗(yàn)不通過原因并沒有以有效的方式告之給前端應(yīng)用。下面我們通過上面提到的異常處理方式來完成這個(gè)功能:
首先,在 ResultCode 類中定義好 參數(shù)錯(cuò)誤 的 code,代碼如下:
PARAMETER_ERROR(10101, "參數(shù)錯(cuò)誤")在 ExceptionHandlerAdvice 中添加對(duì)應(yīng)的異常處理方法:
@ExceptionHandler(MethodArgumentNotValidException.class) public Result handleIllegalParamException(MethodArgumentNotValidException e) {List<ObjectError> errors = e.getBindingResult().getAllErrors();String tips = "參數(shù)不合法";if (errors.size() > 0) {tips = errors.get(0).getDefaultMessage();}Result result = new Result(ResultCode.PARAMETER_ERROR);result.setMsg(tips);return result; }
當(dāng)應(yīng)用程序拋出 MethodArgumentNotValidException 時(shí),會(huì)精確匹配到該方法,在方法里面會(huì)獲取到校驗(yàn)結(jié)果,并將所有校驗(yàn)錯(cuò)誤中的第一條返回給前端應(yīng)用。
這樣的話,就可以在 ExceptionHandlerAdvice 里面添加各種各樣的異常處理方法,以適合不同的應(yīng)用場(chǎng)景。
項(xiàng)目的 github 地址:https://github.com/qchery/funda
?
原文鏈接:http://blog.csdn.net/chinrui/article/details/71036544
轉(zhuǎn)載于:https://www.cnblogs.com/Terry-Wu/p/8343289.html
總結(jié)
以上是生活随笔為你收集整理的SpringBoot实战 之 异常处理篇的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【大话存储】多CPU架构变迁, SMP,
- 下一篇: JavaScript Object.de