Spring boot给接口返回添加request、response log
来源:互联网 发布:php多用户博客系统 编辑:程序博客网 时间:2024/06/11 01:57
title: spring boot给接口返回添加输入输出日志
tag: spring boot
data: 2017-06-09
Spring boot返回request、response 添加log
目前有个需求需要给接口返回添加输入输出日志,目前比价常用的方法就是使用过滤器,就可以很方便的拦截到输入请求和输出请求,那么在过滤器里面如何HttpServletRequest
HttpServletRequest
这两个对象输入和输出日志呢?
解决办法
事实上javax包里面本来就提供HttpServletRequstWrapper、HttpServletResponseWrapper两个包装类进行对请求、和放回进行拦截、我们实现这两个,这样我们就能够写一些单独的东西,就可以实现我们的效果
上代码
先写一个ResponseWrapper类来继承HttpServletResponseWrapper
package com.dzy.itar.pinpin.support.filter;import org.apache.commons.io.output.TeeOutputStream;import javax.servlet.ServletOutputStream;import javax.servlet.ServletResponse;import javax.servlet.WriteListener;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpServletResponseWrapper;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.PrintWriter;public class ResponseWrapper extends HttpServletResponseWrapper { private final ByteArrayOutputStream bos = new ByteArrayOutputStream(); private PrintWriter writer = new PrintWriter(bos); private long id; public ResponseWrapper(Long requestId, HttpServletResponse response) { super(response); this.id = requestId; } @Override public ServletResponse getResponse() { return this; } @Override public ServletOutputStream getOutputStream() throws IOException { return new ServletOutputStream() { @Override public boolean isReady() { return false; } @Override public void setWriteListener(WriteListener writeListener) { } private TeeOutputStream tee = new TeeOutputStream(ResponseWrapper.super.getOutputStream(), bos); @Override public void write(int b) throws IOException { tee.write(b); } }; } @Override public PrintWriter getWriter() throws IOException { return new TeePrintWriter(super.getWriter(), writer); } public byte[] toByteArray(){ return bos.toByteArray(); } public long getId() { return id; } public void setId(long id) { this.id = id; }}
package com.dzy.itar.pinpin.support.filter;import java.io.PrintWriter;public class TeePrintWriter extends PrintWriter{ PrintWriter branch; public TeePrintWriter(PrintWriter main, PrintWriter branch) { super(main, true); this.branch = branch; } public void write(char buf[], int off, int len) { super.write(buf, off, len); super.flush(); branch.write(buf, off, len); branch.flush(); } public void write(String s, int off, int len) { super.write(s, off, len); super.flush(); branch.write(s, off, len); branch.flush(); } public void write(int c) { super.write(c); super.flush(); branch.write(c); branch.flush(); } public void flush() { super.flush(); branch.flush(); }}
package com.dzy.itar.pinpin.support.filter;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.stereotype.Component;import org.springframework.web.filter.OncePerRequestFilter;import javax.servlet.FilterChain;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import java.io.IOException;import java.io.UnsupportedEncodingException;import java.util.concurrent.atomic.AtomicLong;@Componentpublic class LoggingFilter extends OncePerRequestFilter { protected static final Logger logger = LoggerFactory.getLogger(LoggingFilter.class); private static final String REQUEST_PREFIX = "Request: "; private static final String RESPONSE_PREFIX = "Response: "; private AtomicLong id = new AtomicLong(1); @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, final FilterChain filterChain) throws ServletException, IOException { if (logger.isDebugEnabled()) { long requestId = id.incrementAndGet(); request = new RequestWrapper(requestId, request); response = new ResponseWrapper(requestId, response); } try { filterChain.doFilter(request, response);// response.flushBuffer(); } finally { if (logger.isDebugEnabled()) { logRequest(request); logResponse((ResponseWrapper) response); } } } private void logRequest(final HttpServletRequest request) { StringBuilder msg = new StringBuilder(); msg.append(REQUEST_PREFIX); if (request instanceof RequestWrapper) { msg.append("request id=").append(((RequestWrapper) request).getId()).append("; "); } HttpSession session = request.getSession(false); if (session != null) { msg.append("session id=").append(session.getId()).append("; "); } if (request.getMethod() != null) { msg.append("method=").append(request.getMethod()).append("; "); } if (request.getContentType() != null) { msg.append("content type=").append(request.getContentType()).append("; "); } msg.append("uri=").append(request.getRequestURI()); if (request.getQueryString() != null) { msg.append('?').append(request.getQueryString()); } if (request instanceof RequestWrapper && !isMultipart(request) && !isBinaryContent(request)) { RequestWrapper requestWrapper = (RequestWrapper) request; try { String charEncoding = requestWrapper.getCharacterEncoding() != null ? requestWrapper.getCharacterEncoding() : "UTF-8"; msg.append("; payload=").append(new String(requestWrapper.toByteArray(), charEncoding)); } catch (UnsupportedEncodingException e) { logger.warn("Failed to parse request payload", e); } } logger.debug(msg.toString()); } private boolean isBinaryContent(final HttpServletRequest request) { if (request.getContentType() == null) { return false; } return request.getContentType().startsWith("image") || request.getContentType().startsWith("video") || request.getContentType().startsWith("audio"); } private boolean isMultipart(final HttpServletRequest request) { return request.getContentType() != null && request.getContentType().startsWith("multipart/form-data"); } private void logResponse(final ResponseWrapper response) { StringBuilder msg = new StringBuilder(); msg.append(RESPONSE_PREFIX); msg.append("request id=").append((response.getId())); try { msg.append("; payload=").append(new String(response.toByteArray(), response.getCharacterEncoding())); } catch (UnsupportedEncodingException e) { logger.warn("Failed to parse response payload", e); } logger.debug(msg.toString()); }}
PrintWriter是一种写入字符的一种操作类,可以写入字符,TeePrintWriter继承了他,主要功能是把原始的字符流copy到branch里面。
LoggingFilter是一种filter,继承OncePerRequestFilter,每次请求都会经过他。
主要代码就是上面这样的,我把代码放到了这里大家可以下载借鉴
源码解析
SpringMVC在处理完毕请求之后,会调用AbstractMessageConverterMethodProcessor
里的writeWithMessageConverters
方法,然后会调用AbstractGenericHttpMessageConverter
的write方法,把返回的接口输出到HttpOutputMessage里面去,事实上,然后会调用WriteInternal方法
然后里面有getBody()方法,然后里面就调用到了我们的getOutputStream方法,终于走到我们写的方法了
然后我们就可以处理这个流了
主要是copy了一份,然后再filter里面打印了出来
完毕
!
- Spring boot给接口返回添加request、response log
- spring boot log日志
- Spring Boot AOP Log
- Spring获取request和response
- 【存档记录】给Spring Boot添加远程调试端口
- spring boot 返回 html
- spring boot 中使用log
- spring boot之log日志
- Spring-boot 配置Aop获取controller里的request中的参数以及其返回值
- Spring-boot 配置Aop获取controller里的request中的参数以及其返回值
- 给ngx3m添加log功能
- spring如何获取request response session
- spring mvc 获取到request response @ModelAttribute
- Spring 注解获取request和response对象
- Spring Aspect获取request和response
- Spring AOP中获取request,response
- Spring MVC中获取request ,response
- 小程序request接口封装,实现给循环列表添加点击样式
- Ubuntu 13.04 下 完美解决 QQ 问题
- GPT & MBR 设置隐藏分区/ 或分…
- java——与c++之不同——类
- 小米手机adb无法连接的问题。 ADB …
- 小米手机重新挂载
- Spring boot给接口返回添加request、response log
- KDE 802.1x MD5认证
- Linux中查看进程的多线程
- 高德地图-历史轨迹回放
- 1047. Student List for Course (25)
- MinGW 中如何生成独立于MinGW环境…
- 阿里大于短信验证码简单使用
- 使用firework切图
- 正则匹配的test方法值一直变化的原因讲解及解决方法