SpringMVC-快速入门(七)- Spring MVC全局异常处理

概述

SpringMVC 异常统一处理的三种方式:

  1. 使用 @ExceptionHandler 注解
  2. 实现 HandlerExceptionResolver 接口
  3. 使用 @ControllerAdvice + @ExceptionHandler 注解

其中,实现 HandlerExceptionResolver 接口适用于前后端分离项目不使用,用途很少,先不介绍。

@ExceptionHandler注解

作用域:局部,针对一个Controller中的指定异常类。

注有该注解的方法,和发生异常的Mapping方法,两者需要在同一个Controller里面。

@RestController
public class TestExceptionController {
    @RequestMapping("/testEx01")
    public Map testEx01(){
        Map codeMap = new HashMap();
        int i = 9/0;
        codeMap.put("code",200);
        codeMap.put("msg","ok");
        return codeMap;
    }

    // @ExceptionHandler 参数为 要处理器的 异常类(或子类)
    @ExceptionHandler(ArithmeticException.class)
    public Map exInfo(ArithmeticException e){
        Map codeMap = new HashMap();
        System.out.println(e.getMessage());
        codeMap.put("code",700);
        codeMap.put("msg","分母不能为0");
        return codeMap;
    }
}

使用postman访问url:http://localhost:8080/testEx01。

后台控制台打印:

/ by zero

@ExceptionHandler(Exception.class) 表示处理所以Exception或其子类。如果我们需要更细的异常控制,我们可以定义多个由@ExceptionHandler 注解的方法,然后对应的Exception.class不一样。

如果我们需要同一个方法处理多种类型的异常:@ExceptionHandler({Exception1.class,Exception2.class})

@ControllerAdvice 注解

作用域:全局,针对全部 Controller 中的指定异常类;该注解需要 和 @ExceptionHandler 配合,来完成全局异常的处理;

注有该注解的方法,和发生异常的Mapping方法,不需要在同一个Controller里面。

全局异常处理类GlobleExceptionAdvice:

//统一异常的通知
@RestControllerAdvice
public class GlobleExceptionAdvice {

    @ExceptionHandler(Exception.class)
    public Map showInfoE(Exception e){
        System.out.println(" 统一异常 ");
        System.out.println(e.getMessage());

        Map codeMap = new HashMap();
        codeMap.put("code",800);
        codeMap.put("msg","系统繁忙!!");
        return codeMap;
    }

    // @ExceptionHandler 参数为要处理器的 异常类(或子类)
    // 注解参数不声明指定异常类,则默认为方法列表中的异常参数类
    @ExceptionHandler(ArithmeticException.class)
    public Map showInfo(Exception e){
        System.out.println(" 算数异常 ");
        System.out.println(e.getMessage());

        Map codeMap = new HashMap();
        codeMap.put("code",800);
        codeMap.put("msg","你不能把分母设置为0");
        return codeMap;
    }

    //自定义异常
    @ExceptionHandler(MyException.class)
    public Map myException(MyException e){
        System.out.println(e.getMsg());

        Map codeMap = new HashMap();
        codeMap.put("code",e.getCode());
        codeMap.put("msg",e.getMsg());
        return codeMap;
    }
}

@ControllerAdvice 和 @RestControllerAdvice 是作用在类上的注解,@RestControllerAdvice = @ControllerAdvice + @ResponseBody。

自定义异常类MyException,需要继承 RuntimeException

//自定义异常
public class MyException extends RuntimeException{
    private int code;
    private String msg;

    public MyException() {
    }

    public MyException(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public int getCode() { return code; }

    public void setCode(int code) { this.code = code; }

    public String getMsg() { return msg; }

    public void setMsg(String msg) { this.msg = msg; }
}

控制类TestExceptionController 增加 @RequestMapping(“/testEx03”):

@RestController
public class TestExceptionController {
    ...

     //测试 自定义异常
    @RequestMapping("/testEx03")
    public Map zdyEx(int x,int y){
        Map codeMap = new HashMap();
        if (y == 1001) {
            throw new MyException(1001,"自定义异常");
        }
        int i = x/y;
        codeMap.put("code",200);
        codeMap.put("msg","ok");
        codeMap.put("data",i);
        return codeMap;
    }
}
  • 使用postman访问url:http://localhost:8080/testEx03?x=1&y=。

后台控制台打印:

统一异常 
Failed to convert value of type [java.lang.String] to required type [int]; nested exception is java.lang.NumberFormatException: For input string: ""

因为参数 y 没有传值,会触发 Exception 异常,故返回 code = 800。

  • 使用postman访问url:http://localhost:8080/testEx03?x=1&y=1001。

后台控制台打印:

自定义异常

因为参数 y 传值1001,会触发 MyException异常,故返回 code = 1001。

  • 使用postman访问url:http://localhost:8080/testEx03?x=1&y=0。

后台控制台打印:

/ by zero

当某个 Mapping 发生异常后,先由所在 Controller 的 @ExceptionHandler 处理;如果所在 Controller 没有 @ExceptionHandler,则由全局 @ControllerAdvice + @E…Handle 处理;如果没有上者,则由 HandlerExceptionResolver 处理。

所以上例中会调用 TestExceptionController 中的@ExceptionHandler 处理,返回 code = 700。

如果去除TestExceptionController 中的@ExceptionHandler,则会调用全局的GlobleExceptionAdvice。

@RestController
public class TestExceptionController {
    @RequestMapping("/testEx01")
    public Map testEx01(){
        Map codeMap = new HashMap();
        int i = 9/0;
        codeMap.put("code",200);
        codeMap.put("msg","ok");
        return codeMap;
    }

    // @ExceptionHandler 参数为 要处理器的 异常类(或子类)
    /*@ExceptionHandler(ArithmeticException.class)
    public Map exInfo(ArithmeticException e){
        Map codeMap = new HashMap();
        System.out.println(e.getMessage());
        codeMap.put("code",700);
        codeMap.put("msg","分母不能为0");
        return codeMap;
    }*/

     //测试 自定义异常
    @RequestMapping("/testEx03")
    public Map zdyEx(int x,int y){
        Map codeMap = new HashMap();
        if (y == 1001) {
            throw new MyException(1001,"自定义异常");
        }
        int i = x/y;
        codeMap.put("code",200);
        codeMap.put("msg","ok");
        codeMap.put("data",i);
        return codeMap;
    }
}
  • 使用postman访问url:http://localhost:8080/testEx03?x=1&y=0。

后台控制台打印:

 算数异常 
/ by zero

@ControllerAdvice 执行顺序

应用中有多个 @ControllerAdvice 或 @RestControllerAdvice 的时候,其顺序默认是按照bean的名称来执行的,如果需要自己指定,可以使用 @Order 注解来指定。建议指定该顺序。

小结

  1. SpringMVC 异常统一处理的三种方式:使用 @ExceptionHandler 注解;实现 HandlerExceptionResolver 接口;使用 @ControllerAdvice 注解。
  2. 当某个 Mapping 发生异常后,先由所在 Controller 的 @ExceptionHandler 处理;如果所在 Controller 没有 @ExceptionHandler,则由全局 @ControllerAdvice + @E…Handle 处理;如果没有上者,则由 HandlerExceptionResolver 处理。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不会叫的狼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值