【Java】SpringBoot 全局异常捕获不到Filter中的异常的解决办法

情景:当我想用 一个过滤器(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);
    }
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot全局异常处理器可以用于捕获和处理应用程序抛出的异常。然而,默认情况下,Spring Boot无法捕获和处理HttpMessageNotReadableException异常。这是因为HttpMessageNotReadableException异常是由HttpMessageConverter引起的,它在尝试将请求正文转换为控制器方法参数时发生错误。 要解决这个问题,你可以实现自己的全局异常处理器,并在其捕获和处理HttpMessageNotReadableException异常。以下是一个示例: ```java @ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(HttpMessageNotReadableException.class) public ResponseEntity<Object> handleHttpMessageNotReadableException( HttpMessageNotReadableException ex, WebRequest request) { // 处理HttpMessageNotReadableException异常 // 返回自定义错误信息或其他逻辑 return new ResponseEntity<>("Error: Invalid request body", HttpStatus.BAD_REQUEST); } // 添加其他异常处理方法... } ``` 在上面的示例,我们使用@ControllerAdvice注释来标记全局异常处理器类,并使用@ExceptionHandler注释来指定处理HttpMessageNotReadableException异常的方法。在方法,我们可以根据需要自定义处理逻辑,并返回自定义错误信息或适当的HTTP状态码。 注意,为了使全局异常处理器生效,还需要确保在应用程序启用了异常处理机制。你可以通过在应用程序的启动类上添加@EnableWebMvc或@EnableWebFlux注释来实现这一点。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值