javascript
Spring中Controller层、Filter层、Interceptor层全局统一异常处理
Controller層、Filter層、Interceptor層全局統(tǒng)一異常處理
SpringBoot為異常處理提供了很多優(yōu)秀的方法,但是像我這種新手在處理異常時(shí)還是會(huì)覺(jué)得一頭包,終于我痛定思痛,總結(jié)了一下統(tǒng)一異常處理的辦法,讓異常處理變得上流。
本片文章較長(zhǎng),我先定義以下后面會(huì)用到的類
/*** @author ht113* * 錯(cuò)誤dto,就是從后端返回到前端的錯(cuò)誤信息,下面這個(gè)作為例子比較簡(jiǎn)單*/ @Data public class ErrorInfo {String datetime;String msg;String url;HttpStatus httpStatus;public ErrorInfo(String datetime, String message, String url, HttpStatus httpStatus) {this.datetime = datetime;this.msg = message;this.url = url;this.httpStatus = httpStatus;} }自定義抽象異常類
/*** @author ht113*** 基本抽象類,所以我自定義的異常類都繼承自此方法*/ public abstract class AbstractBaseException extends Exception{private ErrorInfo errorInfo;public AbstractBaseException(String msg){super(msg);}public AbstractBaseException(String msg, Throwable cause){super(msg, cause);}public void setErrorInfo(ErrorInfo errorInfo){this.errorInfo = errorInfo;}//這是唯一的抽象方法,也是子類必須實(shí)現(xiàn)的方法,以此達(dá)到使自定義異常對(duì)應(yīng)到不同的http狀態(tài)@NonNullpublic abstract HttpStatus getHttpStatus();}以下兩個(gè)是自定義的異常類,對(duì)應(yīng)的http狀態(tài)分別為NOT_FOUND和INTERNAL_SERVER_ERROR,即404和500
public class MyExceptionA extends AbstractBaseException {public MyExceptionA(String msg) {super(msg);}public MyExceptionA(String msg, Throwable cause){super(msg, cause);}@Overridepublic HttpStatus getHttpStatus() {return HttpStatus.NOT_FOUND;} }public class MyExceptionB extends AbstractBaseException {public MyExceptionB(String msg) {super(msg);}public MyExceptionB(String msg, Throwable cause){super(msg, cause);}@Overridepublic HttpStatus getHttpStatus() {return HttpStatus.INTERNAL_SERVER_ERROR;} }1.一般Controller層的統(tǒng)一異常處理
@ExceptionHandler
在Spring中,我們可以通過(guò)對(duì)Controller中的方法添加@ExceptionHandler注釋來(lái)實(shí)現(xiàn)對(duì)同一個(gè)Controller中路由方法拋出的異常進(jìn)行處理,來(lái)達(dá)到我們想要的異常處理效果
/*** @author ht113*/ @RestController public class HelloController {@RequestMapping("/")public String hello() throws AbstractBaseException{throw new MyExceptionA("exception A test");}//需要捕獲的異常的類@ExceptionHandler(MyExceptionA.class)public String exceptionHandlerA(){return "exception A caught successfully";}}處理效果:
是個(gè)好方法,但是有個(gè)致命缺點(diǎn),就是處理方法不能在Controller間共享,如果我在另一個(gè)Controller中拋出自定義異常就要重新實(shí)現(xiàn)一次,太拉垮了。
/*** @author ht113*/ @RestController public class HelloController2 {@RequestMapping("/hello2")public String hello2() throws AbstractBaseException {throw new MyExceptionA("exception A test");}}@ControllerAdvice
通過(guò)對(duì)Controller添加注釋@ControllerAdvice可以實(shí)現(xiàn)Controller層的全局異常處理,處理方法和@ExceptionHandler相同,但是可以在Controller中共享,實(shí)例如下:
/*** @author ht113*/ @ControllerAdvice public class MyHandler {@ExceptionHandler(AbstractBaseException.class)public ResponseEntity<ErrorInfo> handler(HttpServletRequest request, AbstractBaseException e){return ResponseEntity.status(e.getHttpStatus()).body(new ErrorInfo(new Date().toString(), e.getMessage(),request.getRequestURL().toString(), e.getHttpStatus()));}}測(cè)試類
/*** @author ht113*/ @RestController public class HelloController {@RequestMapping("/1/testA")public void hello() throws AbstractBaseException{throw new MyExceptionA("exception A test from Controller1");}@RequestMapping("/1/testB")public void hello1() throws AbstractBaseException{throw new MyExceptionB("exception B test from Controller1");}}/*** @author ht113*/ @RestController public class HelloController2 {@RequestMapping("/2/testA")public void hello() throws AbstractBaseException {throw new MyExceptionA("exception A test from Controller2");}@RequestMapping("/2/testB")public void hello1() throws AbstractBaseException{throw new MyExceptionB("exception B test from Controller2");}}測(cè)試結(jié)果
我們所有的自定義異常,只要繼承自AbstractBaseException都可以被hander()方法捕獲,進(jìn)行統(tǒng)一異常處理,當(dāng)然也可以根據(jù)異常的不同進(jìn)行特定的處理,只需要在MyHandler類中添加新的處理方法即可
2.Filter層、Interceptor層異常統(tǒng)一處理
過(guò)濾器Filter和過(guò)濾器Interceptor攔截器的使用總是后端開(kāi)發(fā)不可避免的一部分,有時(shí)候我們需要在過(guò)濾器或攔截器中進(jìn)行邏輯處理,拋出異常,那么這里拋出的異常可以被@ControllerAdvice注釋的異常處理類捕獲嗎?答案是Filter不會(huì),而Interceptor可以,Filter是基于Servlet框架編寫(xiě)的,Interceptor是基于SpringMVC框架的,SpingMVC不會(huì)對(duì)Filter中的異常統(tǒng)一處理,所以這里被拋出的異常不能被捕獲,那我們?nèi)绾巫尣荒鼙徊东@的異常被被捕獲呢?
答案有兩個(gè):
本例選擇方法2,便于實(shí)現(xiàn)真正的統(tǒng)一。
Filter、Interception、Controller處理流程:
用上面提到的testA進(jìn)行測(cè)試,結(jié)果如下(如果Controller中拋出異常,那么postHandler不會(huì)調(diào)用):
HandlerExceptionResolver類圖:
如何使用HandlerExceptionResolver?
Filter中捕獲異常
/*** @author ht113*/ @Component public class MyFilter extends OncePerRequestFilter {@Autowired@Qualifier("handlerExceptionResolver")private HandlerExceptionResolver handlerExceptionResolver;@Overrideprotected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {System.out.println("==============i'm in filter===================");handlerExceptionResolver.resolveException(httpServletRequest, httpServletResponse,null,new MyExceptionA("exception A test in filter"));return;//捕獲異常后就直接推出了//filterChain.doFilter(httpServletRequest, httpServletResponse);//System.out.println("===============i'm out filter===================");} }用的是MyExceptionA,結(jié)果如下
Interceptor中捕獲異常
/*** @author ht113*/ public class MyInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("=============i'm in interceptor============");throw new MyExceptionA("exception A test in interceptor");//return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("=============i'm out interceptor============");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("=============i'm out interceptor============");} }由于ExceptionHandler可以直接捕獲Interceptor中的異常,所以在Interceptor中自定義異常和Controller中一樣使用就可以。
由于ExceptionHandler可以直接捕獲Interceptor中的異常,所以在Interceptor中自定義異常和Controller中一樣使用就可以。
OVER!
總結(jié)
以上是生活随笔為你收集整理的Spring中Controller层、Filter层、Interceptor层全局统一异常处理的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Servlet架构初解析
- 下一篇: 二叉树相关性质以及数学证明