校園二手交易網(wǎng)站開發(fā)背景百度推廣有用嗎
統(tǒng)計(jì)請(qǐng)求的處理時(shí)間(用時(shí))既可以使用 Servlet 過濾器(Filter)
,也可以使用 Spring 攔截器(Interceptor)
。兩者都可以在請(qǐng)求處理前后插入自定義邏輯,從而實(shí)現(xiàn)對(duì)請(qǐng)求響應(yīng)時(shí)間的統(tǒng)計(jì)。
使用建議
如果你需要在更底層、與框架無關(guān)的地方記錄所有請(qǐng)求(包括靜態(tài)資源請(qǐng)求)的處理時(shí)間,那么 Servlet 過濾器
是一個(gè)更好的選擇。
如果你正在使用 Spring MVC 并且關(guān)注的是 Controller 層的處理時(shí)間,或者需要訪問到 Spring 上下文中的服務(wù),那么 Spring 攔截器
可能更為合適。
代碼樣例
Servlet 過濾器(Filter)
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;import java.io.IOException;
import java.time.Instant;// @Component 注冊(cè)時(shí)會(huì)new 這里無需指定 registration.setFilter(new LogFilter());
@Slf4j
public class LogFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {System.err.println("***LogFilter.doFilter.start***");HttpServletRequest httpReq = (HttpServletRequest) request;long startTime = Instant.now().toEpochMilli();// 記錄請(qǐng)求開始時(shí)間及請(qǐng)求信息log.warn("LogFilter.doFilter: Start processing request at {} - {}", Instant.now(), httpReq.getRequestURI());try {// 將請(qǐng)求傳遞給下一個(gè)過濾器或目標(biāo)資源chain.doFilter(request, response);} finally {// 記錄請(qǐng)求結(jié)束時(shí)間及響應(yīng)狀態(tài)碼long endTime = Instant.now().toEpochMilli();int statusCode = ((HttpServletResponse) response).getStatus();log.warn("LogFilter.doFilter: Finished processing request at {} - {} in {} ms. Status code: {}", Instant.now(), httpReq.getRequestURI(), (endTime - startTime), statusCode);}System.err.println("***LogFilter.doFilter.end***");}
}
注冊(cè)過濾器(Filter)
@Configuration
public class AppConfig {@Beanpublic FilterRegistrationBean<LogFilter> tokenFilterRegistration() {FilterRegistrationBean<LogFilter> registration = new FilterRegistrationBean<>();registration.setFilter(new LogFilter());// 可以設(shè)置過濾器名稱registration.setName("logFilter");// 設(shè)置攔截規(guī)則registration.addUrlPatterns("/*"); // 攔截所有請(qǐng)求// 設(shè)置過濾器執(zhí)行順序,默認(rèn)為0,數(shù)值越小優(yōu)先級(jí)越高registration.setOrder(1);return registration;}
}
Spring 攔截器(Interceptor)
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import java.time.Instant;@Component
@Slf4j
public class LogInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {System.err.println("***LogInterceptor.preHandle***");long startTime = Instant.now().toEpochMilli();request.setAttribute("startTime", startTime);log.warn("LogInterceptor.postHandle: Start processing request at {} - {}", Instant.now(), request.getRequestURI());return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {System.err.println("***LogInterceptor.preHandle***");// 獲取請(qǐng)求開始時(shí)間Long startTime = (Long) request.getAttribute("startTime");if (startTime != null) {long executionTime = Instant.now().toEpochMilli() - startTime;int statusCode = response.getStatus();log.warn("LogInterceptor.postHandle: Finished processing request at {} - {} in {} ms. Status code: {}", Instant.now(), request.getRequestURI(), executionTime, statusCode);}}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.err.println("***LogInterceptor.afterCompletion***");// 在此可以添加額外的后處理邏輯,但本例中我們不需要}
}
注冊(cè)攔截器(Interceptor)
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {@Autowiredprivate ResponsePostInterceptor responsePostInterceptor;@Autowiredprivate LogInterceptor logInterceptor;/*** 為攔截器注冊(cè)表添加攔截器** @param registry 攔截器注冊(cè)表*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 在Spring MVC配置中注冊(cè)一個(gè)名為responsePostInterceptor的攔截器,使其能夠?qū)ζヅ渎窂健?**”(即對(duì)應(yīng)用程序中的所有路徑)的請(qǐng)求進(jìn)行攔截registry.addInterceptor(responsePostInterceptor).addPathPatterns("/**");registry.addInterceptor(logInterceptor).addPathPatterns("/**");}
}
[Ref] 在Spring Boot中注冊(cè)過濾器幾種方式
測試驗(yàn)證
# 過濾器開始計(jì)時(shí)
***LogFilter.doFilter.start***
[2024-01-17 08:17:55] [WARN ] [http-nio-8080-exec-2] [LogFilter.java:22] → [LogFilter.doFilter: Start processing request at 2024-01-17T00:17:55.662652400Z - /students]
***RequestHeaderCheckFilter.doFilter.start***# 攔截器組的 preHandle
***ResponsePostInterceptor.preHandle***
# log用時(shí)攔截器開始計(jì)時(shí)
***LogInterceptor.preHandle***
[2024-01-17 08:17:55] [WARN ] [http-nio-8080-exec-2] [LogInterceptor.java:20] → [LogInterceptor.postHandle: Start processing request at 2024-01-17T00:17:55.852229500Z - /students]# Controller層
***StudentController.edit***
[2024-01-17 08:17:56] [INFO ] [http-nio-8080-exec-2] [HikariDataSource.java:110] → [practisedb - Starting...]
[2024-01-17 08:17:56] [INFO ] [http-nio-8080-exec-2] [HikariPool.java:565] → [practisedb - Added connection com.mysql.cj.jdbc.ConnectionImpl@34a6ebfc]
[2024-01-17 08:17:56] [INFO ] [http-nio-8080-exec-2] [HikariDataSource.java:123] → [practisedb - Start completed.]# @ControllerAdvice對(duì)Response增強(qiáng),比如修改狀態(tài)碼,補(bǔ)充header值
***ResponsePostAdvice.supports***
***ResponsePostAdvice.beforeBodyWrite***# 攔截器組的 postHandle
***LogInterceptor.postHandle***
# log用時(shí)攔截器結(jié)束計(jì)時(shí)
[2024-01-17 08:17:56] [WARN ] [http-nio-8080-exec-2] [LogInterceptor.java:32] → [LogInterceptor.postHandle: Finished processing request at 2024-01-17T00:17:56.636557900Z - /students in 784 ms. Status code: 200]
***ResponsePostInterceptor.postHandle***# 攔截器組的 afterCompletion
***LogInterceptor.afterCompletion***
***ResponsePostInterceptor.afterCompletion***# 過濾器結(jié)束計(jì)時(shí)
***RequestHeaderCheckFilter.doFilter.end***
[2024-01-17 08:17:56] [WARN ] [http-nio-8080-exec-2] [LogFilter.java:31] → [LogFilter.doFilter: Finished processing request at 2024-01-17T00:17:56.920165800Z - /students in 1258 ms. Status code: 200]
***LogFilter.doFilter.end***