這篇文章主要介紹“spring Boot項(xiàng)目怎么處理全局異?!保谌粘2僮髦?,相信很多人在spring Boot項(xiàng)目怎么處理全局異常問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”spring Boot項(xiàng)目怎么處理全局異?!钡囊苫笥兴鶐椭?!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!
十載的永福網(wǎng)站建設(shè)經(jīng)驗(yàn),針對(duì)設(shè)計(jì)、前端、開(kāi)發(fā)、售后、文案、推廣等六對(duì)一服務(wù),響應(yīng)快,48小時(shí)及時(shí)工作處理。成都全網(wǎng)營(yíng)銷的優(yōu)勢(shì)是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動(dòng)調(diào)整永福建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無(wú)論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計(jì),從而大程度地提升瀏覽體驗(yàn)。創(chuàng)新互聯(lián)建站從事“永福網(wǎng)站設(shè)計(jì)”,“永福網(wǎng)站推廣”以來(lái),每個(gè)客戶項(xiàng)目都認(rèn)真落實(shí)執(zhí)行。
異常的處理在我們的日常開(kāi)發(fā)中是一個(gè)繞不過(guò)去的坎,在Spring Boot 項(xiàng)目中如何優(yōu)雅的去處理異常,正是我們這一節(jié)課需要研究的方向。
在一個(gè)Spring Boot項(xiàng)目中,我們可以把異常分為兩種,第一種是請(qǐng)求到達(dá)Controller
層之前,第二種是到達(dá)Controller層
之后項(xiàng)目代碼中發(fā)生的錯(cuò)誤。而第一種又可以分為兩種錯(cuò)誤類型:1. 路徑錯(cuò)誤 2. 類似于請(qǐng)求方式錯(cuò)誤,參數(shù)類型不對(duì)等類似錯(cuò)誤。
為了保持返回值的統(tǒng)一,我們這里定義了統(tǒng)一返回的類ReturnVO
,以及一個(gè)記錄錯(cuò)誤返回碼和錯(cuò)誤信息的枚舉類ReturnCode
,而具體的錯(cuò)誤信息和錯(cuò)誤代碼保存到了response.properties
中,使用流進(jìn)行讀取。
public class ReturnVO { private static Properties properties = ReadPropertiesUtil.getProperties(System.getProperty("user.dir") + CommonUrl.RESPONSE_PROP_URL); /** * 返回代碼 */ private String code; /** * 返回信息 */ private String message; /** * 返回?cái)?shù)據(jù) */ private Object data; public Object getData() { return data; } public void setData(Object data) { this.data = data; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } /** * 默認(rèn)構(gòu)造,返回操作正確的返回代碼和信息 */ public ReturnVO() { this.setCode(properties.getProperty(ReturnCode.SUCCESS.val())); this.setMessage(properties.getProperty(ReturnCode.SUCCESS.msg())); } /** * 返回代碼,這里需要在枚舉中去定義 * @param code */ public ReturnVO(ReturnCode code) { this.setCode(properties.getProperty(code.val())); this.setMessage(properties.getProperty(code.msg())); } /** * 返回?cái)?shù)據(jù),默認(rèn)返回正確的code和message * @param data */ public ReturnVO(Object data) { this.setCode(properties.getProperty(ReturnCode.SUCCESS.val())); this.setMessage(properties.getProperty(ReturnCode.SUCCESS.msg())); this.setData(data); } /** * 返回錯(cuò)誤的代碼,以及自定義的錯(cuò)誤信息 * @param code * @param message */ public ReturnVO(ReturnCode code, String message) { this.setCode(properties.getProperty(code.val())); this.setMessage(message); } /** * 返回自定義的code,message,以及data * @param code * @param message * @param data */ public ReturnVO(ReturnCode code, String message, Object data) { this.setCode(code.val()); this.setMessage(message); this.setData(data); } @Override public String toString() { return "ReturnVO{" + "code='" + code + '\'' + ", message='" + message + '\'' + ", data=" + data + '}'; } }
其他的錯(cuò)誤處理只需要在枚舉類中添加對(duì)應(yīng)的異常即可,枚舉的名稱要定義為異常的名稱,這樣可以直接不用對(duì)其他的代碼進(jìn)行修改,添加一個(gè)新的異常時(shí),僅僅添加枚舉類中的字段和properties文件中的屬性。
public enum ReturnCode { /** 操作成功 */ SUCCESS("SUCCESS_CODE", "SUCCESS_MSG"), /** 操作失敗 */ FAIL("FAIL_CODE", "FAIL_MSG"), /** 空指針異常 */ NullPointerException("NPE_CODE", "NPE_MSG"), /** 自定義異常之返回值為空 */ NullResponseException("NRE_CODE", "NRE_MSG"), /** 運(yùn)行時(shí)異常 */ RuntimeException("RTE_CODE","RTE_MSG"), /** 請(qǐng)求方式錯(cuò)誤異常 */ HttpRequestMethodNotSupportedException("REQUEST_METHOD_UNSUPPORTED_CODE","REQUEST_METHOD_UNSUPPORTED_MSG"), /** INTERNAL_ERROR */ BindException("BIND_EXCEPTION_CODE","BIND_EXCEPTION_MSG"), /** 頁(yè)面路徑不對(duì) */ UrlError("UE_CODE","UE_MSG"); private ReturnCode(String value, String msg){ this.val = value; this.msg = msg; } public String val() { return val; } public String msg() { return msg; } private String val; private String msg; }
這里我自定義了一些異常用于后面的測(cè)試,在我們實(shí)際的項(xiàng)目中需要定義很多的異常去完善。
SUCCESS_CODE=2000 SUCCESS_MSG=操作成功 FAIL_CODE=5000 FAIL_MSG=操作失敗 NPE_CODE=5001 NPE_MSG=空指針異常 NRE_CODE=5002 NRE_MSG=返回值為空 RTE_CODE=5001 RTE_MSG=運(yùn)行時(shí)異常 UE_CODE=404 UE_MSG=頁(yè)面路徑有誤 REQUEST_METHOD_UNSUPPORTED_CODE=4000 REQUEST_METHOD_UNSUPPORTED_MSG=請(qǐng)求方式異常 BIND_EXCEPTION_CODE=4001 BIND_EXCEPTION_MSG=請(qǐng)求參數(shù)綁定失敗
這里的路徑錯(cuò)誤處理方式是采用了實(shí)現(xiàn)ErrorController
接口,然后實(shí)現(xiàn)了getErrorPath()
方法:
/** * 請(qǐng)求路徑有誤 * @author yangwei * @since 2019-01-02 18:13 */ @RestController public class RequestExceptionHandler implements ErrorController { @Override public String getErrorPath() { return "/error"; } @RequestMapping("/error") public ReturnVO errorPage(){ return new ReturnVO(ReturnCode.UrlError); } }
這里可以進(jìn)行測(cè)試一下:
類似于到達(dá)Controller
之前的請(qǐng)求參數(shù)錯(cuò)誤,請(qǐng)求方式錯(cuò)誤,數(shù)據(jù)格式不對(duì)等等錯(cuò)誤都?xì)w類為一種,這里僅僅展示請(qǐng)求方式錯(cuò)誤的處理方式。
/** * 全局異常處理類 * @author yangwei * * 用于全局返回json,如需返回ModelAndView請(qǐng)使用ControllerAdvice * 繼承了ResponseEntityExceptionHandler,對(duì)于一些類似于請(qǐng)求方式異常的異常進(jìn)行捕獲 */ @RestControllerAdvice public class GlobalExceptionHandler extends ResponseEntityExceptionHandler { private static Properties properties = ReadPropertiesUtil.getProperties(System.getProperty("user.dir") + CommonUrl.RESPONSE_PROP_URL); /** * 重寫handleExceptionInternal,自定義處理過(guò)程 **/ @Override protected ResponseEntity
這里我們可以進(jìn)行測(cè)試:
@RestController @RequestMapping(value = "/user") public class UserController { @Autowired private IUserService userService; @PostMapping(value = "/findAll") public Object findAll() { throw new RuntimeException("ddd"); } @RequestMapping(value = "/findAll1") public ReturnVO findAll1(UserDO userDO) { System.out.println(userDO); return new ReturnVO(userService.findAll1()); } @RequestMapping(value = "/test") public ReturnVO test() { throw new RuntimeException("測(cè)試非自定義運(yùn)行時(shí)異常"); } }
直接在瀏覽器訪問(wèn)findAll,默認(rèn)為get方法,這里按照我們期望會(huì)拋出請(qǐng)求方式異常的錯(cuò)誤:
訪問(wèn)findAll1?id=123ss,這里由于我們接受的UserDO
中id
屬性是Integer
類型,所以這里報(bào)一個(gè)參數(shù)綁定異常:
我們上節(jié)課使用AOP對(duì)于全局異常處理進(jìn)行了一次簡(jiǎn)單的操作,這節(jié)課進(jìn)行了完善,并將其放入到我們的公用模塊,使用時(shí)只需導(dǎo)入jar包,然后在啟動(dòng)類配置掃描包路徑即可
/** * 統(tǒng)一封裝返回值和異常處理 * * @author vi * @since 2018/12/20 6:09 AM */ @Slf4j @Aspect @Order(5) @Component public class ResponseAop { @Autowired private GlobalExceptionHandler exceptionHandler; /** * 切點(diǎn) */ @Pointcut("execution(public * indi.viyoung.viboot.*.controller..*(..))") public void httpResponse() { } /** * 環(huán)切 */ @Around("httpResponse()") public ReturnVO handlerController(ProceedingJoinPoint proceedingJoinPoint) { ReturnVO returnVO = new ReturnVO(); try { Object proceed = proceedingJoinPoint.proceed(); if (proceed instanceof ReturnVO) { returnVO = (ReturnVO) proceed; } else { returnVO.setData(proceed); } } catch (Throwable throwable) { // 這里直接調(diào)用剛剛我們?cè)趆andler中編寫的方法 returnVO = exceptionHandler.handlerException(throwable); } return returnVO; } }
做完這些準(zhǔn)備工作,以后我們?cè)谶M(jìn)行異常處理的時(shí)候只需要進(jìn)行以下幾步操作:
引入公用模塊jar包
在啟動(dòng)類上配置掃描包路徑
如果新增異常的話,在枚舉類中新增后,再去properties中進(jìn)行返回代碼和返回信息的編輯即可(注意:枚舉類的變量名一定要和異常名保持一致)
到此,關(guān)于“spring Boot項(xiàng)目怎么處理全局異?!钡膶W(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!