`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中灵活地为特定方法添加额外的处理逻辑,例如日志记录、权限校验等。这种方法使得代码更加清晰且易于维护。