在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; } }
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。