SpringMVC实现全局异常处理器 (转)

出处:  SpringMVC实现全局异常处理器

  

  我们知道,系统中异常包括:编译时异常和运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。在开发中,不管是dao层、service层还是controller层,都有可能抛出异常,在springmvc中,能将所有类型的异常处理从各处理过程解耦出来,既保证了相关处理过程的功能较单一,也实现了异常信息的统一处理和维护。这篇博文主要总结一下SpringMVC中如何统一处理异常。 

异常处理思路

  首先来看一下在springmvc中,异常处理的思路

Spring MVC处理异常有4种方式: 

(1)使用Spring MVC提供的简单异常处理器SimpleMappingExceptionResolver; 

(2)实现Spring的异常处理接口HandlerExceptionResolver 自定义自己的异常处理器; 

(3)使用@ExceptionHandler注解实现异常处理;
(4)使用@ControllerAdvice + @ExceptionHandler

 

下面使用 @ControllerAdvice + @ExceptionHandler来实现

通过 @ControllerAdvice 注解,我们可以在一个地方对所有 @Controller 注解的控制器进行管理。
注解了 @ControllerAdvice 的类的方法可以使用 @ExceptionHandler、 @InitBinder、 @ModelAttribute 注解到方法上,这对所有注解了 @RequestMapping 的控制器内的方法都有效。

  1:@ExceptionHandler:用于捕获所有控制器里面的异常,并进行处理。
  2:@InitBinder:用来设置 WebDataBinder,WebDataBinder 用来自动绑定前台请求参数到 Model 中。
  3:@ModelAttribute@ModelAttribute 本来的作用是绑定键值对到 Model 里,此处是让全局的@RequestMapping 都能获得在此处设置的键值对。
本文使用 @ControllerAdvice + @ExceptionHandler 进行全局的 Controller 层异常处理。只要设计得当,就再也不用在 Controller 层进行 try-catch 了!

一、经典案例
 需求:希望通过全局统一的异常处理将自定义错误码以json的形式发送给前端。

1、统一返回结果类 ApiResult
首先,定义一个统一结果返回类,最终需要将这个结果类的内容返回给前端。:

/**
 * Api统一的返回结果类
 */
public class ApiResult {

    /**
     * 结果码
     */
    private String code;
    
    /**
     * 结果码描述
     */
    private String msg;
    
    
    public ApiResult() {
    }

    public ApiResult(ResultCode resultCode) {
        this.code = resultCode.getCode();
        this.msg = resultCode.getMsg();
    }
    
    /**
     * 生成一个ApiResult对象, 并返回
     *
     * @param resultCode
     * @return
     */
    public static ApiResult of(ResultCode resultCode) {
        return new ApiResult(resultCode);
    }


    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;
    }

    @Override
    public String toString() {
        return "ApiResult{" +
                "code='" + code + '\'' +
                ", msg='" + msg + '\'' +
                '}';
    }
    
}

2、错误码枚举类 ResultCode

有了 ApiResult ,接下来需要定义一个枚举类, 来包含所有自定义的结果码。

/**
 * 错误码
 */
public enum ResultCode {
    SUCCESS("0", "success"),
    UNKNOWN_ERROR("0x10001", "unkonwn error"),
    USERNAME_ERROR("0x10002", "username error or does not exist"),
    PASSWORD_ERROR("0x10003", "password error"),
    USERNAME_EMPTY("0x10004", "username can not be empty");
    
    private String code;
    private String msg;
    
    ResultCode(String code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public String getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }

}

3、自定义业务异常类 BusinessRuntimeException

接下来需要定义我们自己的业务异常类,以后和业务相关的异常通通抛出这个异常类,我们将错误码枚举变量的值存于其中。

/**
 *    自定义业务异常
 */
public class BusinessRuntimeException extends RuntimeException{
    
    private String code;
    private String msg;
    private ResultCode resultCode;
    
    public BusinessRuntimeException(ResultCode resultCode) {
        super(resultCode.getMsg());
        this.code = resultCode.getCode();
        this.msg = resultCode.getMsg();
        this.resultCode = resultCode;
    }

    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;
    }

    public ResultCode getResultCode() {
        return resultCode;
    }

    public void setResultCode(ResultCode resultCode) {
        this.resultCode = resultCode;
    }

}

4、全局异常处理类 GlobalExceptionResolver
最后便是定义全局异常处理类。

  1:通过 @ControllerAdvice 指定该类为 Controller 增强类。
  2:通过 @ExceptionHandler 自定捕获的异常类型。
  3:通过 @ResponseBody 返回 json 到前端。
注意一点:被@ControllerAdvice注解的全局异常处理类也是一个 Controller ,我们需要配置扫描路径,确保能够扫描到这个Controller

/**
 *  全局Controller层异常处理类
 */
@ControllerAdvice
public class GlobalExceptionResolver {

    /**
     *处理所有不可知异常
     * @param e 异常
     * @return json结果
     */
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public ApiResult handleException(Exception e) {
        System.out.println(e.getMessage());
        return ApiResult.of(ResultCode.UNKNOWN_ERROR);
    }
    
    /**
             * 处理所有业务异常
     * @param e 业务异常
     * @return json结果
     */
    @ExceptionHandler(BusinessRuntimeException.class)
    @ResponseBody
    public ApiResult handleOpdRuntimeException(BusinessRuntimeException e) {
        System.out.println(e.getMessage());
        return ApiResult.of(e.getResultCode());
    }

}

二、测试

1、测试 TestExceptionController

@Controller
@RequestMapping("/test/")
public class TestExceptionController {

    /**
     * 测试返回异常信息
     * @return
     */
    @RequestMapping(value = "exception.do",method = RequestMethod.GET)
    public String returnExceptionInfo() {

        if (1 != 2) {
            // 用户民错误或不存在异常
            throw new BusinessRuntimeException(ResultCode.USERNAME_ERROR);
        }

        return "success";
    }

}

 

效果:

 

其他比较全的文章可以看这个: SpringMVC中的统一异常处理

 

posted @ 2019-11-08 15:54  myseries  阅读(2256)  评论(0编辑  收藏  举报