`HandlerInterceptor` 是Spring MVC中用于在請求處理之前、之后以及完成之后執行邏輯的接口。它與Servlet的`Filter`類似,但更加靈活,因為它可以訪問Spring的上下文和模型數據。`HandlerInterceptor` 常用于日志記錄、權限驗證、性能監控等場景。
### **1. 創建自定義 `HandlerInterceptor`**
要使用 `HandlerInterceptor`,你需要實現 `HandlerInterceptor` 接口,并重寫以下方法:
- `preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)`:在請求處理之前被調用,返回`true`表示繼續執行后續的攔截器或Controller,返回`false`表示中斷執行。
- `postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)`:在請求處理之后被調用,但視圖渲染之前。
- `afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)`:在請求處理完成之后被調用,無論是否發生異常。
以下是一個簡單的自定義 `HandlerInterceptor` 示例:
```java
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class CustomInterceptor implements HandlerInterceptor {
? ? @Override
? ? public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
? ? ? ? // 請求處理之前執行
? ? ? ? System.out.println("Pre Handle method is Calling");
? ? ? ? System.out.println("Request URL: " + request.getRequestURL());
? ? ? ? return true; // 返回true繼續執行后續邏輯,返回false中斷執行
? ? }
? ? @Override
? ? public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
? ? ? ? // 請求處理之后執行
? ? ? ? System.out.println("Post Handle method is Calling");
? ? ? ? if (modelAndView != null) {
? ? ? ? ? ? modelAndView.addObject("timestamp", System.currentTimeMillis());
? ? ? ? }
? ? }
? ? @Override
? ? public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
? ? ? ? // 請求處理完成之后執行
? ? ? ? System.out.println("Request and Response is completed");
? ? ? ? if (ex != null) {
? ? ? ? ? ? System.out.println("Exception occurred: " + ex.getMessage());
? ? ? ? }
? ? }
}
```
### **2. 注冊 `HandlerInterceptor`**
在Spring MVC中,可以通過 `WebMvcConfigurer` 接口注冊 `HandlerInterceptor`。以下是一個示例:
```java
import org.springframework.beans.factory.annotation.Autowired;
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 {
? ? @Autowired
? ? private CustomInterceptor customInterceptor;
? ? @Override
? ? public void addInterceptors(InterceptorRegistry registry) {
? ? ? ? // 注冊自定義攔截器,指定攔截路徑
? ? ? ? registry.addInterceptor(customInterceptor)
? ? ? ? ? ? ? ? .addPathPatterns("/api/**") // 攔截/api路徑下的所有請求
? ? ? ? ? ? ? ? .excludePathPatterns("/api/public/**"); // 排除/api/public路徑下的請求
? ? }
}
```
### **3. 測試 `HandlerInterceptor`**
啟動Spring Boot應用后,訪問 `/api/**` 路徑下的任何接口,`CustomInterceptor` 都會攔截請求并執行相應的邏輯。
### **4. 使用場景**
- **日志記錄**:記錄請求的URL、參數、響應時間等。
- **權限驗證**:在 `preHandle` 方法中檢查用戶是否登錄,是否有權限訪問某個資源。
- **性能監控**:在 `preHandle` 和 `afterCompletion` 方法中記錄請求處理的時間。
- **數據預處理**:在 `postHandle` 方法中修改模型數據或視圖。
### **5. 完整示例**
以下是一個完整的Spring Boot項目示例,包含自定義 `HandlerInterceptor` 和注冊邏輯:
#### **`CustomInterceptor.java`**
```java
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class CustomInterceptor implements HandlerInterceptor {
? ? @Override
? ? public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
? ? ? ? System.out.println("Pre Handle method is Calling");
? ? ? ? System.out.println("Request URL: " + request.getRequestURL());
? ? ? ? return true;
? ? }
? ? @Override
? ? public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
? ? ? ? System.out.println("Post Handle method is Calling");
? ? ? ? if (modelAndView != null) {
? ? ? ? ? ? modelAndView.addObject("timestamp", System.currentTimeMillis());
? ? ? ? }
? ? }
? ? @Override
? ? public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
? ? ? ? System.out.println("Request and Response is completed");
? ? ? ? if (ex != null) {
? ? ? ? ? ? System.out.println("Exception occurred: " + ex.getMessage());
? ? ? ? }
? ? }
}
```
#### **`WebConfig.java`**
```java
import org.springframework.beans.factory.annotation.Autowired;
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 {
? ? @Autowired
? ? private CustomInterceptor customInterceptor;
? ? @Override
? ? public void addInterceptors(InterceptorRegistry registry) {
? ? ? ? registry.addInterceptor(customInterceptor)
? ? ? ? ? ? ? ? .addPathPatterns("/api/**")
? ? ? ? ? ? ? ? .excludePathPatterns("/api/public/**");
? ? }
}
```
#### **`Controller` 示例**
```java
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
? ? @GetMapping("/api/test")
? ? public String test() {
? ? ? ? return "Hello, World!";
? ? }
? ? @GetMapping("/api/public/test")
? ? public String publicTest() {
? ? ? ? return "This is a public endpoint";
? ? }
}
```
### **6. 輸出示例**
訪問 `/api/test` 時,控制臺輸出:
```
Pre Handle method is Calling
Request URL: http://localhost:8080/api/test
Post Handle method is Calling
Request and Response is completed
```
訪問 `/api/public/test` 時,控制臺不會輸出攔截器的日志,因為該路徑被排除了。
通過以上方法,你可以輕松地在Spring項目中使用 `HandlerInterceptor` 來實現各種功能。
下面這個例子是使用了自定義注解方式
在Spring中結合`HandlerInterceptor`和自定義注解可以實現靈活的請求處理邏輯,例如權限校驗、日志記錄等。以下是一個完整的示例,展示如何定義自定義注解,并在`HandlerInterceptor`中使用它。
### **1. 定義自定義注解**
首先,定義一個自定義注解,用于標記需要特殊處理的Controller方法。例如,定義一個`@Loggable`注解,用于記錄方法的調用信息:
```java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD) // 僅適用于方法
@Retention(RetentionPolicy.RUNTIME) // 運行時保留
public @interface Loggable {
? ? String value() default ""; // 可選的描述信息
}
```
### **2. 創建攔截器**
接下來,創建一個`HandlerInterceptor`實現類,用于在請求處理前后執行邏輯:
```java
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LoggingInterceptor implements HandlerInterceptor {
? ? @Override
? ? public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
? ? ? ? if (handler instanceof HandlerMethod) {
? ? ? ? ? ? HandlerMethod handlerMethod = (HandlerMethod) handler;
? ? ? ? ? ? Loggable loggable = handlerMethod.getMethodAnnotation(Loggable.class);
? ? ? ? ? ? if (loggable != null) {
? ? ? ? ? ? ? ? // 獲取注解的值
? ? ? ? ? ? ? ? String description = loggable.value();
? ? ? ? ? ? ? ? System.out.println("Logging: " + description);
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? return true; // 繼續后續處理
? ? }
? ? @Override
? ? public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
? ? ? ? System.out.println("Request completed");
? ? }
}
```
### **3. 注冊攔截器**
在Spring配置中注冊攔截器,使其生效:
```java
import org.springframework.beans.factory.annotation.Autowired;
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 {
? ? @Autowired
? ? private LoggingInterceptor loggingInterceptor;
? ? @Override
? ? public void addInterceptors(InterceptorRegistry registry) {
? ? ? ? registry.addInterceptor(loggingInterceptor)
? ? ? ? ? ? ? ? .addPathPatterns("/**") // 攔截所有路徑
? ? ? ? ? ? ? ? .excludePathPatterns("/static/**", "/css/**", "/js/**"); // 排除靜態資源
? ? }
}
```
### **4. 使用自定義注解**
在Controller方法上使用自定義注解:
```java
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ExampleController {
? ? @GetMapping("/example")
? ? @Loggable(value = "This is an example method")
? ? public String exampleMethod() {
? ? ? ? return "Hello, World!";
? ? }
}
```
### **5. 測試**
啟動Spring Boot應用后,訪問`/example`路徑,控制臺將輸出類似以下內容:
```
Logging: This is an example method
Request completed
```
### **總結**
通過定義自定義注解并結合`HandlerInterceptor`,可以在Spring MVC中靈活地為特定方法添加額外的處理邏輯,例如日志記錄、權限校驗等。這種方法使得代碼更加清晰且易于維護。