在SpringBoot框架中实现打印响应的日志
作者:小子宝丁
SpringBoot框架中打印响应的日志
在 Spring Boot 框架中,可以使用拦截器来打印响应的日志。
通过自定义一个拦截器,可以在响应返回给客户端之前捕获响应信息,并将其记录到日志中。
以下是在 Spring Boot 框架中打印响应日志的步骤:
1.创建一个拦截器类并实现HandlerInterceptor接口
例如,您可以创建一个名为 ResponseLoggingInterceptor 的类。
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ResponseLoggingInterceptor implements HandlerInterceptor {
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
// 在响应返回给客户端之后被调用
// 记录响应信息到日志
String logMessage = "RESPONSE - " +
"Status: " + response.getStatus() +
" | Request URI: " + request.getRequestURI();
// 使用日志框架打印日志,例如使用 SLF4J: LoggerFactory.getLogger(ResponseLoggingInterceptor.class).info(logMessage);
}
}
在上面的示例中,我们在 postHandle 方法中记录响应的状态码和请求的URI。
您可以根据需要扩展此方法,记录更多的响应信息。
2.注册拦截器
在您的配置类中,将拦截器注册到 Spring Boot 应用程序中。
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new ResponseLoggingInterceptor());
}
}
在上述示例中,我们实现了 WebMvcConfigurer 接口,并重写了 addInterceptors 方法。
在该方法中,我们将自定义的拦截器 ResponseLoggingInterceptor 添加到拦截器注册表中。
3.运行应用程序
现在,当您运行 Spring Boot 应用程序并发送请求时,拦截器将捕获每个响应并将其记录到日志中。
请注意:
- 拦截器记录的日志将在每个请求的响应之后生成。
- 这意味着拦截器不会记录在发生错误或异常时的响应。
- 如果您需要记录这些情况下的响应,您可能需要结合异常处理机制来实现。
SpringBoot日志打印的几种方式
记录一下springboot日志打印的三种方式,过滤器、拦截器、AOP
1.过滤器
创建LogFilter类实现Filter接口
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
@Component
public class LogFilter implements Filter {
private static final Logger LOG = LoggerFactory.getLogger(LogFilter.class);
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// 打印请求信息
HttpServletRequest request = (HttpServletRequest) servletRequest;
LOG.info("------------- LogFilter 开始 -------------");
LOG.info("请求地址: {} {}", request.getRequestURL().toString(), request.getMethod());
LOG.info("远程地址: {}", request.getRemoteAddr());
long startTime = System.currentTimeMillis();
filterChain.doFilter(servletRequest, servletResponse);
LOG.info("------------- LogFilter 结束 耗时:{} ms -------------", System.currentTimeMillis() - startTime);
}
}
2.拦截器
(1)创建LogInterceptor类实现HandlerInterceptor接口
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 拦截器:Spring框架特有的,常用于登录校验,权限校验,请求日志打印 /login
*/
@Component
public class LogInterceptor implements HandlerInterceptor {
private static final Logger LOG = LoggerFactory.getLogger(LogInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 打印请求信息
LOG.info("------------- LogInterceptor 开始 -------------");
LOG.info("请求地址: {} {}", request.getRequestURL().toString(), request.getMethod());
LOG.info("远程地址: {}", request.getRemoteAddr());
long startTime = System.currentTimeMillis();
request.setAttribute("requestStartTime", startTime);
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
long startTime = (Long) request.getAttribute("requestStartTime");
LOG.info("------------- LogInterceptor 结束 耗时:{} ms -------------", System.currentTimeMillis() - startTime);
}
}
(2)创建SpringMvcConfig配置类实现WebMvcConfigurer接口,将上述类注册到配置类中
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.annotation.Resource;
@Configuration
public class SpringMvcConfig implements WebMvcConfigurer {
@Resource
LogInterceptor logInterceptor;
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(logInterceptor)
.addPathPatterns("/**")
.excludePathPatterns();
}
}
3.AOP
(1)打开pom.xml,添加AOP依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
(2)添加fastjson依赖,对于本代码来说是必须的,因为本代码在使用AOP时想要排除敏感字段,需要fastjson下的JSONObject。如果只是单纯的使用AOP是不需要这个依赖的
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.70</version>
</dependency>
(3)创建LogAspect类
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.support.spring.PropertyPreFilters;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
@Aspect
@Component
public class LogAspect {
private final static Logger LOG = LoggerFactory.getLogger(LogAspect.class);
/** 定义一个切点 */
@Pointcut("execution(public * com.jiawa.*.controller..*Controller.*(..))")
public void controllerPointcut() {}
@Before("controllerPointcut()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
// 开始打印请求日志
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
Signature signature = joinPoint.getSignature();
String name = signature.getName();
// 打印请求信息
LOG.info("------------- 开始 -------------");
LOG.info("请求地址: {} {}", request.getRequestURL().toString(), request.getMethod());
LOG.info("类名方法: {}.{}", signature.getDeclaringTypeName(), name);
LOG.info("远程地址: {}", request.getRemoteAddr());
// 打印请求参数
Object[] args = joinPoint.getArgs();
// LOG.info("请求参数: {}", JSONObject.toJSONString(args));
Object[] arguments = new Object[args.length];
for (int i = 0; i < args.length; i++) {
if (args[i] instanceof ServletRequest
|| args[i] instanceof ServletResponse
|| args[i] instanceof MultipartFile) {
continue;
}
arguments[i] = args[i];
}
// 排除字段,敏感字段或太长的字段不显示
String[] excludeProperties = {"password", "file"};
PropertyPreFilters filters = new PropertyPreFilters();
PropertyPreFilters.MySimplePropertyPreFilter excludefilter = filters.addFilter();
excludefilter.addExcludes(excludeProperties);
LOG.info("请求参数: {}", JSONObject.toJSONString(arguments, excludefilter));
}
@Around("controllerPointcut()")
public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
// 执行业务
Object result = proceedingJoinPoint.proceed();
// 排除字段,敏感字段或太长的字段不显示
String[] excludeProperties = {"password", "file"};
PropertyPreFilters filters = new PropertyPreFilters();
PropertyPreFilters.MySimplePropertyPreFilter excludefilter = filters.addFilter();
excludefilter.addExcludes(excludeProperties);
LOG.info("返回结果: {}", JSONObject.toJSONString(result, excludefilter));
LOG.info("------------- 结束 耗时:{} ms -------------", System.currentTimeMillis() - startTime);
return result;
}
/**
* 使用nginx做反向代理,需要用该方法才能取到真实的远程IP
* @param request
* @return
*/
public String getRemoteIp(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
}
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
