早期 Spring MVC 開發中,單一功能(增刪改查)常拆分為多個 Controller(AbstractController、SimpleFormController),導致類別爆炸、驗證邏輯重複、配置繁瑣。MultiActionController 參考 Struts DispatchAction 設計,允許一個 Controller 類別包含多個處理方法,透過 MethodNameResolver 將 URL 映射至方法。
public class SampleMultiMethodController extends MultiActionController {
private SampleAction sampleAction; // 業務 Service
public ModelAndView listUser(HttpServletRequest req, HttpServletResponse res) {
List<UserInfoDTO> list = sampleAction.getUserInfoList();
return new ModelAndView("userListView", "userInfoList", list);
}
public ModelAndView editUser(HttpServletRequest req, HttpServletResponse res) {
String uid = RequestUtils.getStringParameter(req, "id");
UserInfoDTO dto = (uid != null && !uid.isEmpty())
? sampleAction.getUserInfo(uid) : new UserInfoDTO();
return new ModelAndView("userFormView", getCommandName(null), dto);
}
public ModelAndView saveUser(HttpServletRequest req, HttpServletResponse res,
UserInfoDTO command) {
ServletRequestDataBinder binder = new ServletRequestDataBinder(command);
BindException errors = binder.getErrors();
// 驗證邏輯...
if (errors.hasErrors()) {
return new ModelAndView("userFormView", errors.getModel());
}
sampleAction.saveUserInfo(command);
return new ModelAndView("redirect:listUser.do");
}
public ModelAndView deleteUser(HttpServletRequest req, HttpServletResponse res) {
sampleAction.deleteUserInfo(RequestUtils.getStringParameter(req, "id"));
return new ModelAndView("redirect:listUser.do");
}
// getter/setter 略
}
<bean id="handlerMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="defaultHandler" ref="sampleMultiMethodController"/>
</bean>
<bean id="sampleMultiMethodController"
class="com.prs...SampleMultiMethodController">
<property name="methodNameResolver">
<bean class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver">
<property name="mappings">
<props>
<prop key="/listUser.do">listUser</prop>
<prop key="/editUser.do">editUser</prop>
<prop key="/saveUser.do">saveUser</prop>
</props>
</property>
</bean>
</property>
<property name="sampleAction" ref="sampleAction"/>
</bean>
MethodNameResolver,再定義 mappings 屬性,兩層嵌套。SimpleUrlHandlerMapping,違反單一職責。command,無法自訂語意化名稱(如 userInfoDTO)。期望配置簡化為:
<bean name="sampleMultiMethodController"
class="com.prs...SampleMultiMethodController">
<property name="commandName" value="userInfoDTO"/>
<property name="formView" value="userFormView"/>
<property name="successView" value="redirect:listUser.do"/>
<property name="urlMethodMappings">
<props>
<prop key="/listUser.do">listUser</prop>
<prop key="/editUser.do">editUser</prop>
<prop key="/saveUser.do">saveUser</prop>
<prop key="/deleteUser.do">deleteUser</prop>
</props>
</property>
<property name="sampleAction" ref="sampleAction"/>
</bean>
改良重點:
1. 將 URL→方法映射內移為 Controller 屬性 urlMethodMappings。
2. 新增 commandName、formView、successView 等屬性,支援彈性綁定與視圖。
3. 移除外部 MethodNameResolver 與 SimpleUrlHandlerMapping 耦合。
MultiMethodController 介面,定義上述屬性契約。MultiMethodControllerUrlHandlerMapping 掃描容器中所有實作該介面的 Bean,自動建立 URL 映射表。handleRequestInternal() 依映射分派方法、處理資料綁定與驗證。MultiActionController 雖解決類別爆炸,但配置複雜度轉移至 XML。將映射資訊內聚至 Controller 本身,並透過自訂 HandlerMapping 自動掃描,才是符合「慣例優於配置」的正確演進路徑。