1. 核心对比
对比项 | @Configuration + WebMvcConfigurer |
@ControllerAdvice + ResponseBodyAdvice |
---|---|---|
用途 | 配置 Spring MVC 全局行为(如拦截器、消息转换器等) | 全局拦截控制器方法的请求或响应体 |
扩展方式 | 继承 WebMvcConfigurer (旧版用 WebMvcConfigurerAdapter ) |
实现 RequestBodyAdvice / ResponseBodyAdvice |
执行时机 | 用于注册拦截器、视图解析等,在请求处理前配置 | 在请求处理前后修改请求/响应体内容 |
典型用途 | 注册自定义拦截器、跨域配置、静态资源映射 | 统一加签、解密请求、包装响应体 |
是否可替代 | ❌ 不能替代,它是“配置入口” | ❌ 不能替代,它是“数据处理” |
2. HTTP 请求流程
1. HTTP 请求到达
↓
2. Filter(过滤器) ← 最早,可终止请求(如 CORS、登录检查)
↓
3. HandlerInterceptor.preHandle() ← 推荐鉴权位置
↓
4. RequestBodyAdvice.beforeBodyRead() ← 只处理 @RequestBody 的请求体
↓
5. Controller 方法执行
↓
6. ResponseBodyAdvice.beforeBodyWrite()
↓
7. 响应返回
↓
8. HandlerInterceptor.afterCompletion()
↓
9. Filter 最终处理
关键说明:
RequestBodyAdvice
是在preHandle()
之后才执行的- 它只对带有
@RequestBody
的接口有效 - 它的目的是处理请求体内容(如解密、记录原始 JSON),不是做权限判断
3. @Configuration + WebMvcConfigurer
适用场景
3.1 适用场景
用于配置 Spring MVC 的全局行为,属于"框架配置层",适合在请求处理流程中进行前置控制或流程定制。
典型用途:
- 注册拦截器(如鉴权、日志、限流)
- 配置跨域(CORS)
- 静态资源映射
- 消息转换器(如自定义 JSON 处理)
- 添加视图控制器
3.2 Demo:使用 WebMvcConfigurer 注册鉴权拦截器
1. 自定义注解:@RequireAuth
// com.example.annotation.RequireAuth
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RequireAuth {
}
2. 拦截器:AuthInterceptor
// com.example.interceptor.AuthInterceptor
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
// 判断方法是否标记了 @RequireAuth
if (handlerMethod.hasMethodAnnotation(RequireAuth.class)) {
String token = request.getHeader("Authorization");
if (token == null || !token.equals("Bearer admin123")) {
response.setStatus(401);
response.setContentType("application/json");
response.getWriter().write("{\"error\": \"Unauthorized\"}");
return false;
}
}
}
return true;
}
}
3. 配置类:注册拦截器
// com.example.config.WebConfig
import com.example.interceptor.AuthInterceptor;
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 AuthInterceptor authInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authInterceptor)
.addPathPatterns("/api/**"); // 只拦截 /api 路径
}
}
4. 控制器测试
@RestController
public class TestController {
@GetMapping("/public")
public String publicApi() {
return "This is public";
}
@GetMapping("/private")
@RequireAuth
public String privateApi() {
return "This is private";
}
}
测试结果:
/public
:无需 token,直接访问/private
:必须携带Authorization: Bearer admin123
,否则返回 401
4. ControllerAdvice
适用场景
4.1 适用场景
用于全局增强控制器行为,属于"业务处理层",适合对所有控制器方法进行统一处理。
典型用途:
- 全局异常处理(
@ExceptionHandler
) - 统一响应体包装(
ResponseBodyAdvice
) - 请求体预处理(
RequestBodyAdvice
) - 全局数据绑定(
@ModelAttribute
)
4.2 Demo:使用 @ControllerAdvice
统一响应体格式
1. 自定义注解:@WrapResponse
// com.example.annotation.WrapResponse
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface WrapResponse {
}
2. 响应体统一包装:ResponseWrapperAdvice
// com.example.advice.ResponseWrapperAdvice
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import java.util.HashMap;
import java.util.Map;
@ControllerAdvice
public class ResponseWrapperAdvice implements ResponseBodyAdvice<Object> {
@Override
public boolean supports(MethodParameter returnType, Class<?> converterType) {
// 仅对标注 @WrapResponse 的方法生效
return returnType.getMethodAnnotation(WrapResponse.class) != null;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType,
MediaType selectedContentType,
Class<?> selectedConverterType,
ServerHttpRequest request,
ServerHttpResponse response) {
Map<String, Object> result = new HashMap<>();
result.put("code", 200);
result.put("message", "success");
result.put("data", body);
result.put("timestamp", System.currentTimeMillis());
return result;
}
}
3. 控制器测试
@RestController
public class TestController {
@GetMapping("/raw")
public String rawResponse() {
return "原始响应,不包装";
}
@GetMapping("/wrapped")
@WrapResponse
public User wrappedResponse() {
return new User("李四", 30);
}
static class User {
String name;
int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
// getter/setter 省略
public String getName() { return name; }
public int getAge() { return age; }
}
}
测试结果:
/raw
:返回"原始响应,不包装"
/wrapped
:返回 JSON:
{
"code": 200,
"message": "success",
"data": {
"name": "李四",
"age": 30
},
"timestamp": 1725432100123
}
5. 总结对比
维度 | @Configuration + WebMvcConfigurer |
@ControllerAdvice |
---|---|---|
定位 | 框架配置入口 | 控制器行为增强 |
主要用途 | 注册拦截器、跨域、静态资源等 | 全局异常处理、响应包装、请求预处理 |
执行阶段 | 请求流程的配置阶段 | 控制器方法执行的前后 |
是否影响流程 | ✅ 可拦截、终止请求 | ❌ 一般不终止,只修改数据 |
推荐场景 | 鉴权、日志、限流、CORS | 统一响应格式、加签、异常处理 |
选择建议:
- 要"控制流程" → 用
WebMvcConfigurer
+ 拦截器 - 要"处理数据" → 用
@ControllerAdvice
+ResponseBodyAdvice
/@ExceptionHandler