统一处理一个Controller中抛出的异常


一、前言

  在搭建工程的时候,统一处理抛出的异常会让我们的程序看起来更加整洁,有序,方便管理。所以我打算在我的项目中配置使用统一异常处理。

二、步骤

  一般来说有三个步骤:

  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类,这样所有控制器的异常可以在一个地方进行处理。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM