在SpringBoot框架中实现打印响应的日志

 更新时间:2024年05月22日 09:05:08   作者:小子宝丁  
这篇文章主要介绍了在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;
    }

}

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。 

相关文章

  • 全网最精细详解二叉树,2万字带你进入算法领域

    全网最精细详解二叉树,2万字带你进入算法领域

    大家好,我是哪吒,一个热爱编码的Java工程师,本着"欲速则不达,欲达则欲速"的学习态度,在程序猿这条不归路上不断成长,所谓成长,不过是用时间慢慢擦亮你的眼睛,少时看重的,年长后却视若鸿毛,少时看轻的,年长后却视若泰山,成长之路,亦是渐渐放下执念,内心归于平静的旅程
    2021-08-08
  • idea maven 项目src下的配置文件没有同步至target的解决操作

    idea maven 项目src下的配置文件没有同步至target的解决操作

    这篇文章主要介绍了idea maven 项目src下的配置文件没有同步至target的解决操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-08-08
  • springboot application.properties 文件注入数组方式

    springboot application.properties 文件注入数组方式

    这篇文章主要介绍了springboot application.properties 文件注入数组方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • jenkins中如何集成commander应用的完整步骤

    jenkins中如何集成commander应用的完整步骤

    jenkins是一个用java编写的开源的持续集成工具,在与oracle发生争执后,项目从hudson项目独立出来,下面这篇文章主要给大家介绍了关于jenkins中如何集成commander应用的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2018-05-05
  • SpringBoot+Quartz实现定时任务的代码模版分享

    SpringBoot+Quartz实现定时任务的代码模版分享

    quartz 是一款开源且丰富特性的Java 任务调度库,用于实现任务调度和定时任务,本文主要和大家分享一个SpringBoot整合Quartz实现定时任务的代码模版,需要的可以参考一下
    2023-06-06
  • idea中提示Class 'xxx' is never used的解决

    idea中提示Class 'xxx' is never us

    这篇文章主要介绍了idea中提示Class 'xxx' is never used的解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-01-01
  • Java获取文件夹下所有文件名称的方法示例

    Java获取文件夹下所有文件名称的方法示例

    这篇文章主要介绍了Java获取文件夹下所有文件名称的方法,涉及java针对文件与目录相关操作技巧,需要的朋友可以参考下
    2017-06-06
  • es(elasticsearch)整合SpringCloud(SpringBoot)搭建教程详解

    es(elasticsearch)整合SpringCloud(SpringBoot)搭建教程详解

    这篇文章主要介绍了es(elasticsearch)整合SpringCloud(SpringBoot)搭建教程,本文通过实例图文相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-06-06
  • 学习C语言对后期java有帮助吗

    学习C语言对后期java有帮助吗

    在本篇文章里小编给大家整理的是一篇关于学习C语言对后期java有帮助吗的基础文章,有兴趣的朋友们可以参考下。
    2020-11-11
  • Java之while与do-while循环的用法详解

    Java之while与do-while循环的用法详解

    在上一篇文章中,给大家讲解了循环的概念,并重点给大家讲解了for循环的使用。但在Java中,除了for循环之外,还有while、do-while、foreach等循环形式。这篇文章给大家讲解while循环的使用
    2023-05-05

最新评论