一、参数绑定(Parameter Binding)
🎯 目标
Spring MVC 支持多种方式绑定请求参数到 Controller 方法的参数中,例如:
@GetMapping("/user")
public String getUser(@RequestParam("id") int id, @RequestBody User user, @PathVariable String name) {
...
}
这些注解的背后是通过 HandlerMethodArgumentResolver
实现的。
🔧 核心组件
注解 | 对应 Resolver |
---|---|
@RequestParam | RequestParamMethodArgumentResolver |
@PathVariable | PathVariableMethodArgumentResolver |
@RequestBody | RequestResponseBodyMethodProcessor |
@ModelAttribute | ModelAttributeMethodProcessor |
@RequestHeader | RequestHeaderMethodArgumentResolver |
HttpServletRequest , HttpServletResponse | ServletRequestMethodArgumentResolver |
📦 参数解析流程
-
Controller 方法注册时
RequestMappingHandlerMapping
会为每个方法创建一个HandlerMethod
。- 所有参数信息都封装在
MethodParameter
对象中。
-
请求处理时
- 在
RequestMappingHandlerAdapter
的handleInternal()
方法中:invocableMethod.invokeForRequest(webRequest, mavContainer, providedArgs);
- 在
-
调用链触发参数解析
ServletInvocableHandlerMethod.invokeForRequest()
内部调用:Object[] args = getMethodArgumentValues(webRequest, mavContainer, providedArgs);
-
遍历所有 ArgumentResolver 尝试匹配并解析参数
- 每个
HandlerMethodArgumentResolver
都会判断是否支持当前参数类型:if (resolver.supportsParameter(parameter)) { return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory); }
- 每个
🧪 @RequestParam
的解析过程
public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(RequestParam.class);
}
protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
// 从 request.getParameter() 获取值
return request.getParameter(name);
}
}
二、拦截器(Interceptor)
🎯 目标
拦截器用于在 Controller 方法执行前后做一些统一处理,如权限验证、日志记录等。
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 请求前处理
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
// Controller 执行后,视图渲染前处理
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// 整个请求完成后的清理工作
}
📦 核心接口与类
- 接口:
HandlerInterceptor
- 类:
HandlerExecutionChain
(持有多个 Interceptor) - 配置类:
WebMvcConfigurer
(重写addInterceptors()
)
🧭 调用流程
-
获取 HandlerExecutionChain
DispatcherServlet.getHandler()
返回包含拦截器链的对象。
-
preHandle 拦截器调用
mappedHandler.applyPreHandle(request, response);
- 按顺序调用每个 Interceptor 的
preHandle()
,如果返回 false 则中断请求。
- 按顺序调用每个 Interceptor 的
-
Controller 执行完成后调用 postHandle
mappedHandler.applyPostHandle(processedRequest, response, mv);
-
afterCompletion 在整个请求结束后调用
processDispatchResult(...);
🧪 自定义拦截器
@Component
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (request.getSession().getAttribute("user") == null) {
response.sendRedirect("/login");
return false;
}
return true;
}
}
注册方式(配置类):
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Autowired
private AuthInterceptor authInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/login", "/css/**");
}
}
三、文件上传(Multipart 解析)
🎯 目标
处理客户端上传的文件,使用 MultipartResolver
接口解析 multipart/form-data
请求体。
📦 核心类
- 接口:
MultipartResolver
- 实现类:
StandardServletMultipartResolver
(基于 Servlet 3.0+)、CommonsMultipartResolver
(Apache Commons FileUpload)
🧭 文件上传处理流程
-
请求进入
DispatcherServlet.doDispatch()
-
检查是否为 multipart 请求
if (multipartResolver != null && multipartResolver.isMultipart(request)) { processedRequest = multipartResolver.resolveMultipart(request); }
-
resolveMultipart()
方法解析请求内容StandardServletMultipartResolver
使用request.getParts()
获取所有 part。- 文件部分会被封装成
MultipartFile
。
-
Controller 中接收 MultipartFile
@PostMapping("/upload") public String upload(@RequestParam("file") MultipartFile file) { ... }
-
参数解析器自动识别 MultipartFile
RequestParamMethodArgumentResolver
会检测到参数类型为MultipartFile
并正确注入。
🧪 文件上传 Controller
@PostMapping("/upload")
public String handleFileUpload(@RequestParam("file") MultipartFile file) {
if (!file.isEmpty()) {
// 处理文件
String originalFilename = file.getOriginalFilename();
// 保存文件逻辑...
}
return "redirect:/success";
}
⚙️ 配置 MultipartResolver(可选)
在 Java 配置中启用 Multipart 支持:
@Bean
public MultipartResolver multipartResolver() {
return new StandardServletMultipartResolver();
}
同时需要设置 spring.servlet.multipart.enabled=true
(Spring Boot)或配置 MultipartConfigElement
。
✅ 总结
功能 | 组件/类 | 作用 |
---|---|---|
参数绑定 | HandlerMethodArgumentResolver | 自动解析请求参数并注入到 Controller 方法中 |
拦截器 | HandlerInterceptor | 控制请求生命周期中的前置、后置处理 |
文件上传 | MultipartResolver | 解析 multipart 请求,生成 MultipartFile 对象 |
📚 源码路径
可以查看以下类的源码来进一步理解上述功能:
功能 | 源码路径 |
---|---|
参数绑定 | org.springframework.web.method.support.HandlerMethodArgumentResolver |
拦截器 | org.springframework.web.servlet.HandlerInterceptor |
文件上传 | org.springframework.web.multipart.MultipartResolver |
DispatcherServlet | org.springframework.web.servlet.DispatcherServlet |
HandlerExecutionChain | org.springframework.web.servlet.HandlerExecutionChain |