在Spring Filter中抛出异常的一种办法

先说办法,如果看官觉得合适再往下看原理吧

解决办法

步骤:

1、创建一个专门抛出Filter中异常的Controller及接口方法,例如该接口地址为:/filter/login_auth_fail

@RequestMapping("/filter")
@RestController
public class FilterController {
	@RequestMapping("/login_auth_fail")
	public void loginAuthFail(HttpServletRequest request) {
	  // 此处构造一个合适的异常并抛出即可
	  String code = request.getAttribute("code");
	  throw new CustomException(code);
	}
}

2、在Filter中,需要抛出异常的地方,将异常信息存起来(例如:可以存在HttpServletRequest中),并将请求转发给上面创建的接口地址:

request.setAttribute("code", "xxx");
request.getRequestDispatcher("/filter/login_auth_fail").forward(request, response);

原理

可能大家尝试过一种拦截办法:使用@ControllerAdvice和@ExceptionHanlder组合拦截,但并没有成功拦截Filter中的异常

@ControllerAdvice
public class ExpHanlder {
  @ExceptionHandler(Exception.class)
  public void handle() {
    // do somthing...
  }
}

那为什么没有成功呢?关键在于@ControllerAdvice只是对Controller做了加强,而Filter在Controller之前进行,故而异常就这样逃出了咱们的“掌心”。
本文中介绍的办法,恰是利用了这样的运行顺序,让异常乖乖地抛出去:既然Filter中不能抛出,那我先把错误信息记录下来,把请求转发到一个特定的接口(可认为是一个“陷阱”),然后在这个接口中利用记录的错误信息复原一个异常抛出即可。

到这,解决办法的原理已经介绍完了了,后面内容按需观看,将和大家一起回顾Filter与Controller的业务流程。

借用Spring 梳理 - filter、interceptor、aop实现与区别 -第二篇中的顺序图:
Filter与Controller运行顺序
可以看到,Spring在将请求交给Controller的接口处理前、后分别调用Filter链中Filter的方法对处理进行增强。当preHandle中将异常抛出时,并没有到Controller,故而@ControllerAdvice未能拦截该异常。

笔者是在集成Shiro时,需要保留原有项目功能:在身份验证失败或越权时返回JSON格式错误信息而遇到了这个问题,因为Shiro是基于Filter做的拦截,故而需要将Filter中的错误信息抛出。
项目原先的登陆验证是放在AOP做的,而AOP也在Filter之后进行,关于Filter、Interceptor、AOP及其异常抛出顺序,可以看下这篇文章:Spring:过滤器filter、拦截器interceptor、和AOP的区别与联系

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值