我已经使用@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
,看起来也不会通过上述记录器方面。
如果不需要记录已执行的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上覆盖此行为,缓存原始处理程序。