實作 MultiMethodControllerUrlHandlerMapping,自動掃描 Spring 容器中所有 MultiMethodController 型別的 Bean,讀取其 urlMethodMappings 屬性,建立「URL → Controller」對應表,免除手工在 SimpleUrlHandlerMapping 逐一配置。
public class MultiMethodControllerUrlHandlerMapping
extends AbstractUrlHandlerMapping {
private Map<String, Object> urlMap = new HashMap<>();
@Override
protected void initApplicationContext() throws BeansException {
initialUrlMap();
}
private void initialUrlMap() throws BeansException {
// 1. 取得容器中所有 MultiMethodController 及其子類 Bean
Map<String, MultiMethodController> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(
getWebApplicationContext(),
MultiMethodController.class, true, false);
if (!matchingBeans.isEmpty()) {
for (MultiMethodController controller : matchingBeans.values()) {
Properties urlProps = controller.getUrlMethodMappings();
for (String url : urlProps.stringPropertyNames()) {
urlMap.put(url, controller); // URL → Controller 實例
}
}
}
}
@Override
protected Object getHandlerInternal(HttpServletRequest request)
throws Exception {
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
Object handler = urlMap.get(lookupPath);
if (handler != null) {
return handler;
}
return super.getHandlerInternal(request); // fallback
}
}
AbstractUrlHandlerMapping:自動擁有 WebApplicationContext 存取能力。BeanFactoryUtils.beansOfTypeIncludingAncestors():遞迴搜尋父容器,確保跨模組 Controller 皆被掃描。MultiMethodController.getUrlMethodMappings():約定 Controller 需暴露此屬性(Properties 型別),Key 為 URL,Value 為方法名。getHandlerInternal():依請求路徑直接從 urlMap 查找 Controller,效能 O(1)。<bean class="com.yourpkg.MultiMethodControllerUrlHandlerMapping">
<property name="order" value="0"/> <!-- 優先順序最高 -->
</bean>
public class SampleMultiMethodController extends MultiActionController
implements MultiMethodController {
private Properties urlMethodMappings = new Properties();
// setter/getter 略
public ModelAndView listUser(HttpServletRequest req, HttpServletResponse res) { ... }
public ModelAndView editUser(HttpServletRequest req, HttpServletResponse res) { ... }
public ModelAndView saveUser(HttpServletRequest req, HttpServletResponse res, UserDTO cmd) { ... }
public ModelAndView deleteUser(HttpServletRequest req, HttpServletResponse res) { ... }
}
在 Bean 定義中設定 urlMethodMappings:
<bean id="sampleMultiMethodController"
class="com.prs.application.ehld.sample.web.controller.SampleMultiMethodController">
<property name="urlMethodMappings">
<props>
<prop key="/ehld.sample.getuserinfolist.do">listUser</prop>
<prop key="/ehld.sample.edituserinfo.do">editUser</prop>
<prop key="/ehld.sample.saveuserinfo.do">saveUser</prop>
<prop key="/ehld.sample.deleteuserinfo.do">deleteUser</prop>
</props>
</property>
<property name="sampleAction" ref="sampleAction"/>
</bean>
| 優點 | 缺點 |
|---|---|
| 零配置 URL Mapping,Controller 自描述 | 需自訂介面 MultiMethodController,侵入性稍高 |
| 新增方法只需在 Controller 內加映射,無須動 XML | URL 衝突檢測需自行實作(如兩 Controller 映射同一 URL) |
| 符合「高內聚」:相關操作集中在同一 Controller | Spring 3+ 建議改用 @Controller + @RequestMapping,此方案屬歷史遺產 |
透過自訂 UrlHandlerMapping 掃描 Controller 內部映射屬性,可大幅簡化 Spring MVC 早期版本的配置複雜度。現代專案請直接使用註解式開發,但此機制對理解 Spring MVC 請求分派原理極具參考價值。