Spring编写统一异常处理

一、使用注解@ExceptionHandler

在Controller层中,使用@ExceptionHandler可以获取该Controller层下的异常。

    @ResponseBody
    //这里是说明只处理Runtime的异常
    @ExceptionHandler(RuntimeException.class)
    //JsonData是我封装的包含状态码和状态数据JAVA对象
    public JsonData RuntimeException(RuntimeException r){
        return JsonData.error(r.getMessage());
    }
    @GetMapping("/test")
    @ResponseBody
    public JsonData test(){
        throw  new RuntimeException("运行时异常");
    }

测试接口/test
在这里插入图片描述
@ExceptionHandler的value值说明要捕获的异常,默认值是该Controller层下的所有Exception异常都有该异常处理。如果要捕获全局异常,则方法里面的异常需要是所有异常的父类,即Excetion类,否则会报错,因为不同的异常类并不能相互转换。

如果上述改成如下

    @ResponseBody
    @ExceptionHandler
    //JsonData是我封装的包含状态码和状态数据JAVA对象
    public JsonData RuntimeException(NullPointerException r){
        return JsonData.error(r.getMessage());
    }
    @GetMapping("/test")
    @ResponseBody
    public JsonData test(){
        throw  new RuntimeException("运行时异常");
    }

测试接口/test
在这里插入图片描述
程序会报异常,因为RuntimeException不能转换为NullPointerException,而ExceptionHandler捕获了所有的Exception。所以个人推荐写法是@ExceptionHandler的Value值和方法中的异常类相同,如果要捕获全部类型的异常,可以如下写法;

    @ResponseBody
    //这里是说明处理所有的Exception异常
    @ExceptionHandler(Exception.class)
    //JsonData是我封装的包含状态码和状态数据JAVA对象
    public JsonData RuntimeException(Exception e){
        return JsonData.error(e.getMessage());
    }

二、使用 @ControllerAdvice + ExceptionHandler 实现异常处理

@ControllerAdice如果不标明特定Controller层,则所有的Controller都会被其代理通知,配合ExcetionHandler则能实现全局异常处理。

//@RestControllerAdvice等于@ResponseBody + @ControllerAdvice
@RestControllerAdvice
public class ExceptionController {
	//这里是用来捕获url页面无法寻址的异常
    @ExceptionHandler(Exception.class)
    public JsonData exception(Exception e){
        return JsonData.error(e.getMessage);
    }
}

如果想限定@ControllerAdvice的作用范围,其basePackageClasses和basePackages可以进行限定。前者是直接限制某些类,后者是限制某个包下的,两者都是数组类型的,即可以限定多个类和多个包
写法如下:

@RestControllerAdvice(basePackages = {"com.test.Controller","com.ali.Controller"})
@RestControllerAdvice(basePackageClasses = {userLoginController.class,studentController.class})

以上都是SpringBoot注解提供的方法,实际上Spring自身有可以实现全局异常处理的方法。

三、继承实现HandlerExceptionResolver

这是由Spring提供的,需要编写resolveException的方法,其返回类型是ModelAndView。其格式如下:

    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
    }

由于目前流行前后端分离,使用ModelAndView已经有点不符合需求了,但是该方法response参数,于是我们可以通过response传输数据,而不依赖于ModelAndView。

@Component
public class ExceptionInterceptor implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        try {
            //说明返回数据的格式和编码类型
            response.setContentType("application/json;charset=utf-8");
            PrintWriter out = response.getWriter();
            //使用fastjson工具包将数据转为JSON格式
             String message = JSONObject.toJSONString(JsonData.error(ex.getMessage()));
            out.println(message);
            out.close();

        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }
}

上述方法如果需要拦截特定类型的异常,可以使用instanceof判断Exception的类型是否为该异常,如果是,才进行对应处理;

@Component
public class ExceptionInterceptor implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
    if(ex instanceof RuntimeRuntimeException(){
        try {
            //说明返回数据的格式和编码类型
            response.setContentType("application/json;charset=utf-8");
            PrintWriter out = response.getWriter();
            //使用fastjson工具包将数据转为JSON格式
             String message = JSONObject.toJSONString(JsonData.error(ex.getMessage()));
            out.println(message);
            out.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
 }
        return null;
    }
}

测试接口/test如下
在这里插入图片描述

具体使用哪种方法由项目架构和需求决定,当然首选是第一和第二种,写法更加优雅和灵活。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值