一、前言
在搭建工程的时候,统一处理抛出的异常会让我们的程序看起来更加整洁,有序,方便管理。所以我打算在我的项目中配置使用统一异常处理。
二、步骤
一般来说有三个步骤:
1. 定义错误
2. 将错误映射成异常
3. 处理异常,然后让异常以自己需要的形式返回到前端。
三、 具体实现
1. 定义错误
public enum Error { NO_TOKEN_FOUND(1, "No token found"), NO_VALID_TOKEN(2, "Token is not valid"); public final int errorCode; public final String errorMessage; private Error(int errorCode, String errorMessage) { this.errorCode = errorCode; this.errorMessage = errorMessage; } public int getErrorCode() { return errorCode; } public String getErrorMessage() { return errorMessage; } }
2. 将错误映射成异常
public class RequestException extends Exception{ private static final long serialVersionUID = 1L; private final Error error; public RequestException(Error err) { super(err.getErrorMessage()); this.error = err; } public Error getError() { return error; } }
3. 处理异常,然后让异常以自己需要的形式返回到前端。(这里我是直接返回的是Map形式的数据)
@ControllerAdvice public class ExceptionHandle { @ExceptionHandler(value = Exception.class) @ResponseBody public Map<String, String> handler( Exception e){ RequestException requestException = (RequestException) e; Map map = new HashMap<String, String>(); map.put(requestException.getError().errorCode,requestException.getError().errorMessage); return map; } }
4. 使用我们定义的异常
User user = userRespository.findOne(userId); if (user == null) { throw new RequestException(Error.USER_DOES_NOT_EXIST);//这里会产生一个新的异常,然后步骤三的操作会捕捉到异常,以我们定义的形式返回到前端 }
四、扩展延伸
- @ExceptionHandler:统一处理某一类异常,从而能够减少代码重复率和复杂度
- @ControllerAdvice:异常集中处理,更好的使业务逻辑与异常处理剥离开
- @ResponseStatus:可以将某种异常映射为HTTP状态码
@ExceptionHandler
源码如下:
@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface ExceptionHandler { Class<? extends Throwable>[] value() default {}; }
该注解作用对象为方法,并且在运行时有效,value()可以指定异常类。由该注解注释的方法可以具有灵活的输入参数(详细参见Spring API):
- 异常参数:包括一般的异常或特定的异常(即自定义异常),如果注解没有指定异常类,会默认进行映射。
- 请求或响应对象 (Servlet API or Portlet API): 你可以选择不同的类型,如ServletRequest/HttpServletRequest或PortleRequest/ActionRequest/RenderRequest
。
- Session对象(Servlet API or Portlet API): HttpSession或PortletSession。
- WebRequest或NativeWebRequest
- Locale
- InputStream/Reader
- OutputStream/Writer
Model
方法返回值可以为:
- ModelAndView对象
- Model对象
- Map对象
- View对象
- String对象
- 还有@ResponseBody、HttpEntity<?>或ResponseEntity<?>,以及void
@ControllerAdvice
源码如下:
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface ControllerAdvice { @AliasFor("basePackages") String[] value() default {}; @AliasFor("value") String[] basePackages() default {}; Class<?>[] basePackageClasses() default {}; Class<?>[] assignableTypes() default {}; Class<? extends Annotation>[] annotations() default {}; }
该注解作用对象为TYPE,包括类、接口和枚举等,在运行时有效,并且可以通过Spring扫描为bean组件。其可以包含由@ExceptionHandler、@InitBinder 和@ModelAttribute标注的方法,可以处理多个Controller类,这样所有控制器的异常可以在一个地方进行处理。