当前位置: 首页 > ai >正文

Spring MVC 扩展机制对比总结:@Configuration + WebMvcConfigurer vs @ControllerAdvice

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 {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {if (handler instanceof HandlerMethod) {HandlerMethod handlerMethod = (HandlerMethod) handler;// 判断方法是否标记了 @RequireAuthif (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 {@Autowiredprivate AuthInterceptor authInterceptor;@Overridepublic 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")@RequireAuthpublic 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> {@Overridepublic boolean supports(MethodParameter returnType, Class<?> converterType) {// 仅对标注 @WrapResponse 的方法生效return returnType.getMethodAnnotation(WrapResponse.class) != null;}@Overridepublic 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")@WrapResponsepublic 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
http://www.xdnf.cn/news/19924.html

相关文章:

  • Spring Boot 启动卡死:循环依赖与Bean初始化的深度分析
  • 【问题记录】Anaconda的jupyter NoteBook点击launch的时候,弹出的页面提示ERR_FILE_NOT_FOUND
  • 【Linux我做主】细说进程等待
  • 20.35 ChatGLM3-6B QLoRA实战:4bit量化+低秩适配,显存直降70%!
  • 重温经典之游戏模拟器选型指南
  • java注解、Lambda表达式、Servlet
  • Web安全:你所不知道的HTTP Referer注入攻击
  • 【PZ-AU15P】璞致fpga开发板 Aritx UltraScalePlus PZ-AU15P 核心板与开发板用户手册
  • 新客户 | TDengine 时序数据库赋能开源鸿蒙物联展区实时监控与展示
  • 解决 ES 模块与 CommonJS 模块互操作性的关键开关esModuleInterop
  • AI+ 行动意见解读:音视频直播SDK如何加速行业智能化
  • Excel ——INDEX + MATCH 组合
  • [iOS] 折叠 cell
  • Fiddler 实战案例解析,开发者如何用抓包工具快速解决问题
  • 鸿蒙分布式数据同步失败全解
  • jenkins使用ansible单节点lnmp
  • Nvidia Orin DK 本地 ollama 主流 20GB 级模型 gpt-oss, gemma3, qwen3 部署与测试
  • AI搜索排名规则突变:企业如何用GEO工具保持竞争力?
  • LeetCode 刷题【64. 最小路径和】
  • 无人机气象观测技术
  • 华为的 4A 架构简介
  • 代码随想录算法训练营第二十八天 | 买卖股票的最佳实际、跳跃游戏、K次取反后最大化的数组和
  • Vue基础知识-脚手架开发-初始化目录解析
  • 分布式对象存储系统 Minio 之 Centos 环境安装
  • SQLynx 3.7 发布:数据库管理工具的性能与交互双重进化
  • Java 方法:从定义调用到重载,入门到面试全攻略
  • 前端路由切换不再白屏:React/Vue 实战优化全攻略(含可运行 Demo)
  • 基于html+css+js+jquery实现轮播图(自动轮播,手动选择,翻页)
  • #T1359. 围成面积
  • 华清远见25072班I/O学习day5