记录@Controller请求Spring Boot
我正在尝试在spring boot中使用spring @Aspect
记录我的@Controller
请求(请求名称和数据).
问题在于,当在没有有效数据的情况下使用@Valid
时,由于参数解析是之前发生的,因此该方法无法执行.
I am trying to log my @Controller
request (both request name and data ) using spring @Aspect
in spring boot .
The issue is that when using @Valid
with no valid data the method is not execute since the argument resolving happened before.
我也尝试了以下解决方案,但它们对我没有用:
I have also tried the following solutions ,but they didn't worked for me:
- 实现过滤器-需要缓存流并实现自己的Servlet流+禁用使用ThreadContext的能力,以便在逻辑中的所有日志中标识请求.
- Interceptor-我试图添加Interceptor,这有两个问题,首先是扩展了WebMvcAutoConfiguration.EnableWebMvcConfiguration或WebMvcConfigurationSupport,导致自动配置第二次无法工作以获取数据,我需要在以后的阶段中添加它,因为在预处理中没有我仍然可以使用ThreadContext和
@InitBinder
,但是我仍然会遇到第一个问题,不是很干净的解决方案.
- Implementing Filter - It required to cache the Stream and Implement your own Servlet Stream + It disable the abbility to use ThreadContext in order to identify the request in all logs in logic.
- Interceptor - I was trying to add Interceptor this has two problems first extends WebMvcAutoConfiguration.EnableWebMvcConfiguration or WebMvcConfigurationSupport cause the Autoconfig not to work secondly in order to get the data I need to add it in a later phase since in pre handle it not readed yet .I can use ThreadContext and
@InitBinder
for that I guess but it still leave me with the first problem and very not clean solution.
如果有人对如何将@Aspect与@Valid结合使用有其他想法或好的建议,将非常有帮助. 谢谢
If anyone has other idea or good suggestion on how to use @Aspect with @Valid it will be very helpful . Thanks
要记录请求和响应标头和正文,您可以注册日志过滤器:
To log request and response headers and body you can register your log filter:
package demo;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.util.Collections;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import org.apache.commons.io.output.TeeOutputStream;
import org.springframework.boot.context.embedded.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.mock.web.DelegatingServletOutputStream;
@Configuration
public class HttpServerConfig {
private final static Logger LOG = Logger.getLogger(HttpServerConfig.class.getName());
@Bean
public FilterRegistrationBean logFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setDispatcherTypes(DispatcherType.REQUEST);
registration.setFilter(new Filter() {
@Override
public void init(FilterConfig fc) throws ServletException {
LOG.info("Init LOG Request Filter");
}
private void logRequest(HttpServletRequest httpReq) throws IOException {
// log request headers
LOG.info("### Request Headers:");
for (String header : Collections.list(httpReq.getHeaderNames())) {
LOG.log(Level.INFO, "\t* {0}: {1}", new Object[]{header, httpReq.getHeader(header)});
}
// log request body
Scanner qs = new Scanner(httpReq.getInputStream()).useDelimiter("\\A");
String qb = qs.hasNext() ? qs.next() : "[empty body]";
LOG.log(Level.INFO, "### Request body: `{0}` ###", qb);
}
private void logResponse(HttpServletResponse httpResp, ByteArrayOutputStream baos) {
// log response headers
LOG.log(Level.INFO, "### Response [{0}] Headers:", httpResp.getStatus());
for (String header : httpResp.getHeaderNames()) {
LOG.log(Level.INFO, "\t* {0}: {1}", new Object[]{header, httpResp.getHeader(header)});
}
// log response body
LOG.log(Level.INFO, "### Response body: `{0}` ###", baos.toString());
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
logRequest((HttpServletRequest) req);
HttpServletResponse httpResp = (HttpServletResponse) resp;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
final PrintStream ps = new PrintStream(baos);
chain.doFilter(req, new HttpServletResponseWrapper(httpResp) {
@Override
public ServletOutputStream getOutputStream() throws IOException {
return new DelegatingServletOutputStream(new TeeOutputStream(super.getOutputStream(), ps));
}
@Override
public PrintWriter getWriter() throws IOException {
return new PrintWriter(new DelegatingServletOutputStream(new TeeOutputStream(super.getOutputStream(), ps)));
}
});
logResponse(httpResp, baos);
}
@Override
public void destroy() {
LOG.info("Destroy LOG Request Filter");
}
});
return registration;
}
}