在SpringBoot框架中實(shí)現(xiàn)打印響應(yīng)的日志
SpringBoot框架中打印響應(yīng)的日志
在 Spring Boot 框架中,可以使用攔截器來打印響應(yīng)的日志。
通過自定義一個(gè)攔截器,可以在響應(yīng)返回給客戶端之前捕獲響應(yīng)信息,并將其記錄到日志中。
以下是在 Spring Boot 框架中打印響應(yīng)日志的步驟:
1.創(chuàng)建一個(gè)攔截器類并實(shí)現(xiàn)HandlerInterceptor接口
例如,您可以創(chuàng)建一個(gè)名為 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 { // 在響應(yīng)返回給客戶端之后被調(diào)用 // 記錄響應(yīng)信息到日志 String logMessage = "RESPONSE - " + "Status: " + response.getStatus() + " | Request URI: " + request.getRequestURI(); // 使用日志框架打印日志,例如使用 SLF4J: LoggerFactory.getLogger(ResponseLoggingInterceptor.class).info(logMessage); } }
在上面的示例中,我們在 postHandle
方法中記錄響應(yīng)的狀態(tài)碼和請求的URI。
您可以根據(jù)需要擴(kuò)展此方法,記錄更多的響應(yīng)信息。
2.注冊攔截器
在您的配置類中,將攔截器注冊到 Spring Boot 應(yīng)用程序中。
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()); } }
在上述示例中,我們實(shí)現(xiàn)了 WebMvcConfigurer
接口,并重寫了 addInterceptors
方法。
在該方法中,我們將自定義的攔截器 ResponseLoggingInterceptor
添加到攔截器注冊表中。
3.運(yùn)行應(yīng)用程序
現(xiàn)在,當(dāng)您運(yùn)行 Spring Boot 應(yīng)用程序并發(fā)送請求時(shí),攔截器將捕獲每個(gè)響應(yīng)并將其記錄到日志中。
請注意:
- 攔截器記錄的日志將在每個(gè)請求的響應(yīng)之后生成。
- 這意味著攔截器不會(huì)記錄在發(fā)生錯(cuò)誤或異常時(shí)的響應(yīng)。
- 如果您需要記錄這些情況下的響應(yīng),您可能需要結(jié)合異常處理機(jī)制來實(shí)現(xiàn)。
SpringBoot日志打印的幾種方式
記錄一下springboot日志打印的三種方式,過濾器、攔截器、AOP
1.過濾器
創(chuàng)建LogFilter類實(shí)現(xiàn)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("遠(yuǎn)程地址: {}", request.getRemoteAddr()); long startTime = System.currentTimeMillis(); filterChain.doFilter(servletRequest, servletResponse); LOG.info("------------- LogFilter 結(jié)束 耗時(shí):{} ms -------------", System.currentTimeMillis() - startTime); } }
2.攔截器
(1)創(chuàng)建LogInterceptor類實(shí)現(xiàn)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框架特有的,常用于登錄校驗(yàn),權(quán)限校驗(yàn),請求日志打印 /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("遠(yuǎn)程地址: {}", 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 結(jié)束 耗時(shí):{} ms -------------", System.currentTimeMillis() - startTime); } }
(2)創(chuàng)建SpringMvcConfig配置類實(shí)現(xiàn)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依賴,對于本代碼來說是必須的,因?yàn)楸敬a在使用AOP時(shí)想要排除敏感字段,需要fastjson下的JSONObject。如果只是單純的使用AOP是不需要這個(gè)依賴的
<dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.70</version> </dependency>
(3)創(chuàng)建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); /** 定義一個(gè)切點(diǎn) */ @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("遠(yuǎn)程地址: {}", request.getRemoteAddr()); // 打印請求參數(shù) Object[] args = joinPoint.getArgs(); // LOG.info("請求參數(shù): {}", 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("請求參數(shù): {}", JSONObject.toJSONString(arguments, excludefilter)); } @Around("controllerPointcut()") public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { long startTime = System.currentTimeMillis(); // 執(zhí)行業(yè)務(wù) Object result = proceedingJoinPoint.proceed(); // 排除字段,敏感字段或太長的字段不顯示 String[] excludeProperties = {"password", "file"}; PropertyPreFilters filters = new PropertyPreFilters(); PropertyPreFilters.MySimplePropertyPreFilter excludefilter = filters.addFilter(); excludefilter.addExcludes(excludeProperties); LOG.info("返回結(jié)果: {}", JSONObject.toJSONString(result, excludefilter)); LOG.info("------------- 結(jié)束 耗時(shí):{} ms -------------", System.currentTimeMillis() - startTime); return result; } /** * 使用nginx做反向代理,需要用該方法才能取到真實(shí)的遠(yuǎn)程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; } }
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- SpringBoot使用TraceId進(jìn)行日志鏈路追蹤的實(shí)現(xiàn)步驟
- SpringBoot使用@Slf4j注解實(shí)現(xiàn)日志輸出的示例代碼
- Springboot日志配置的實(shí)現(xiàn)示例
- springboot項(xiàng)目配置logback-spring.xml實(shí)現(xiàn)按日期歸檔日志的方法
- SpringBoot中使用AOP實(shí)現(xiàn)日志記錄功能
- SpringBoot項(xiàng)目實(shí)現(xiàn)日志打印SQL的常用方法(包括SQL語句和參數(shù))
- Springboot MDC+logback實(shí)現(xiàn)日志追蹤的方法
- SpringBoot集成logback打印彩色日志的代碼實(shí)現(xiàn)
- springboot 日志實(shí)現(xiàn)過程
相關(guān)文章
jpa異常No entity found for query問題解決
這篇文章主要為大家介紹了jpa異常之No entity found for query的異常問題解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2022-03-03java線程池實(shí)戰(zhàn)應(yīng)用步驟詳解
這篇文章主要介紹了java線程池實(shí)戰(zhàn)應(yīng)用小結(jié),包括線程池的創(chuàng)建方式,本文給大家分享兩種方式,結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧2025-04-04詳解如何通過Java實(shí)現(xiàn)壓縮PDF文檔
PDF文檔是我們?nèi)粘^k公中使用最頻繁的文檔格式。但因?yàn)榇蠖鄶?shù)PDF文檔都包含很多頁面圖像或大量圖片,這就導(dǎo)致PDF文檔過大,處理起來較為麻煩。本文將介紹如何通過Java應(yīng)用程序壓縮PDF文檔,需要的可以了解一下2022-12-12MyBatisPlus+Lombok實(shí)現(xiàn)分頁功能的方法詳解
Lombok是一個(gè)Java類庫,提供了一組注解,簡化POJO實(shí)體類開發(fā)。本文將為大家介紹一下Lombok的使用以及如何利用MyBatisPlus+Lombok實(shí)現(xiàn)分頁功能,感興趣的可以動(dòng)手嘗試一下2022-07-07如何使用Spring Security手動(dòng)驗(yàn)證用戶的方法示例
這篇文章主要介紹了如何使用Spring Security手動(dòng)驗(yàn)證用戶的方法示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-05-05java 數(shù)據(jù)結(jié)構(gòu) 冒泡排序?qū)崿F(xiàn)代碼
這篇文章主要介紹了java 數(shù)據(jù)結(jié)構(gòu) 冒泡排序的相關(guān)資料,并附實(shí)例代碼,有需要的小伙伴可以參考下2016-09-09