有个需要日志记录http请求和响应的需求,通过一个logFilter来实现
一、入参打印
JSON.toJSONString(servletRequest.getParameterMap()));
二、出参打印
ServletResponse中将输出流,直接获取流并不能获取流中的数据,只可以改写响应流,替换响应内容;
所以需要重写ServletResponse来保存传到输出流的内容;
com.github.isrsal.logging.ResponseWrapper 则实现了这个需求,将输出流的内容保存在了字节数组缓冲区;
需要引入的依赖:
<dependency> <groupId>com.github.isrsal</groupId> <artifactId>spring-mvc-logger</artifactId> <version>0.2</version> <exclusions> <exclusion> <groupId>log4j</groupId> <artifactId>log4j</artifactId> </exclusion> <exclusion> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> </exclusion> <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </exclusion> </exclusions> </dependency>
获取出参的方法:
ResponseWrapper responseWrapper = new ResponseWrapper(Thread.currentThread().getId(), (HttpServletResponse) servletResponse); filterChain.doFilter(servletRequest, responseWrapper); String str = new String(responseWrapper.toByteArray(), responseWrapper.getCharacterEncoding());
三、完整的出入参打印
import com.alibaba.fastjson.JSON; import com.github.isrsal.logging.RequestWrapper; import com.github.isrsal.logging.ResponseWrapper; import org.apache.catalina.connector.RequestFacade; import org.apache.catalina.connector.ResponseFacade; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.logging.log4j.ThreadContext; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.util.HashMap; import java.util.Map; import java.util.UUID; /** * @Author: chenhao * @Date: 2018-06-14 */ @Component @WebFilter(filterName = "logFilter", urlPatterns = "/*") public class LogFilter implements Filter { private static final Log log = LogFactory.getLog(LogFilter.class); private static final String ignoreUrlRegex = ".*((pay/)|(/index)|(/index/.*)|([.]((html)|(jsp)|(css)|(js)|(gif)|(png))))$"; @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { ThreadContext.put("TId", UUID.randomUUID().toString()); ResponseWrapper responseWrapper = new ResponseWrapper(Thread.currentThread().getId(), (HttpServletResponse) servletResponse); HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest; RequestWrapper requestWrapper = new RequestWrapper(Thread.currentThread().getId(), httpServletRequest); // 请求html页面、js不打印日志 if (httpServletRequest.getRequestURI().matches(ignoreUrlRegex)) { ThreadContext.clearAll(); filterChain.doFilter(servletRequest, responseWrapper); return; } Map params; // 记录入参 log.info("请求的URL:" + httpServletRequest.getRequestURI()); filterChain.doFilter(requestWrapper, responseWrapper); // 打印from格式的入参信息 params = servletRequest.getParameterMap(); if (null != params && params.size() != 0) { log.info("入参:" + JSON.toJSONString(params)); } else { // 打印json格式的入参信息 String charEncoding = requestWrapper.getCharacterEncoding() != null ? requestWrapper.getCharacterEncoding() : "UTF-8"; log.info("入参" + new String(requestWrapper.toByteArray(), charEncoding)); } // 记录出参 String outParam = new String(); // 记录出参响应头 params = new HashMap(); // 如果响应头存在errorCode则打印,除文件下载外均不存在 try { params.put("errorCode", ((ResponseFacade) servletResponse).getHeader("errorCode")); params.put("errorMsg", (URLDecoder.decode(((ResponseFacade) servletResponse).getHeader("errorMsg"), "UTF-8"))); outParam = JSON.toJSONString(params); } catch (Exception e) { } // 记录出参响应体 if (params.size() < 2) { outParam = outParam + new String(responseWrapper.toByteArray(), responseWrapper.getCharacterEncoding()); } log.info("出参:" + outParam); ThreadContext.clearAll(); } @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void destroy() { } }