Springboot 异常处理

本文详细介绍了Springboot如何处理Controller层异常,通过@RestControllerAdvice和@ExceptionHandler实现全局统一异常处理。同时,针对Filter层的异常,文章讨论了不同解决方案,包括继承BasicErrorController、使用HandlerExceptionResolver以及将异常交给Controller处理。最后,由于项目特殊性,采用了创建优先级更高的异常过滤器直接处理并返回统一异常信息。

 

一、Springboot捕获controller层异常

参考博客:https://blog.csdn.net/kinginblue/article/details/70186586

                   https://blog.csdn.net/lkforce/article/details/98494922

Spring boot项目中通过@RestControllerAdvice或者@ControllerAdvice配合@ExceptionHandler实现全局异常统一处理。

1、@ExceptionHandler注解

优点:将Controller层的异常和数据校验的异常进行统一处理,减少模板代码,减少编码量,提升扩展性和可维护性。

缺点:只能处理Controller层未捕获(往外抛)的异常,对于Interceptor(拦截器)层的异常,Spring框架层的异常,就无能为力了。

1.1 @RestControllerAdvice注解定义全局异常处理类

通过注解@RestControllerAdvice统一处理rest接口的异常信息

@RestControllerAdvice

public class GlobalExceptionHandler {

}

1.2 @ExceptionHandler 注解声明异常处理方法

方法handleException()就会处理所有Controller层抛出的Exception及其子类的异常

@RestControllerAdvice

public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)

    @ResponseBody

    String handleException(){

        return "Exception Deal!";

}

}

1.3 注解的参数

@ExceptionHandler注解中可以添加参数,参数是某个异常类的class,代表这个方法专门处理该类异常

此时注解的参数是NumberFormatException.class,表示只有方法抛出NumberFormatException时,才会调用该方法

@RestControllerAdvice

public class GlobalExceptionHandler {

    @ExceptionHandler(NumberFormatException.class)

    @ResponseBody

    String handleException(){

        return "Exception Deal!";

}

}

二、springboot捕获filter异常

1、问题背景

项目中使用@ExceptionHandler注解的方式统一controller层抛出的异常,即将统一错误信息格式,返回到前端页面,友好的展示给用户,但是在一些token认证或者鉴权认证中,如果认证失败,则不会继续走到controller层,因此抛出的错误信息无法被@ExceptionHandler捕获,使用的是springboot默认的异常拦截器,通过postman访问一个认证鉴权的url并认证失败后会,会返回如下一个错误结构,这个是springboot默认的错误信息返回结构。

2、解决这个问题网上大致有3种方法

方法1:继承springboot的BasicErrorController类,重写里面的error方法

@RestController
@Api(value = "handle filter throws exception", description = "
处理filter抛出的异常")
public class ErrorController extends BasicErrorController {

    public ErrorController() {
        super(new DefaultErrorAttributes(), new ErrorProperties());
    }
    @Override
    @RequestMapping(produces = {MediaType.APPLICATION_JSON_VALUE})
    public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
        Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL));
        HttpStatus status = getStatus(request);

        Map<String,Object> map = new HashMap<String,Object>();
        map.put("code",body.get("status"));
        map.put("msg",body.get("message"));
        return new ResponseEntity<Map<String, Object>>(map, status);
    }
}

但是该方法在我的项目中不生效,网上却也有成功的案例,还不是很清楚为啥我的项目里继承这个类不生效

方法2:HandlerExceptionResolver

参考如下博客,该方法在我的项目中仍然不生效

https://blog.csdn.net/zhang19903848257/article/details/111414675?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-5&spm=1001.2101.3001.4242

方法3:把异常交给Controller处理

既然Filter中的异常,不能经过我们定义的异常处理类,那我们就把此异常交给controller,让controller经过异常处理类,帮我们处理。

(1)定义过滤器,将异常交给controller处理

(2)调整该过滤器的位置,将这个过滤器的位置要放在存在异常处理器的前面(原因看后面图解)

(3)定义处理异常的controller

具体实现可以参考如下博客:

https://blog.csdn.net/zhang19903848257/article/details/111414675?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-5&spm=1001.2101.3001.4242

该方法是个可行的法子,但是因为我的项目中没有controller层,不是webapp的应用,不能使用@PostMapping等方法,因此,第三个步骤对我来说不适用,故使用了第四种方法

方法4:定义优先级更高的filter,在该filter里直接进行异常捕获和处理,并统一异常返回的信息,直接通过response响应返回到前端

(1)创建异常过滤器

(2)注册成bean

再次访问则实现自定义的异常结构,友好展示到前端

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值