在 SpringMVC 的 web.xml 配置中,<servlet-class> 和 <url-pattern> 是两个关键配置项,分别用于指定处理请求的 Servlet 类和定义该 Servlet 拦截的请求路径规则。以下是它们的具体作用及原理分析:
一、<servlet-class> 的作用
1. 指定核心前端控制器
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
- 核心作用:明确声明当前 Servlet 的实现类为 SpringMVC 的前端控制器
DispatcherServlet
。
DispatcherServlet
是 SpringMVC 的入口,负责协调处理所有 Web 请求,包括请求分发、视图解析、异常处理等核心流程。 - 本质:
DispatcherServlet
是HttpServlet
的子类,遵循 Servlet 规范,通过重写doGet
/doPost
等方法实现对 SpringMVC 流程的控制。
2. 集成 SpringMVC 生态
- 该类会自动加载 SpringMVC 的配置(如
springmvc-servlet.xml
),初始化处理器映射(HandlerMapping
)、处理器适配器(HandlerAdapter
)、视图解析器(ViewResolver
)等组件,形成完整的请求处理链条。
二、<url-pattern>
的作用
1. 定义请求拦截规则
<url-pattern>/</url-pattern>
- 核心作用:指定哪些请求会被
DispatcherServlet
处理。
常见取值有/*
、/
、*.do
等,不同取值影响请求的拦截范围。
2. 不同取值的区别
取值 | 拦截范围 | 适用场景 |
---|---|---|
/* | 拦截 所有请求(包括静态资源 .html /.js /.css 、JSP 页面请求等)。 | 不推荐:会导致 JSP 页面无法正常访问(因 JSP 本质是 Servlet,需由 Tomcat 内置 Servlet 处理)。 |
/ | 拦截 除 .jsp 以外的所有请求(静态资源、RESTful 接口等)。 | 推荐配置:JSP 页面由 Tomcat 默认 Servlet 处理,避免与 DispatcherServlet 冲突。 |
*.do | 拦截 以 .do 结尾的请求(如 /user.do )。 | 传统 MVC 风格,通过后缀区分动态请求,目前逐渐被 RESTful 无后缀风格取代。 |
3. 为什么推荐使用 <url-pattern>/</url-pattern>
?
- 避免 JSP 拦截问题:
当请求为 JSP 页面(如/index.jsp
)时,Tomcat 会使用内置的JspServlet
处理。若使用/*
,DispatcherServlet
会优先拦截 JSP 请求,导致 404 错误。
使用/
时,DispatcherServlet
仅拦截 非 JSP 请求(JSP 的扩展名.jsp
会被 Tomcat 直接处理),确保静态页面和动态接口的正常分发。 - 支持 RESTful 风格:
无后缀的 URL(如/user/1
)更简洁,符合现代 Web 开发规范,且无需额外配置后缀映射。
三、请求处理流程与配置的关系
- 请求到达 Tomcat:
浏览器发送请求(如/user/list
或/index.jsp
)。 - Tomcat 匹配 Servlet:
- 若请求是 JSP(
.jsp
结尾):由 Tomcat 内置的JspServlet
处理,直接返回页面。 - 若请求是其他路径(如
/user/list
):根据<url-pattern>/</url-pattern>
,由DispatcherServlet
接管。
- 若请求是 JSP(
- DispatcherServlet 处理流程:
- 通过处理器映射(
HandlerMapping
)找到对应的控制器(@Controller
方法)。 - 调用控制器处理请求,返回模型数据和视图名。
- 视图解析器(
ViewResolver
)解析视图,生成最终响应(如 HTML 页面或 JSON 数据)。
- 通过处理器映射(
四、最佳实践
配置 <url-pattern>/</url-pattern>
:
这是 SpringMVC 推荐的现代配置方式,兼容 RESTful 接口和静态资源,同时避免与 JSP 冲突(若项目使用 JSP 作为视图)。
静态资源处理:
若项目包含静态资源(如 CSS/JS/ 图片),需在 SpringMVC 配置中额外声明静态资源映射,避免被 DispatcherServlet
拦截:
// WebMvcConfigurer 配置
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
}
无 JSP 项目(如前后端分离):
若项目完全使用 JSON 响应(无 JSP 视图),可安全使用 /*
,但需确保静态资源路径正确映射。
总结
<servlet-class>
:指定 SpringMVC 的核心前端控制器DispatcherServlet
,启动请求处理的整个流程。<url-pattern>/</url-pattern>
:精准拦截非 JSP 请求,确保动态接口由 SpringMVC 处理,静态资源和 JSP 由 Tomcat 内置机制处理,是现代 Web 开发的最佳实践配置。
通过合理配置这两个项,可实现请求的高效分发,避免资源访问冲突,提升项目的可维护性。
请求处理流程更加详细点
以下是 SpringMVC 请求处理流程 的详细解析,从客户端发送请求到服务器返回响应的完整链路,结合核心组件的协作机制展开说明:
一、请求处理的核心流程(12 个关键步骤)
1. 浏览器发送请求到 Tomcat
- 用户在浏览器输入 URL(如
http://localhost:8080/app/user/list
),请求通过网络到达 Tomcat 服务器。 - Tomcat 根据
web.xml
中的<url-pattern>
匹配处理该请求的 Servlet:- 若请求是 JSP 页面(如
.jsp
结尾):由 Tomcat 内置的JspServlet
处理(直接跳过 SpringMVC)。 - 若请求是 非 JSP 请求(如
/user/list
):根据配置url-pattern>/</url-pattern>
,由DispatcherServlet
接管。
- 若请求是 JSP 页面(如
2. DispatcherServlet 接收请求并初始化上下文
DispatcherServlet
作为前端控制器,是请求处理的入口,负责协调所有后续组件。- 它会加载 SpringMVC 配置文件(如
springmvc-servlet.xml
或通过 Java 配置类),初始化以下核心组件(在第一次请求时完成初始化):- 处理器映射器(HandlerMapping):将请求 URL 映射到具体的控制器(
@Controller
方法)。 - 处理器适配器(HandlerAdapter):适配不同类型的控制器(如
@RequestMapping
方法、HttpRequestHandler
等)。 - 视图解析器(ViewResolver):将逻辑视图名解析为具体的视图对象(如 JSP、Thymeleaf 模板、JSON 视图等)。
- 其他组件:如异常处理器(
HandlerExceptionResolver
)、文件上传解析器(MultipartResolver
)等。
- 处理器映射器(HandlerMapping):将请求 URL 映射到具体的控制器(
3. 处理器映射器(HandlerMapping)查找 Handler
- 目标:根据请求 URL 找到对应的 处理器(Handler),即处理该请求的控制器方法。
- 工作机制:
- 遍历所有已注册的
HandlerMapping
(如RequestMappingHandlerMapping
),尝试匹配请求 URL。 - 例如,对于 URL
/user/list
,若存在@RequestMapping("/user/list")
注解的方法,则返回一个HandlerExecutionChain
对象,包含:- Handler:具体的控制器方法(如
UserController.list()
)。 - 拦截器链(Interceptor List):请求处理前后执行的拦截器(如
HandlerInterceptor
的preHandle
/postHandle
方法)。
- Handler:具体的控制器方法(如
- 遍历所有已注册的
- 输出:返回
HandlerExecutionChain
,若未找到匹配的 Handler,则抛出404 Not Found
异常。
4. 处理器适配器(HandlerAdapter)调用 Handler
- 目标:适配不同类型的 Handler,确保统一调用方式。
- 工作机制:
DispatcherServlet
根据 Handler 的类型选择对应的HandlerAdapter
(如RequestMappingHandlerAdapter
处理@Controller
方法)。- 调用
HandlerAdapter.handle()
方法,执行以下操作:- 预处理:解析请求参数(如
@RequestParam
、@RequestBody
),绑定到控制器方法的参数列表。 - 调用控制器:执行具体的控制器方法,返回
ModelAndView
(或void
、String
、ResponseEntity
等类型,由适配器转换为ModelAndView
)。
ModelAndView
包含:- Model:视图渲染所需的数据(如
Map<String, Object>
)。 - ViewName:逻辑视图名(如
user/list
)或直接是View
对象(如InternalResourceView
对应 JSP)。
- Model:视图渲染所需的数据(如
- 预处理:解析请求参数(如
5. 拦截器前置处理(preHandle)
- 在调用控制器方法 之前,拦截器链中的所有拦截器依次执行
preHandle()
方法:- 可用于权限校验、日志记录、请求参数修改等。
- 若某拦截器返回
false
,则中断后续流程,直接执行afterCompletion()
(不会调用控制器和后续拦截器)。
6. 执行控制器(@Controller 方法)
- 控制器方法被调用,处理业务逻辑:
- 接收请求参数(通过
@RequestParam
、@PathVariable
等注解)。 - 调用服务层、持久层获取数据。
- 返回结果:
- 若返回
String
:表示逻辑视图名(如success
),结合视图解析器生成最终视图。 - 若返回
ModelAndView
:直接包含视图名和模型数据。 - 若返回
void
:需通过HttpServletResponse
直接输出响应(如 RESTful 接口返回 JSON 时,需配合@ResponseBody
注解)。
- 若返回
- 接收请求参数(通过
7. 拦截器后置处理(postHandle)
- 在控制器方法 执行之后、视图渲染之前,拦截器链逆序执行
postHandle()
方法:- 可用于修改模型数据(
ModelAndView
中的Model
)、补充响应头信息等。
- 可用于修改模型数据(
8. 视图解析器(ViewResolver)解析视图
- 目标:将逻辑视图名(如
user/list
)转换为具体的View
对象。 - 工作机制:
- 遍历所有已注册的
ViewResolver
(如InternalResourceViewResolver
处理 JSP)。 - 例如,配置
prefix="/WEB-INF/views/"
和suffix=".jsp"
,则视图名user/list
会被解析为:java
View = new InternalResourceView("/WEB-INF/views/user/list.jsp");
- 遍历所有已注册的
- 支持的视图类型:JSP、Thymeleaf、Freemarker、JSON(如
MappingJackson2JsonView
)、XML 等。
9. 视图渲染(View.render ())
- 目标:将模型数据填充到视图中,生成最终的响应内容(如 HTML、JSON、XML 等)。
- 工作机制:
View
对象调用render(Model, request, response)
方法:- 对于 JSP 视图:将
Model
数据放入request
或session
作用域,转发到 JSP 页面,JSP 通过 EL 表达式或标签库获取数据并渲染。 - 对于 JSON 视图(配合
@ResponseBody
):直接将模型数据序列化为 JSON 格式,写入HttpServletResponse
的输出流。
- 对于 JSP 视图:将
- 注意:若控制器方法返回
@ResponseBody
或ResponseEntity
,则跳过视图解析器,直接由HttpMessageConverter
(如MappingJackson2HttpMessageConverter
)处理响应数据。
10. 拦截器完成处理(afterCompletion)
- 在视图渲染 完成后,拦截器链逆序执行
afterCompletion()
方法:- 用于资源清理(如关闭数据库连接、记录耗时日志等),无论请求是否成功都会执行。
11. DispatcherServlet 返回响应
- 生成的响应内容(如 HTML 页面、JSON 数据)通过
HttpServletResponse
发送回浏览器。
12. 浏览器解析响应并展示
- 浏览器接收响应,解析 HTML/JSON 等内容,渲染页面或处理数据(如 AJAX 请求的回调函数)。
二、核心组件的协作关系图
浏览器请求 → Tomcat → DispatcherServlet↓[1] 处理器映射器(HandlerMapping) ↓ (返回 HandlerExecutionChain:Handler + 拦截器链)[2] 处理器适配器(HandlerAdapter) ↓ (调用 Controller 方法,返回 ModelAndView)[3] 视图解析器(ViewResolver) ↓ (解析为 View 对象)[4] 视图渲染(View.render()) ↓响应返回浏览器
三、关键组件的作用与扩展点
1. 处理器映射器(HandlerMapping)
- 默认实现:
RequestMappingHandlerMapping
:处理@RequestMapping
注解的控制器。BeanNameUrlHandlerMapping
:按 Bean 名称映射 URL(较少使用)。
- 扩展:自定义
HandlerMapping
,实现特殊的 URL 匹配逻辑(如基于数据库的动态路由)。
2. 处理器适配器(HandlerAdapter)
- 默认实现:
RequestMappingHandlerAdapter
:支持@Controller
注解的方法(最常用)。SimpleControllerHandlerAdapter
:支持实现Controller
接口的控制器(传统方式)。
- 扩展:自定义
HandlerAdapter
,支持非标准的控制器类型(如自定义函数式处理器)。
3. 视图解析器(ViewResolver)
- 默认实现:
InternalResourceViewResolver
:解析 JSP 视图(转发到WEB-INF
目录下的页面)。ThymeleafViewResolver
:解析 Thymeleaf 模板(需集成 Thymeleaf 依赖)。
- 扩展:自定义
ViewResolver
,支持自定义视图类型(如 Markdown 视图、Excel 导出视图)。
4. 拦截器(Interceptor)
- 作用:在请求处理的 前、中、后 阶段插入自定义逻辑,实现:
- 登录校验(
preHandle
)。 - 性能监控(记录方法执行时间)。
- 响应数据包装(统一添加响应头)。
- 登录校验(
- 实现:自定义类实现
HandlerInterceptor
接口,重写preHandle
/postHandle
/afterCompletion
方法,并通过WebMvcConfigurer.addInterceptors()
注册。
四、典型场景处理细节
1. RESTful 接口返回 JSON(无视图渲染)
- 控制器方法添加
@ResponseBody
注解(或使用@RestController
组合注解):java
@GetMapping("/api/user/{id}") @ResponseBody public User getUser(@PathVariable Long id) {return userService.getUser(id); // 直接返回 Java 对象 }
- 流程变化:
- 跳过视图解析器和视图渲染阶段。
- 由
HttpMessageConverter
(如MappingJackson2HttpMessageConverter
)将 Java 对象序列化为 JSON,写入响应体。
2. 文件上传处理
- 配置
MultipartResolver
(如CommonsMultipartResolver
):xml
<!-- web.xml 或 Java 配置 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"><property name="maxUploadSize" value="10485760" /> <!-- 10MB --> </bean>
- 控制器方法接收
MultipartFile
参数:java
@PostMapping("/upload") public String upload(@RequestParam("file") MultipartFile file) {// 处理文件上传逻辑return "uploadSuccess"; }
- 流程变化:在
DispatcherServlet
处理请求前,MultipartResolver
会将HttpServletRequest
包装为MultipartHttpServletRequest
,解析文件数据。
3. 异常处理
- 配置
HandlerExceptionResolver
(如SimpleMappingExceptionResolver
或@ControllerAdvice
):- 全局捕获控制器抛出的异常,返回自定义错误页面或 JSON 响应。
- 流程变化:若控制器方法抛出异常,会跳过视图渲染,直接由异常处理器处理,返回对应的错误视图或响应。
五、总结:SpringMVC 设计的核心思想
- 模块化设计:通过
DispatcherServlet
统一调度,各组件(映射器、适配器、解析器)分工明确,可独立扩展。 - 约定大于配置:默认组件支持大多数场景,仅需少量配置即可快速启动(如自动装配
RequestMappingHandlerMapping
)。 - 兼容性:支持多种控制器风格(注解式、接口式)和视图技术(JSP、模板引擎、REST 响应),适配不同项目需求。
理解这一流程后,开发者可更高效地调试问题(如 404 错误可能是 Handler 未匹配,500 错误可能是视图解析失败),并利用扩展点实现个性化需求(如自定义拦截器、视图解析器)。