统一处理某一类异常,能够减少代码的重复度和复杂度,有利于代码的维护。springmvc统一处理异常有三种方式
- @ExceptionHandler
使用@ExceptionHandler注解作用在方法上面,参数是具体的异常类型。一旦系统抛出这种类型的异常时,会引导到该方法来处理。但是它的缺陷很明显
处理异常的方法和出错的方法(或者异常最终抛出来的地方)必须在同一个controller,不能全局控制。
@RequestMapping(value = "/error111",method = RequestMethod.GET) @ResponseBody public ResultBean error111(){ service.test(); // int i = 1/0; return null; } @ExceptionHandler(RuntimeException.class) @ResponseBody public String error3(){ return "run time exception"; } @org.springframework.stereotype.Service public class Service { public void test(){ int i = 1/0; } }
- @ControllerAdvice + @ExceptionHandler
使用@ControllerAdvice 和@ExceptionHandler 可以全局控制异常,使业务逻辑和异常处理分隔开。
@ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(MyException.class) @ResponseBody public ResultBean handleMyException(MyException e){ System.out.println("handleMyException...."); return new ResultBean(e.getErrorEnum().getCode(),e.getErrorEnum().getMsg()); } } public class MyException extends RuntimeException { private ErrorEnum errorEnum; public MyException(ErrorEnum errorEnum){ this.errorEnum = errorEnum; } public ErrorEnum getErrorEnum() { return errorEnum; } } public enum ErrorEnum { SystemError("999","系统异常,请联系管理员"), MyError1("001","自定义异常1"), MyError2("002","自定义异常2"), MyError3("003","自定义异常3"); private String code; private String msg; ErrorEnum(String code,String msg){ this.code = code; this.msg = msg; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } } @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) public class ResultBean <T>{ private final String SUCCESSCODE = "000"; private final String SUCCESSMSG = "请求成功"; /** *999 : 请求失败 (系统异常:这时候具体问题原因要去看日志) *000 : 请求成功 * *001 : 自定义异常1,用户一眼就能看出问题在哪 *002 : 自定义异常2,用户一眼就能看出问题在哪 *003 : 自定义异常3,用户一眼就能看出问题在哪 * * * */ public String code; public String message; public T data; public ResultBean(){ this.code = SUCCESSCODE; this.message = SUCCESSMSG; } public ResultBean(String code, String message) { this.code = code; this.message = message; } public ResultBean(T data) { this(); this.data = data; } }
- 实现 HandlerExceptionResolver 接口
@Component public class MyException implements HandlerExceptionResolver{ /** * TODO 简单描述该方法的实现功能(可选). * @see org.springframework.web.servlet.HandlerExceptionResolver#resolveException(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object, java.lang.Exception) */ public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { System.out.println("This is exception handler method!"); return null; } }
优先级
既然在SpringMVC中有两种处理异常的方式,那么就存在一个优先级的问题:
当发生异常的时候,SpringMVC会如下处理:
(1)SpringMVC会先从配置文件找异常解析器HandlerExceptionResolver
(2)如果找到了异常异常解析器,那么接下来就会判断该异常解析器能否处理当前发生的异常
(3)如果可以处理的话,那么就进行处理,然后给前台返回对应的异常视图
(4)如果没有找到对应的异常解析器或者是找到的异常解析器不能处理当前的异常的时候,就看当前的Controller中有没有提供对应的异常处理器,如果提供了就由Controller自己进行处理并返回对应的视图
(5)如果配置文件里面没有定义对应的异常解析器,而当前Controller中也没有定义的话,就看有没有全局ControllerAdvice提供的全局异常处理器,如果没有那么该异常就会被抛出来。