在SpringBoot框架中實現(xiàn)打印響應(yīng)的日志
SpringBoot框架中打印響應(yīng)的日志
在 Spring Boot 框架中,可以使用攔截器來打印響應(yīng)的日志。
通過自定義一個攔截器,可以在響應(yīng)返回給客戶端之前捕獲響應(yīng)信息,并將其記錄到日志中。
以下是在 Spring Boot 框架中打印響應(yīng)日志的步驟:
1.創(chuàng)建一個攔截器類并實現(xiàn)HandlerInterceptor接口
例如,您可以創(chuàng)建一個名為 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ù)需要擴展此方法,記錄更多的響應(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());
}
}
在上述示例中,我們實現(xiàn)了 WebMvcConfigurer 接口,并重寫了 addInterceptors 方法。
在該方法中,我們將自定義的攔截器 ResponseLoggingInterceptor 添加到攔截器注冊表中。
3.運行應(yīng)用程序
現(xiàn)在,當(dāng)您運行 Spring Boot 應(yīng)用程序并發(fā)送請求時,攔截器將捕獲每個響應(yīng)并將其記錄到日志中。
請注意:
- 攔截器記錄的日志將在每個請求的響應(yīng)之后生成。
- 這意味著攔截器不會記錄在發(fā)生錯誤或異常時的響應(yīng)。
- 如果您需要記錄這些情況下的響應(yīng),您可能需要結(jié)合異常處理機制來實現(xiàn)。
SpringBoot日志打印的幾種方式
記錄一下springboot日志打印的三種方式,過濾器、攔截器、AOP
1.過濾器
創(chuàng)建LogFilter類實現(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é)束 耗時:{} ms -------------", System.currentTimeMillis() - startTime);
}
}
2.攔截器
(1)創(chuàng)建LogInterceptor類實現(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框架特有的,常用于登錄校驗,權(quá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é)束 耗時:{} ms -------------", System.currentTimeMillis() - startTime);
}
}
(2)創(chuàng)建SpringMvcConfig配置類實現(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依賴,對于本代碼來說是必須的,因為本代碼在使用AOP時想要排除敏感字段,需要fastjson下的JSONObject。如果只是單純的使用AOP是不需要這個依賴的
<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);
/** 定義一個切點 */
@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é)束 耗時:{} ms -------------", System.currentTimeMillis() - startTime);
return result;
}
/**
* 使用nginx做反向代理,需要用該方法才能取到真實的遠(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é)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
- SpringBoot使用TraceId進(jìn)行日志鏈路追蹤的實現(xiàn)步驟
- SpringBoot使用@Slf4j注解實現(xiàn)日志輸出的示例代碼
- Springboot日志配置的實現(xiàn)示例
- springboot項目配置logback-spring.xml實現(xiàn)按日期歸檔日志的方法
- SpringBoot中使用AOP實現(xiàn)日志記錄功能
- SpringBoot項目實現(xiàn)日志打印SQL的常用方法(包括SQL語句和參數(shù))
- Springboot MDC+logback實現(xiàn)日志追蹤的方法
- SpringBoot集成logback打印彩色日志的代碼實現(xiàn)
- springboot 日志實現(xiàn)過程
相關(guān)文章
jpa異常No entity found for query問題解決
這篇文章主要為大家介紹了jpa異常之No entity found for query的異常問題解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2022-03-03
MyBatisPlus+Lombok實現(xiàn)分頁功能的方法詳解
Lombok是一個Java類庫,提供了一組注解,簡化POJO實體類開發(fā)。本文將為大家介紹一下Lombok的使用以及如何利用MyBatisPlus+Lombok實現(xiàn)分頁功能,感興趣的可以動手嘗試一下2022-07-07
如何使用Spring Security手動驗證用戶的方法示例
這篇文章主要介紹了如何使用Spring Security手動驗證用戶的方法示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-05-05
java 數(shù)據(jù)結(jié)構(gòu) 冒泡排序?qū)崿F(xiàn)代碼
這篇文章主要介紹了java 數(shù)據(jù)結(jié)構(gòu) 冒泡排序的相關(guān)資料,并附實例代碼,有需要的小伙伴可以參考下2016-09-09

