美文网首页
servlet过滤器无法被全局异常处理器捕获处理

servlet过滤器无法被全局异常处理器捕获处理

作者: 千千雪人 | 来源:发表于2024-09-02 17:15 被阅读0次

    在Servlet的Filter中使用自定义异常通常需要一些特别的处理,因为过滤器是在请求到达Servlet之前运行的,所以过滤器中抛出的异常不会被Spring的@ControllerAdvice全局异常处理器捕获。但是,你可以通过HandlerExceptionResolver来手动触发全局异常处理。

    具体来说,你可以在过滤器中捕获异常,然后使用HandlerExceptionResolver的resolveException方法来处理这些异常。这样,你就可以将过滤器中的异常转发给全局异常处理器,从而实现统一的异常处理。

    例如,你可以创建一个过滤器,如下所示:

    java
    @Component
    public class MyFilter implements Filter {
    @Autowired
    private HandlerExceptionResolver handlerExceptionResolver;

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        try {
            chain.doFilter(request, response);
        } catch (Exception e) {
            handlerExceptionResolver.resolveException((HttpServletRequest) request, (HttpServletResponse) response, null, e);
        }
    }
    

    }
    在这个过滤器中,如果doFilter方法抛出异常,它会被捕获并使用HandlerExceptionResolver来处理。这样,你就可以在全局异常处理器中定义如何处理这些异常了。

    这种方法允许你在过滤器中使用自定义异常,并且可以利用Spring的异常处理机制来统一处理这些异常。这样,你就可以在过滤器中进行一些预处理工作,比如验证用户权限、检查请求参数等,如果发现问题就抛出自定义异常,然后在全局异常处理器中统一处理这些异常,返回给用户统一的错误响应。

    下面是一个例子说明

    1. 定义自定义异常类 GoodsException
      首先,我们定义一个GoodsException类,用于商品业务中的异常处理。

    java
    public class GoodsException extends RuntimeException {
    public GoodsException(String message) {
    super(message);
    }

    public GoodsException(String message, Throwable cause) {
        super(message, cause);
    }
    

    }

    1. 创建全局异常处理器 GlobalExceptionHandler
      接下来,我们创建一个全局异常处理器,用于处理GoodsException以及其他异常。

    java
    @ControllerAdvice
    public class GlobalExceptionHandler {

    @ExceptionHandler(GoodsException.class)
    @ResponseBody
    public ResponseEntity<Object> handleGoodsException(GoodsException ex, WebRequest request) {
        // 可以根据异常类型定义不同的错误响应
        Map<String, Object> body = new HashMap<>();
        body.put("timestamp", LocalDateTime.now());
        body.put("status", HttpStatus.BAD_REQUEST.value());
        body.put("error", "Bad Request");
        body.put("message", ex.getMessage());
        body.put("path", request.getPathInfo());
        return new ResponseEntity<>(body, HttpStatus.BAD_REQUEST);
    }
    
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public ResponseEntity<Object> handleException(Exception ex, WebRequest request) {
        // 通用异常处理
        Map<String, Object> body = new HashMap<>();
        body.put("timestamp", LocalDateTime.now());
        body.put("status", HttpStatus.INTERNAL_SERVER_ERROR.value());
        body.put("error", "Internal Server Error");
        body.put("message", ex.getMessage());
        body.put("path", request.getPathInfo());
        return new ResponseEntity<>(body, HttpStatus.INTERNAL_SERVER_ERROR);
    }
    

    }

    1. 创建过滤器 GoodsFilter
      然后,我们创建一个过滤器GoodsFilter,在过滤器中抛出GoodsException异常,并使用HandlerExceptionResolver来处理这个异常。

    java
    @Component
    public class GoodsFilter implements Filter {

    @Autowired
    private HandlerExceptionResolver handlerExceptionResolver;
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
    
        try {
            // 业务逻辑检查,如果发现问题则抛出GoodsException
            boolean isValid = checkGoods(httpRequest);
            if (!isValid) {
                throw new GoodsException("商品验证失败");
            }
            chain.doFilter(request, response);
        } catch (GoodsException ex) {
            handlerExceptionResolver.resolveException(httpRequest, httpResponse, null, ex);
        } catch (Exception ex) {
            handlerExceptionResolver.resolveException(httpRequest, httpResponse, null, ex);
        }
    }
    
    private boolean checkGoods(HttpServletRequest request) {
        // 这里添加检查商品的逻辑
        // 例如,检查请求参数中的goodsId是否有效
        String goodsId = request.getParameter("goodsId");
        return "123".equals(goodsId); // 假设商品ID为123时认为是有效的
    }
    

    }

    1. 配置过滤器
      最后,确保你的过滤器被Spring容器管理。如果你使用的是Spring Boot,可以通过@WebFilter注解自动注册过滤器,或者在配置类中使用FilterRegistrationBean来注册。

    java
    @Configuration
    public class FilterConfig {

    @Autowired
    private GoodsFilter goodsFilter;
    
    @Bean
    public FilterRegistrationBean<GoodsFilter> goodsFilterRegistration() {
        FilterRegistrationBean<GoodsFilter> registration = new FilterRegistrationBean<>();
        registration.setFilter(goodsFilter);
        registration.addUrlPatterns("/goods/*");
        return registration;
    }
    

    }
    这样,当请求匹配到/goods/*路径时,GoodsFilter过滤器会被调用。如果过滤器中的checkGoods方法发现商品验证失败,它会抛出GoodsException异常。这个异常会被HandlerExceptionResolver捕获,并由GlobalExceptionHandler中的handleGoodsException方法处理,最终返回一个统一的错误响应给客户端。

    原理解析

    在 Servlet 的 Filter 中抛出自定义异常 MyException 时,如果不调用 handlerExceptionResolver.resolveException(httpRequest, httpResponse, null, ex),异常处理逻辑不会自动触发,因为 Filter 和 Spring MVC 的异常处理机制是分开的。

    细节解释
    Filter 和 Spring MVC 的分离:

    Filter 是在 Servlet 容器层面执行的,而 Spring MVC 的异常处理机制(如 HandlerExceptionResolver)是在 Spring MVC 框架层面执行的。

    当异常在 Filter 中抛出时,Servlet 容器并不知道如何处理这个异常,因为它不属于 Spring MVC 的异常处理机制。

    HandlerExceptionResolver 的作用:

    HandlerExceptionResolver 是 Spring MVC 框架中的一个接口,用于处理控制器(Controller)中抛出的异常。

    通过调用 handlerExceptionResolver.resolveException(httpRequest, httpResponse, null, ex),你可以手动将异常交给 Spring MVC 的异常处理机制来处理。

    手动触发异常处理:

    在 Filter 中捕获到异常后,调用 handlerExceptionResolver.resolveException(httpRequest, httpResponse, null, ex) 可以将异常传递给 Spring MVC 的异常处理机制。

    这样,Spring MVC 就可以使用注册的 HandlerExceptionResolver 来处理异常,并返回自定义的 ExceptionResponse。


    总结

    关键就是HandlerExceptionResolver 这个接口,它有很多实现类,不同的实现类处理不同的异常处理实现

    SimpleMappingExceptionResolver:通过配置异常类和视图名称的映射关系,将异常映射到特定的视图。

    DefaultHandlerExceptionResolver:处理 Spring MVC 框架定义的标准异常,如 HttpRequestMethodNotSupportedException、HttpMediaTypeNotSupportedException 等。

    ResponseStatusExceptionResolver:根据异常类上标注的 @ResponseStatus 注解来设置响应状态码。

    ExceptionHandlerExceptionResolver:处理控制器中使用 @ExceptionHandler 注解定义的异常处理方法。

    相关文章

      网友评论

          本文标题:servlet过滤器无法被全局异常处理器捕获处理

          本文链接:https://www.haomeiwen.com/subject/ssghljtx.html