SpringMVC使用Filter打印请求和返回日志
简介:关于SpringMVC过滤器和拦截器的介绍,推荐大家一篇博文:https://www.cnblogs.com/rayallenbj/p/8484276.html 这里就不过多介绍了,博文中最后一句感觉还是很有深度的是: Filter依赖于Servlet容器,而Interceptor不依赖于Servlet容器。业务场景:在我们日常开发工作中基本框架结构 SSM,当系统出现BUG...
·
简介:
- 关于SpringMVC 过滤器和拦截器的介绍,推荐大家一篇博文:https://www.cnblogs.com/rayallenbj/p/8484276.html 这里就不过多介绍了,博文中最后一句感觉还是很有深度的是: Filter依赖于Servlet容器,而Interceptor不依赖于Servlet容器。
业务场景:
- 在我们日常开发工作中基本框架结构 SSM,当系统出现BUG时需要后端程序员去确认问题,但是很多时候代码逻辑看不出什么问题,更多的时候是由于请求传参不同而导致的问题,因此需要开发者前期在 Controller 中打印一些有必要的日志供以后问题定位,但是因为每个人的书写习惯不同如何做到统一的打印,并且避免遗漏打印那,此时 Filter 就展现出它的作用了.
代码设计:
- web.xml 中加入Filter配置:
<filter>
<description>访问日志过滤器</description>
<filter-name>logFilter</filter-name>
<filter-class>com.lot.springmvc.config.LogFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>logFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
- LogFilter 中重点代码是第 40行代码,用于执行 SpringMVC中的业务
- LogFilter.java 代码:
/**
* 继承 OncePerRequestFilter 保证该过滤器只会被执行一次
*
* @author Zhangyong
* @date 2018/1/10
*/
public class LogFilter extends OncePerRequestFilter {
/**
* 初始化
*/
public LogFilter() {
System.out.println("init LogFilter");
}
/**
* 连接器方法
* @param request
* @param response
* @param filterChain
* @throws ServletException
* @throws IOException
*/
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// 请求地址
String uri = request.getRequestURI();
// 请求的参数
String requestParam = JSONObject.toJSONString(request.getParameterMap());
// 请求Body
String bodyString = getBodyString(request);
// 请求开始时间
long begin = System.currentTimeMillis();
// 打印请求信息
System.err.println("##### Request-api Url:" + uri + " Request: " +requestParam + " Body :"+ bodyString);
ResponseWrapper responseWrapper = new ResponseWrapper(response);
// 重要:执行 SpringMVC 中 HandlerInterceptor 和 Controller
filterChain.doFilter(request, responseWrapper);
// 返回的结果
String content = responseWrapper.getTextContent();
// 打印返回结果 和 请求耗时
System.err.println("##### Response-api Times " + (System.currentTimeMillis()-begin) + " ms, Url: "+ uri+ " Response: " + content);
response.getOutputStream().write(content.getBytes());
}
/**
* 获取 HttpServletRequest 中 Body 参数
* @param request
* @return
*/
private String getBodyString(HttpServletRequest request){
BufferedReader br = null;
StringBuilder sb = new StringBuilder();
try{
br = request.getReader();
String str;
while ((str = br.readLine()) != null){
sb.append(str);
}
br.close();
}catch (IOException e){
e.printStackTrace();
}
finally{
if (null != br){
try{
br.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
return sb.toString();
}
}
- 为了打印 response 中返回的数据,我们使用了 ResponseWrapper 来包装 Response,用于打印结果【博主此处声明,关于ResponseWrapper 是多年前百度别人博客并用于工作中的,具体出处已经忘了,请多多见谅!另外博主未懂ResponseWrapper 是如何起作用,为什么起到作用,现在把代码贴出来,记录一下,慢慢研究】
- ResponseWrapper.java
public class ResponseWrapper extends HttpServletResponseWrapper {
private ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
private PrintWriter printWriter = new PrintWriter(outputStream);
public ResponseWrapper(HttpServletResponse response) {
super(response);
}
@Override
public PrintWriter getWriter() throws IOException {
return printWriter;
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
return new ServletOutputStream() {
@Override
public boolean isReady() {
return false;
}
@Override
public void setWriteListener(WriteListener listener) {
}
@Override
public void write(int b) throws IOException {
outputStream.write(b);
}
};
}
public void flush(){
try {
printWriter.flush();
printWriter.close();
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public ByteArrayOutputStream getByteArrayOutputStream(){
return outputStream;
}
public String getTextContent() {
flush();
return outputStream.toString();
}
}
- 具体ResponseWrapper代码介绍暂时无能为力,博主对于 Http请求、和Servlert容器理解还是不够透彻,以后再补全…见谅!
Logack:
最近在学习 LogBack 时发现一个非常有意思的功能,可以让 LogBack 帮我们打印 http 请求信息,配置如下,有兴趣的同学可以玩一玩
Maven 配置:
<!-- Logback -->
<!--这个依赖直接包含了 logback-core 以及 slf4j-api的依赖-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
XML 新增打印 Http 请求配置:
<!-- 访问日志,仅适用于Web后台 -->
<logger name="AccessLog" level="INFO" additivity="false">
<appender-ref ref="AccessFile"/>
<!-- 生产环境删除stdout输出 -->
<appender-ref ref="stdout"/>
</logger>
<!-- http 请求打印 -->
<appender name="AccessFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${PROJECT_LOG_PATH}/access_logs/access.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${PROJECT_LOG_PATH}/access_logs/access-%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>${DEFAULT_MAX_HISTORY}</maxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%msg%n</pattern>
</encoder>
</appender>
<!-- 控制台日志打印 -->
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%date{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%thread] %logger{40}:%L - %msg%n</pattern>
</encoder>
</appender>
大家有更好的想法,和意见可以评论多多交流,博主会第一时间更正!
更多推荐
已为社区贡献1条内容
所有评论(0)