弹簧过滤器的异常处理

Roh*_*ain 11 spring exception-handling spring-mvc

我使用@ExceptionHandler在spring中处理异常.使用@ExceptionHandler注释的方法捕获控制器抛出的任何异常,并相应地采取操作.为了避免为我使用@ControllerAdvice注释的每个控制器编写@exceptionHandler.

一切都按预期工作正常.

现在我有一个过滤器(是的,不是拦截器,以处理某些要求),它是使用DelegatingFilterProxy和ContextLoaderListener实现的.

当我从上面的过滤器中抛出相同的异常时,它没有像在控制器情况下那样完成.它直接抛给用户.

这里有什么问题?

And*_*and 18

过滤器在控制器被解析之前发生,因此控制器建议无法捕获从过滤器抛出的异常.

过滤器是servlet的一部分,而不是MVC堆栈.

  • 我想是这样.可以有任何解决方案吗?我们可以在过滤器中自动装配弹簧豆,这意味着我们可以使用弹簧DI,而不是整个堆叠,但它的一些功能.一种解决方法(尽管应该避免),在异常的情况下,过滤器捕获它们并抛出一个控制器,然后抛出异常.这只是为了保持一致性. (3认同)

Ric*_*ard 12

由于异常不是从控制器而是从过滤器引发的,@ControllerAdvice 不会捕获它。

因此,我在四处寻找后找到的最佳解决方案是为这个内部错误创建一个过滤器:

public class ExceptionHandlerFilter extends OncePerRequestFilter {
    @Override
    public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        try {
            filterChain.doFilter(request, response);

        } catch (JwtException e) {
            setErrorResponse(HttpStatus.BAD_REQUEST, response, e);
            e.printStackTrace();
        } catch (RuntimeException e) {
            e.printStackTrace();
            setErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR, response, e);
        }
    }

    public void setErrorResponse(HttpStatus status, HttpServletResponse response, Throwable ex){
        response.setStatus(status.value());
        response.setContentType("application/json");
        // A class used for errors
        ApiError apiError = new ApiError(status, ex);
        try {
            String json = apiError.convertToJson();
            System.out.println(json);
            response.getWriter().write(json);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

将其添加到您的配置中,我正在使用 WebSecurityConfigurerAdapter 实现:

// Custom JWT based security filter
httpSecurity
        .addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);

// Custom Exception Filter for filter
httpSecurity
        .addFilterBefore(exceptionHandlerFilterBean(), JwtAuthenticationTokenFilter.class);
Run Code Online (Sandbox Code Playgroud)

错误类:

public class ApiError {

    private HttpStatus status;
    @JsonSerialize(using = LocalDateTimeSerializer.class)
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy hh:mm:ss")
    private LocalDateTime timestamp;
    private String message;
    private String debugMessage;

    private ApiError() {
        timestamp = LocalDateTime.now();
    }
    public ApiError(HttpStatus status) {
        this();
        this.status = status;
    }

    public ApiError(HttpStatus status, Throwable ex) {
        this();
        this.status = status;
        this.message = "Unexpected error";
        this.debugMessage = ex.getLocalizedMessage();
    }

    public ApiError(HttpStatus status, String message, Throwable ex) {
        this();
        this.status = status;
        this.message = message;
        this.debugMessage = ex.getLocalizedMessage();
    }

    public String convertToJson() throws JsonProcessingException {
        if (this == null) {
            return null;
        }
        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new JavaTimeModule());
        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

        return mapper.writeValueAsString(this);
    }

  //Setters and getters
}
Run Code Online (Sandbox Code Playgroud)