如何在使用 ResponseStatusException 时记录异常信息

use*_*613 8 java spring spring-mvc spring-boot

我正在使用ExceptionAdviceResponseStatusException来处理我的网络应用程序中的异常情况。现在我想在抛出ResponseStatusException控制器类时记录异常信息。

我总是可以在 Controller 类中抛出异常的行附近编写日志代码:

controllerMethod(){
    logger.error("some thing happens here!");
    throw new ResponseStatusException(HttpStatus.FORBIDDEN, "some reason");
}
Run Code Online (Sandbox Code Playgroud)

但是到处编写代码太乏味了,事实上,我想要一些我在课堂上使用的模式ExceptionAdvice

@ResponseBody
@ExceptionHandler(MyException.class)
@ResponseStatus(HttpStatus.FORBIDDEN)
String myExceptionHandler(MyException e){
    logger.error("oops!", e);
    return "something";
}
Run Code Online (Sandbox Code Playgroud)

然而,ReponseStatusExceptionSpring 生成的响应具有我想要维护的格式,例如:

{
    "timestamp": "2018-02-01T04:28:32.917+0000",
    "status": 400,
    "error": "Bad Request",
    "message": "Provide correct Actor Id",
    "path": "/actor/8/BradPitt"
}
Run Code Online (Sandbox Code Playgroud)

那么,无论如何,我是否可以使用建议类进行日志记录,ResponseStatusException同时仍保持其生成的响应,或者相反,使用其他类来添加日志功能,而无需在引发异常的任何地方键入ReponseStatusExceptionlogger.error

wut*_*aer 8

您可以使用属性启用日志记录

spring.mvc.log-resolved-exception=true
Run Code Online (Sandbox Code Playgroud)

涉及的类有

  • WebMvc自动配置
  • 抽象处理异常解析器
  • 响应状态异常解析器


Ged*_*msa 4

这是一种方法(在 Spring Boot 2.3.3 中测试)。

创建一个扩展的类ResponseStatusExceptionResolver

    /**
     * Extended implementation that adds logging of {@link ResponseStatusException}s.
     * <p>
     * Note: {@link #setMessageSource(MessageSource)} has to be called if reason is a message code, rather than a message itself
     */
    private static class LoggingResponseStatusExceptionResolver extends ResponseStatusExceptionResolver {
        @Override
        protected ModelAndView resolveResponseStatus(ResponseStatus responseStatus, HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            log(responseStatus.code(), responseStatus.reason(), ex);
            return super.resolveResponseStatus(responseStatus, request, response, handler, ex);
        }

        @Override
        protected ModelAndView resolveResponseStatusException(ResponseStatusException ex, HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            log(ex.getStatus(), ex.getReason(), ex);
            return super.resolveResponseStatusException(ex, request, response, handler);
        }

        private void log(HttpStatus status, String reason, Exception exception) {
            if (status.isError()) {
                logger.error(status + ": " + reason + "\n", exception);
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

然后在您的应用程序配置类之一中实现WebMvcConfigurer默认解析器并将其替换为扩展解析器:

    @Override
    public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
        resolvers.replaceAll(resolver ->
                resolver instanceof ResponseStatusExceptionResolver
                        ? new LoggingResponseStatusExceptionResolver()
                        : resolver
        );
    }
Run Code Online (Sandbox Code Playgroud)