当请求输入无效时,控制器周围的Spring AOP不起作用

问题描述 投票:0回答:1

我已经使用@Around编写了一个请求/响应记录器:

@Around(value = "execution(* com.xyz.example.controller.*.*(..))")
public Object logControllers(ProceedingJoinPoint joinPoint) throws Throwable {
    Object response = joinPoint.proceed();

    // Log request and response

    return response;
}

但是,我意识到提供的请求输入(即请求正文)是否无效,例如,如果number是请求正文中的必填字段,并且必须为Integer,但是我输入了[ String作为其值并发送到端点,Spring将返回400响应而不会遇到此问题。但是,如果我输入了一些合法的输入,则让请求实际上通过端点,那么这方面就可以完成工作。那么有什么方法可以使这方面在我上面提到的情况下起作用?

PS:我曾尝试将@ControllerAdvice@ExceptionHandler结合使用,但如果触发@ControllerAdvice,看起来也不会通过上述记录器方面。

spring spring-boot logging spring-aop
1个回答
0
投票

如果不需要记录已执行的java方法,则可以使用javax.servlet.Filter

但是根据此要求,您必须访问存储在DispatcherServlet的handlerMapping中的信息。也就是说,您可以重写DispatcherServlet来完成对请求/响应对的记录。

下面是可以进一步增强并适应您的需求的示例。

public class LoggableDispatcherServlet extends DispatcherServlet {

    private final Log logger = LogFactory.getLog(getClass());

    @Override
    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        if (!(request instanceof ContentCachingRequestWrapper)) {
            request = new ContentCachingRequestWrapper(request);
        }
        if (!(response instanceof ContentCachingResponseWrapper)) {
            response = new ContentCachingResponseWrapper(response);
        }
        HandlerExecutionChain handler = getHandler(request);

        try {
            super.doDispatch(request, response);
        } finally {
            log(request, response, handler);
            updateResponse(response);
        }
    }

    private void log(HttpServletRequest requestToCache, HttpServletResponse responseToCache, HandlerExecutionChain handler) {
        LogMessage log = new LogMessage();
        log.setHttpStatus(responseToCache.getStatus());
        log.setHttpMethod(requestToCache.getMethod());
        log.setPath(requestToCache.getRequestURI());
        log.setClientIp(requestToCache.getRemoteAddr());
        log.setJavaMethod(handler.toString());
        log.setResponse(getResponsePayload(responseToCache));
        logger.info(log);
    }

    private String getResponsePayload(HttpServletResponse response) {
        ContentCachingResponseWrapper wrapper = WebUtils.getNativeResponse(response, ContentCachingResponseWrapper.class);
        if (wrapper != null) {

            byte[] buf = wrapper.getContentAsByteArray();
            if (buf.length > 0) {
                int length = Math.min(buf.length, 5120);
                try {
                    return new String(buf, 0, length, wrapper.getCharacterEncoding());
                }
                catch (UnsupportedEncodingException ex) {
                    // NOOP
                }
            }
        }
        return "[unknown]";
    }

    private void updateResponse(HttpServletResponse response) throws IOException {
        ContentCachingResponseWrapper responseWrapper =
            WebUtils.getNativeResponse(response, ContentCachingResponseWrapper.class);
        responseWrapper.copyBodyToResponse();
    }

}

HandlerExecutionChain-包含有关请求处理程序的信息。

然后您可以按以下方式注册此调度程序:

@Bean
public ServletRegistrationBean dispatcherRegistration() {
    return new ServletRegistrationBean(dispatcherServlet());
}

@Bean(name = DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServlet dispatcherServlet() {
    return new LoggableDispatcherServlet();
}

这是日志示例:

httphttp://localhost:8090/settings/testi.g.m.s.s.LoggableDispatcherServlet:LogMessage {httpStatus = 500,path ='/ error',httpMethod ='GET',clientIp ='127.0.0.1',javaMethod ='HandlerExecutionChain,带有处理程序[publicorg.springframework.http.ResponseEntity>org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)]和3个拦截器',arguments = null,response ='{“ timestamp”:1472475814077,“ status”:500,“ error”:“内部服务器错误”,“异常”:“ java.lang.RuntimeException”,“消息”:“ org.springframework.web.util.NestedServletException:请求处理失败;嵌套异常为java.lang.RuntimeException“,”路径“:” / settings / test“}'}

httphttp://localhost:8090/settings/paramsi.g.m.s.s.LoggableDispatcherServlet:LogMessage {httpStatus = 200,path ='/ settings / httpParams',httpMethod ='GET',clientIp ='127.0.0.1',javaMethod ='HandlerExecutionChain,带有处理程序[public x.y.z.DTOx.y.z.Controller.params()]和3个拦截器',arguments = null,response ='{}'}

httphttp://localhost:8090/123i.g.m.s.s.LoggableDispatcherServlet:LogMessage {httpStatus = 404,path ='/ error',httpMethod ='GET',clientIp ='127.0.0.1',javaMethod ='HandlerExecutionChain带处理程序[上市org.springframework.http.ResponseEntity>org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)]和3个拦截器',arguments = null,响应='{“时间戳”:1472475840592,“状态”:404,“错误”:“不找到”,“消息”:“未找到”,“路径”:“ / 123”}'} UPDATE

如果发生错误,Spring会自动执行错误处理。因此,BasicErrorController#error显示为请求处理程序。如果您想保留原始请求处理程序,则可以在调用#processDispatchResult之前,在spring-webmvc-4.2.5.RELEASE-sources.jar!/org/springframework/web/servlet/DispatcherServlet.java:971上覆盖此行为,缓存原始处理程序。

© www.soinside.com 2019 - 2024. All rights reserved.