起因
第三方给的接口文档不全怎么办啊,正在工作中的我,突然被一句熟悉的话给打断了。确实有时候的第三方文档不是太官方,经常漏参数,,我们用的是拦截器打印的日志,由于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请求完全打印出来,问题解决
世上无难事,只怕有心人