1. 简介
在 Spring MVC 中,DispatcherServlet
充当前端控制器角色——接收所有 HTTP 请求并进行处理。
简单来说,处理过程是通过处理器映射(Handler Mappings) 将请求转发给相应的组件来完成的。
HandlerMapping
是一个接口,用于定义请求与处理器对象之间的映射关系。虽然 Spring MVC 框架提供了一些现成的实现,但开发者也可以实现该接口来提供自定义的映射策略。
本文将讨论 Spring MVC 提供的几种实现:BeanNameUrlHandlerMapping
、SimpleUrlHandlerMapping
、ControllerClassNameHandlerMapping
(Spring 5 已移除),包括它们的配置方式以及之间的差异。
2. BeanNameUrlHandlerMapping
BeanNameUrlHandlerMapping
是默认的 HandlerMapping
实现。它将请求 URL 映射到同名的 Bean。
这种映射支持直接名称匹配,也支持使用 *
模式的通配符匹配。例如:
- 直接匹配:URL
/foo
映射到名为/foo
的 Bean - 通配符匹配:URL
/foo*
映射到以/foo
开头的 Bean(如/foo2/
或/fooOne/
)
下面配置一个处理 /beanNameUrl
请求的控制器:
@Configuration
public class BeanNameUrlHandlerMappingConfig {
@Bean
BeanNameUrlHandlerMapping beanNameUrlHandlerMapping() {
return new BeanNameUrlHandlerMapping();
}
@Bean("/beanNameUrl")
public WelcomeController welcome() {
return new WelcomeController();
}
}
对应的 XML 配置:
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
<bean name="/beanNameUrl" class="com.baeldung.WelcomeController" />
⚠️ 注意:两种配置中显式定义 BeanNameUrlHandlerMapping
Bean 并非必需,因为 Spring MVC 默认已提供。移除该定义不会影响功能,请求仍会映射到注册的处理器 Bean。
现在所有 /beanNameUrl
请求将由 DispatcherServlet
转发给 WelcomeController
,后者返回名为 welcome
的视图。
测试代码验证配置:
public class BeanNameMappingConfigTest {
// ...
@Test
public void whenBeanNameMapping_thenMappedOK() {
mockMvc.perform(get("/beanNameUrl"))
.andExpect(status().isOk())
.andExpect(view().name("welcome"));
}
}
3. SimpleUrlHandlerMapping
SimpleUrlHandlerMapping
是最灵活的 HandlerMapping
实现。它允许直接声明式地映射:
- Bean 实例与 URL
- Bean 名称与 URL
将 /simpleUrlWelcome
和 /*/simpleUrlWelcome
映射到 welcome
Bean:
@Configuration
public class SimpleUrlHandlerMappingConfig {
@Bean
public SimpleUrlHandlerMapping simpleUrlHandlerMapping() {
SimpleUrlHandlerMapping simpleUrlHandlerMapping
= new SimpleUrlHandlerMapping();
Map<String, Object> urlMap = new HashMap<>();
urlMap.put("/simpleUrlWelcome", welcome());
simpleUrlHandlerMapping.setUrlMap(urlMap);
return simpleUrlHandlerMapping;
}
@Bean
public WelcomeController welcome() {
return new WelcomeController();
}
}
对应的 XML 配置:
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<value>
/simpleUrlWelcome=welcome
/*/simpleUrlWelcome=welcome
</value>
</property>
</bean>
<bean id="welcome" class="com.baeldung.WelcomeController" />
⚠️ 注意:XML 配置中,<value>
标签内的映射需遵循 java.util.Properties
语法:path=Handler_Bean_Name
。URL 通常以 /
开头,若未提供 Spring 会自动添加。
另一种 XML 配置方式(使用 props
):
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/simpleUrlWelcome">welcome</prop>
<prop key="/*/simpleUrlWelcome">welcome</prop>
</props>
</property>
</bean>
测试代码验证 /*simpleUrlWelcome
请求:
public class SimpleUrlMappingConfigTest {
// ...
@Test
public void whenSimpleUrlMapping_thenMappedOK() {
mockMvc.perform(get("/simpleUrlWelcome"))
.andExpect(status().isOk())
.andExpect(view().name("welcome"));
}
}
4. ControllerClassNameHandlerMapping(Spring 5 已移除)
ControllerClassNameHandlerMapping
将 URL 映射到注册的控制器 Bean(或 @Controller
注解的类),要求控制器名称与 URL 相同或以 URL 开头。
在简单场景下特别方便,尤其是处理单一请求类型的控制器。Spring MVC 的约定是:
- 移除类名中的
Controller
后缀 - 转换为小写
- 添加前导
/
作为映射
例如 WelcomeController
会映射到 /welcome*
,即所有以 welcome
开头的 URL。
配置示例:
@Configuration
public class ControllerClassNameHandlerMappingConfig {
@Bean
public ControllerClassNameHandlerMapping controllerClassNameHandlerMapping() {
return new ControllerClassNameHandlerMapping();
}
@Bean
public WelcomeController welcome() {
return new WelcomeController();
}
}
⚠️ 注意:
- 该类在 Spring 4.3 已废弃,推荐使用注解驱动的处理器方法
- 控制器名称始终返回小写(移除
Controller
后缀)。例如WelcomeBaeldungController
只能处理/welcomebaeldung
而非/welcomeBaeldung
对应的 XML 配置:
<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" />
<bean class="com.baeldung.WelcomeController" />
测试代码验证 /welcome*
请求(如 /welcometest
):
public class ControllerClassNameHandlerMappingTest {
// ...
@Test
public void whenControllerClassNameMapping_thenMappedOK() {
mockMvc.perform(get("/welcometest"))
.andExpect(status().isOk())
.andExpect(view().name("welcome"));
}
}
5. 配置优先级
Spring MVC 允许同时存在多个 HandlerMapping
实现。当多个映射匹配同一 URL 时,需通过优先级确定使用哪个。
配置示例
注册两个控制器,都映射到 /welcome
但返回不同视图:
@Configuration
public class HandlerMappingDefaultConfig {
@Bean("/welcome")
public BeanNameHandlerMappingController beanNameHandlerMapping() {
return new BeanNameHandlerMappingController();
}
@Bean
public WelcomeController welcome() {
return new WelcomeController();
}
}
未显式配置映射器时,默认使用 BeanNameHandlerMapping
。测试验证:
@Test
public void whenConfiguringPriorities_thenMappedOK() {
mockMvc.perform(get("/welcome"))
.andExpect(status().isOk())
.andExpect(view().name("bean-name-handler-mapping"));
}
显式注册多个映射器
@Configuration
public class HandlerMappingPrioritiesConfig {
@Bean
BeanNameUrlHandlerMapping beanNameUrlHandlerMapping() {
BeanNameUrlHandlerMapping beanNameUrlHandlerMapping
= new BeanNameUrlHandlerMapping();
return beanNameUrlHandlerMapping;
}
@Bean
public SimpleUrlHandlerMapping simpleUrlHandlerMapping() {
SimpleUrlHandlerMapping simpleUrlHandlerMapping
= new SimpleUrlHandlerMapping();
Map<String, Object> urlMap = new HashMap<>();
urlMap.put("/welcome", simpleUrlMapping());
simpleUrlHandlerMapping.setUrlMap(urlMap);
return simpleUrlHandlerMapping;
}
@Bean
public SimpleUrlMappingController simpleUrlMapping() {
return new SimpleUrlMappingController();
}
@Bean("/welcome")
public BeanNameHandlerMappingController beanNameHandlerMapping() {
return new BeanNameHandlerMappingController();
}
}
设置优先级
通过 setOrder(int order)
方法控制优先级(数值越小优先级越高):
// Java 配置
beanNameUrlHandlerMapping.setOrder(1);
simpleUrlHandlerMapping.setOrder(0);
XML 配置方式:
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
<property name="order" value="2" />
</bean>
测试验证优先级(order=0
的 SimpleUrlHandlerMapping
优先):
@Test
public void whenConfiguringPriorities_thenMappedOK() {
mockMvc.perform(get("/welcome"))
.andExpect(status().isOk())
.andExpect(view().name("simple-url-handler-mapping"));
}
✅ 关键点:调整 order
值可轻松切换优先级映射器。
6. 总结
本文探讨了 Spring MVC 框架中 URL 映射的处理机制,重点分析了框架提供的几种 HandlerMapping
实现:
BeanNameUrlHandlerMapping
- 默认实现,通过 Bean 名称直接映射 URL
- 支持通配符匹配(如
/foo*
)
SimpleUrlHandlerMapping
- 最灵活的实现
- 支持声明式映射(Bean 实例/名称与 URL)
ControllerClassNameHandlerMapping
- 基于控制器类名生成映射(Spring 5 已移除)
- 约定优于配置的典型应用
优先级配置
- 多映射器共存时通过
order
属性控制优先级 - 数值越小优先级越高
- 多映射器共存时通过
合理选择映射器能显著提升 Spring MVC 应用的灵活性与可维护性。实际开发中,推荐优先使用注解驱动的 @RequestMapping
(现代 Spring 应用的主流方案),但在特定场景下(如遗留系统迁移),这些传统映射器仍有实用价值。