起因
第三方给的接口文档不全怎么办啊,正在工作中的我,突然被一句熟悉的话给打断了。确实有时候的第三方文档不是太官方,经常漏参数,,我们用的是拦截器打印的日志,由于Spring MVC 框架的设计,只能打印出来javaBean里面已有的属性值,没有的属性值是无法解析的,这确实是一个痛点,我们的项目一直都有这个问题。决定今天必须给他解决了
经过
在拦截器中实现了 HandlerInterceptor类,然后重写 preHandle 方法,发现 getQueryString()这个方法,尝试日志打印,结果发现是只能打印出来表单请求,不能打印出来json请求,不满足我们的需求
然后继续研究,发现HttpServletRequest可以获取流 getInputStream,然后利用StringBuffer将流里面的内容打印出来。开启debug模式,发现可以满足要求,于是喜出望外,问题就这么简单的解决了?感觉总是哪里怪怪的,断点接着往下走,结果却发现Spring MVC框架却解析不到值了。最后研究发现原来流只可以读取一次,由于我在拦截器里面讲流读取过了,导致后面读不到了
最后在网上看大神笔记,受到灵感启发,决定对Filter下手
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
String contentType = request.getContentType();
HttpServletResponse res = (HttpServletResponse) response;
logger.info("request url : {}",req.getRequestURL().toString());
logger.info("request method : {}",req.getMethod());
logger.info("request ip : {}",request.getRemoteAddr());
if ((contentType != null) && (contentType.indexOf(MediaType.MULTIPART_FORM_DATA_VALUE) != -1)) {
chain.doFilter(request, response);
} else {
ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(req);
ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(res);
try {
chain.doFilter(requestWrapper, responseWrapper);
} finally {
if (StringUtils.hasLength(req.getQueryString())){
logger.info("query String parameters : {}", req.getQueryString());
}
if (requestWrapper.getContentAsByteArray().length > 0) {
logger.info("request payload: {}", new String(requestWrapper.getContentAsByteArray()));
}
String responseBody = new String(responseWrapper.getContentAsByteArray());
logger.info("http response status {}", res.getStatus());
logger.info("response : {}", responseBody);
responseWrapper.copyBodyToResponse();
}
}
}
首先实现 Filter 接口,重新里面的doFilter 方法,将request强转为 ServletRequest,这个类里面是可以打印ip,请求方法,请求的url,远程主机地址等属性信息的。 利用ContentType 来判断是文件上传,表单还是json请求。文件上传请求我们是不需要处理的,直接放形即可。表单请求需要先强转为 ContentCachingRequestWrapper,然后直接打印出来就行。JSON格式的请求,利用 (StringUtils.hasLength(req.getQueryString()) 返回值大于0来判断。调用 requestWrapper.getContentAsByteArray将内容打印出来,这个过滤器里面用的不是流,不会导致MVC框架转化为JavaBean属性丢失
结果
测试通过,将浏览器中 payload请求完全打印出来,问题解决
世上无难事,只怕有心人