在使用Spring提供的控制器時,AbstractController和SimpleFormController是應用 得最多的。AbstractController是最基本的Controller,可以給予用戶最大的靈活性。 SimpleFormController則用於典型的表單編輯和提交。在一個需要增,刪,改,查的需求中 ,增加和修改擴展SimpleFormController完成,刪除和查詢則擴展AbstractController完 成。
但是像上面那樣完成某一業務對象的增,刪,改,查,都屬於一類相關的業務。把一 類相關的操作分布到不同的類去完成,違返“高內聚”的設計原則。這樣四個業務操作需 要四個類來完成,造成太多的類文件,難以維護和配置。
所以Spring借鑒Struts的DispatchAction提供了類似功能的MultiActionController。 可以實現不同的請求路徑對應MultiActionController中的不同方法,這樣就可以把相關 的操作都在一個類的相關方法中完成。這樣使得這個類具有“高內聚”,也利於系統的維 護,還避免了重復代碼。增加和修改操作的數據驗證邏輯是很相似的,使用 MultiActionController後就可以讓增加和修改操作共用一段數據驗證邏輯代碼。
1.使用MultiActionController
MultiActionController會使不同的請求映射為不同方法,這裡是一個實現用戶信息增 刪改查的例子:
1.1 SampleMultiMethodController實現
public class SampleMultiMethodController extends MultiActionController...{
// 用戶信息列表view
private static final String userInfoListView = "ehld.sample.getuserinfolist";
//用戶信息編輯view
private static final String userFormView = "ehld.sample.userForm";
//提交成功後顯示的view
private static final String userSuccessView ="redirect:ehld.sample.getuserinfolist.do";
// 用戶信息列表key值
private static final String userInfoListKey = "userInfoList";
// userid
private final String userIdParam = "id";
// 定義業務對象
private SampleAction sampleAction;
public SampleAction getSampleAction() ...{
return sampleAction;
}
public void setSampleAction(SampleAction sampleAction) ...{
this.sampleAction = sampleAction;
}
/**//**
* 功能:獲得所有的用戶信息<br>
*/
public ModelAndView listUser(HttpServletRequest request,
HttpServletResponse response) throws Exception ...{
List userInfoList = this.sampleAction.getUserInfoList();
ModelAndView mav = new ModelAndView(userInfoListView);
mav.addObject(this.userInfoListKey,userInfoList);
return mav;
}
/**//**
* 功能:編輯用戶信息<br>
*/
public ModelAndView edtiUser(HttpServletRequest request,
HttpServletResponse response) throws Exception ...{
String uid = RequestUtils.getStringParameter(request, userIdParam);
UserInfoDTO userInfo = null;
if (!"".equals(uid)) ...{
userInfo = this.sampleAction.getUserInfo(uid);
}
if (userInfo == null) ...{
userInfo = new UserInfoDTO();
}
ModelAndView mav = new ModelAndView(this.userFormView, this
.getCommandName(null), userInfo);
return mav;
}
/**//**
* 功能:保存修改或新增的用戶信息<br>
*檢查從頁面bind的對象,如果userId或userName為空則返回原來的form頁面;否則 進行保存用戶信息操作,返回
*成功頁面
*/
public ModelAndView saveUser(HttpServletRequest request,
HttpServletResponse response, UserInfoDTO command) throws Exception ...{
UserInfoDTO user = (UserInfoDTO) command;
ServletRequestDataBinder binder = new ServletRequestDataBinder (command,
getCommandName(command));
BindException errors = binder.getErrors();
ModelAndView mav = null;
if (user.getUserID() == null || "".equals(user.getUserID())) ...{
errors.rejectValue("userID", "userIdNull", "用戶id不能為空");
}
if (user.getUserName() == null || "".equals(user.getUserName())) ... {
errors.reject("userNameNull", "用戶名不能為空");
}
if (errors.hasErrors()) ...{
mav = new ModelAndView(this.userFormView, errors.getModel());
} else ...{
this.sampleAction.saveUserInfo(user);// 保存用戶信息
mav = new ModelAndView(this.userSuccessView);
}
return mav;
}
/**//**
* 功能:刪除用戶信息<br>
*/
public ModelAndView deleteUser(HttpServletRequest request,
HttpServletResponse response) throws Exception ...{
String uid = RequestUtils.getStringParameter(request, userIdParam);
UserInfoDTO user = new UserInfoDTO();
user.setUserID(uid);
this.sampleAction.deleteUserInfo(user);
ModelAndView mav = new ModelAndView(this.userSuccessView);
return mav;
}
}
1.2 web-context配置
<!-- 把sampleMultiMethodController所有的請求映射到 SimpleUrlHandlerMapping -->
<bean id="handlerMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="defaultHandler" ref=" sampleMultiMethodController "/>
</bean>
<!-- 集增,刪,改,查操作到一個類的controller -->
<bean id="sampleMultiMethodController"
class="com.prs.application.ehld.sample.web.controller.SampleMultiMethodControl ler">
<property name="methodNameResolver">
<bean
class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameRes olver">
<property name="mappings">
<props>
<prop key="/ehld.sample.getuserinfolist.do">listUser</prop>
<prop key="/ehld.sample.edituserinfo.do">edtiUser</prop>
<prop key="/ehld.sample.saveuserinfo.do">saveUser</prop>
</props>
</property>
</bean>
</property>
<property name="sampleAction"
ref="com.prs.application.ehld.sample.biz.action.sampleAction"></property >
</bean>
2.MultiActionController的缺點
MultiActionController把相關的業務方法集中在一個類中進行處理,減少控制類的數 量。方便於系統的維護,可以重用相關的邏輯代碼,提高代碼的重用,同時也減少bean的 配置。有太多的bean配置可以說是Spring 的一個暇疵。Spring提供IOC,讓我們靈活的控 制bean的依賴。同時我們需要去維護太多的bean配置,Spring項目中很大程度上都在爛用 xml 配置文件,這很不利於團隊開發和系統的後期維護。MultiActionController也不例 外。
1.multiActionController的配置相對復雜。MultiActionController需要注入一個 MethodNameResolver對象,再通過MethodNameResolver的mappings屬性來提供請求與方法 之間的映射。這樣的配置是復雜的和難以理解的。使用Spring框架的確很靈活,但是有時 這種過分的靈活反而增加了系統的復雜度。
2.multiActionController配置涉及的bean過多。除了自身的bean定義外,還需要把所 有的映射配置到一個UrlHandlerMapping中去。這樣除了維護multiActionController的自 身的bean定義外,還需要維護UrlHandlerMapping的定義。
筆者十分反對這種具有連帶性的配置,一個bean的屬性改變會造成對別一個bean屬性 的改變。這樣增加了系統的復雜度,和維護成本。所以必須提供一種默認的實現,讓bean 之間的依賴,不要造成bean屬性之間的依賴。MultiActionController在這方面表示得十 分不好。
3.數據綁定支持不好。SimpleFormController專門用來支持編輯和表單提效的,它支 持數據綁定,在這方面做得很好。可以把jsp頁面的字段值綁定為某一對象(Command)。可 以自定義command的名稱。雖然MultiActionController也支持數據綁定,但是它並不支持 自定義command的名稱。它默認的comamnd名稱為”command”。這也是不便於維護的,對 象應該有一個代表自身含義的名字。如果所有頁面的綁定對象都以”command”作為名字 ,那將難以理解。MultiActionController支持數據綁定的方法參見上面例子的saveUser 方法。
3.理想的MultiActionController構想
一個理想的MultActionController應該配置簡單明了,並且無需要在多個地方進行配 置。應該支持對綁定對象自定義名稱。
<bean name="sampleMultiMethodController"
class="com.prs.application.ehld.sample.web.controller.SampleMultiMethodControl ler">
<property name="commandName" value="userInfoDTO"/>
<property name="formView" value="ehld.sample.userForm"/>
<property name="successView" value="redirect:ehld.sample.getuserinfolist.do"/>
<property name="urlMethodmappings">
<props>
<!--顯示用戶信息列表 -->
<prop key="/ehld.sample.getuserinfolist.do">listUser</prop>
<!-- 編輯用戶信息 -->
<prop key="/ehld.sample.edituserinfo.do">edtiUser</prop>
<!-- 保存用戶信息-->
<prop key="/ehld.sample.saveuserinfo.do">saveUser</prop>
</props>
</property>
<property name="sampleAction"
ref="com.prs.application.ehld.sample.biz.action.sampleAction"></property >
</bean>
上面是一個更讓人能夠理解的配置。
1.把請求與具體方法之間的映射作為MultiActionController自身的一個屬性 “urlMethodmappings”。
2.通過一個commandName屬性,可以讓用戶自由決定綁定對象的名稱。
3.簡化UrlHandlerMapping的關聯配置。對MutilActionController的bean配置進行改 動時,無再需要去關心 SimpleUrlHandlerMapping的bean配置