情景:当我想用 一个过滤器(filter)来对所有请求进行jwt校验,当校验不通过时我想抛出异常,然后再通过@ExceptionHandler来全局捕获该异常,发现SpringBoot 全局异常捕获不了filter中抛出的异常
原因:因为filter是JavaWeb提供的技术,是在所有请求之前,spring是捕获不到filter抛出的异常的;
解决:要想SpringBoot 全局异常捕获到该filter抛出的异常,那么就要先让他进入到controller中去,所以可以再写个过滤器专门用来分发到异常处理controller中,再有该controller来抛出异常,最后再通过SpringBoot 全局异常捕获。
代码:
1、编写
jwt验证的filter
package com.manager.oa.filter;
import cn.hutool.jwt.JWTException;
import com.manager.oa.exception.TokenInvalidException;
import com.manager.oa.exception.TokenNullException;
import com.manager.oa.exception.TokenTimeOutException;
import com.manager.oa.util.security.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* @Author sms
* @Version V1.0.0
* @Date 2022-08-10
*/
@Slf4j
public class TokenFilter implements Filter {
@Autowired
private JwtUtil jwtUtil;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
log.debug("【过滤器】:进入到token验证过滤器-》");
/*
token验证
*/
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
log.debug("【filter】uri->{}", httpServletRequest.getRequestURI());
if (httpServletRequest.getRequestURI().equals("/login")) {
chain.doFilter(httpServletRequest, response);
} else {
String token = httpServletRequest.getHeader("X-Token");
log.debug("【filter】验证token...->{}", token);
log.debug("【filter】jwtUtil->{}", jwtUtil);
try {
if (jwtUtil.verifyJWT(token)) {
if (jwtUtil.verifyTimeJWT(token)) {
chain.doFilter(httpServletRequest, response);
} else {
throw new TokenTimeOutException("令牌过期");
}
} else {
// 抛出异常 提示令牌无效
throw new TokenInvalidException("令牌无效");
}
} catch (JWTException e) {
// 抛出异常 提示令牌null
throw new TokenNullException("令牌为null", e);
}
}
}
@Override
public void destroy() {
}
}
2、注入该bean
// token校验过滤器
@Bean
public FilterRegistrationBean myTokenFilterRegistrationBean() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
// 不能new 需要交给spring管理后,单独写方法调用 ,否则为null
filterRegistrationBean.setFilter(this.TokenExpireFilter());
// 添加过滤路径
filterRegistrationBean.addUrlPatterns("/*");
// 保证在所有过滤之前执行
filterRegistrationBean.setOrder(1);
return filterRegistrationBean;
}
@Bean
public Filter TokenExpireFilter() {
return new TokenFilter();
}
3、编写异常分发的filter
package com.manager.oa.filter;
import javax.servlet.*;
import java.io.IOException;
/**
* @Author sms
* @Version V1.0.0
* @Date 2022-08-10
*/
public class ExceptionFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
chain.doFilter(request, response);
} catch (Exception e) {
// 异常捕获,发送到error controller
request.setAttribute("filter.error", e);
//将异常分发到/error/exThrow控制器
request.getRequestDispatcher("/error/exThrow").forward(request, response);
}
}
@Override
public void destroy() {
}
}
4、注入该bean
// 异常处理过滤器
@Bean
public FilterRegistrationBean myExceptionFilterRegistrationBean() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
// 不能new 需要交给spring管理后,单独写方法调用 ,否则为null
filterRegistrationBean.setFilter(this.ExceptionFilter());
// 添加过滤路径
filterRegistrationBean.addUrlPatterns("/*");
// 保证在所有过滤之前执行
filterRegistrationBean.setOrder(Integer.MIN_VALUE);
return filterRegistrationBean;
}
@Bean
public Filter ExceptionFilter() {
return new ExceptionFilter();
}
5、编写处理异常的controller
package com.manager.oa.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
/**
* @Author sms
* @Version V1.0.0
* @Date 2022-08-10
*/
@RestController
public class ExceptionController {
@RequestMapping("/error/exThrow")
public void rethrow(HttpServletRequest request) throws Exception {
throw ((Exception) request.getAttribute("filter.error"));
}
}
6、最后全局就能捕获异常了
/**
* token null exception
*
* @param e
* @return
*/
@ExceptionHandler(TokenNullException.class)
public ResponseEntity<?> handlerConstraintViolationException(TokenNullException e) {
e.printStackTrace();
return new ResponseEntity<>(false, "101", "token令牌为null!", null);
}
/**
* token令牌过期
*
* @param e
* @return
*/
@ExceptionHandler(TokenTimeOutException.class)
public ResponseEntity<?> handlerConstraintViolationException(TokenTimeOutException e) {
e.printStackTrace();
return new ResponseEntity<>(false, "102", "token令牌过期!", null);
}
/**
* token令牌无效
*
* @param e
* @return
*/
@ExceptionHandler(TokenInvalidException.class)
public ResponseEntity<?> handlerConstraintViolationException(TokenInvalidException e) {
e.printStackTrace();
return new ResponseEntity<>(false, "103", "token令牌无效!", null);
}