`
fudehai001
  • 浏览: 499020 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

增强MultiActionController

阅读更多
在使用Spring提供的控制器时,AbstractController和SimpleFormController是应用得最多的。 AbstractController是最基本的Controller,可以给予用户最大的灵活性。SimpleFormController则用于典型的表单编辑和提交。在一个需要增,删,改,查的需求中,增加和修改扩展SimpleFormController完成,删除和查询则扩展 AbstractController完成。
但是像上面那样完成某一业务对象的增,删,改,查,都属于一类相关的业务。把一类相关的操作分布到不同的类去完成,违返“高内聚”的设计原则。这样四个业务操作需要四个类来完成,造成太多的类文件,难以维护和配置。
所以Spring借鉴Struts的DispatchAction提供了类似功能的MultiActionController。可以实现不同的请求路径对应MultiActionController中的不同方法,这样就可以把相关的操作都在一个类的相关方法中完成。这样使得这个类具有“高内聚 ”,也利于系统的维护,还避免了重复代码。增加和修改操作的数据验证逻辑是很相似的,使用MultiActionController后就可以让增加和修改操作共用一段数据验证逻辑代码。
1. 使用MultiActionController
MultiActionController会使不同的请求映射为不同方法,这里是一个实现用户信息增删改查的例子:

1.1 SampleMultiMethodController实现
Java代码 复制代码

   1. public class SampleMultiMethodController extends MultiActionController{ 
   2.   // 用户信息列表view 
   3.   private static final String userInfoListView = "ehld.sample.getuserinfolist"; 
   4.   //用户信息编辑view 
   5.   private static final String userFormView = "ehld.sample.userForm"; 
   6.   //提交成功后显示的view 
   7.   private static final String userSuccessView ="redirect:ehld.sample.getuserinfolist.do"; 
   8.   // 用户信息列表key值 
   9.   private static final String userInfoListKey = "userInfoList"; 
  10.   // userid 
  11.   private final String userIdParam = "id"; 
  12.   // 定义业务对象 
  13.   private SampleAction sampleAction; 
  14.   public SampleAction getSampleAction() { 
  15.         return sampleAction; 
  16.   } 
  17.   public void setSampleAction(SampleAction sampleAction) { 
  18.     this.sampleAction = sampleAction; 
  19.   } 
  20.  
  21.   /**
  22.    * 功能:获得所有的用户信息<br>
  23.   */ 
  24.   public ModelAndView listUser(HttpServletRequest request, 
  25.             HttpServletResponse response) throws Exception { 
  26.      List userInfoList = this.sampleAction.getUserInfoList(); 
  27.      ModelAndView mav = new ModelAndView(userInfoListView); 
  28.      mav.addObject(this.userInfoListKey,userInfoList); 
  29.      return mav; 
  30.   } 
  31.  
  32.   /**
  33.    * 功能:编辑用户信息<br>
  34.   */ 
  35.   public ModelAndView edtiUser(HttpServletRequest request, 
  36.             HttpServletResponse response) throws Exception {   
  37.      String uid = RequestUtils.getStringParameter(request, userIdParam); 
  38.      UserInfoDTO userInfo = null; 
  39.      if (!"".equals(uid)) { 
  40.     userInfo = this.sampleAction.getUserInfo(uid); 
  41.      } 
  42.      if (userInfo == null) { 
  43.     userInfo = new UserInfoDTO(); 
  44.      } 
  45.      ModelAndView mav = new ModelAndView(this.userFormView, this 
  46.                 .getCommandName(null), userInfo); 
  47.      return mav;   
  48.   } 
  49.   /**
  50.    * 功能:保存修改或新增的用户信息<br>
  51.    *检查从页面bind的对象,如果userId或userName为空则返回原来的form页面;否则进行保存用户信息操作,返回  
  52.  *成功页面
  53.   */ 
  54. public ModelAndView saveUser(HttpServletRequest request, 
  55.             HttpServletResponse response, UserInfoDTO command) throws Exception { 
  56.     UserInfoDTO user = (UserInfoDTO) command; 
  57.     ServletRequestDataBinder binder = new ServletRequestDataBinder(command, 
  58.                 getCommandName(command)); 
  59.     BindException errors = binder.getErrors(); 
  60.     ModelAndView mav = null; 
  61.     if (user.getUserID() == null || "".equals(user.getUserID())) { 
  62.         errors.rejectValue("userID", "userIdNull", "用户id不能为空"); 
  63.     } 
  64.  
  65.     if (user.getUserName() == null || "".equals(user.getUserName())) { 
  66.         errors.reject("userNameNull", "用户名不能为空"); 
  67.     } 
  68.     if (errors.hasErrors()) { 
  69.        mav = new ModelAndView(this.userFormView, errors.getModel()); 
  70.     } else { 
  71.  
  72.        this.sampleAction.saveUserInfo(user);// 保存用户信息 
  73.        mav = new ModelAndView(this.userSuccessView); 
  74.     } 
  75.         return mav; 
  76. } 
  77.   /**
  78.    * 功能:删除用户信息<br>
  79.   */ 
  80. public ModelAndView deleteUser(HttpServletRequest request, 
  81.             HttpServletResponse response) throws Exception { 
  82.       String uid = RequestUtils.getStringParameter(request, userIdParam); 
  83.       UserInfoDTO user = new UserInfoDTO(); 
  84.       user.setUserID(uid); 
  85.       this.sampleAction.deleteUserInfo(user); 
  86.       ModelAndView mav = new ModelAndView(this.userSuccessView); 
  87.       return mav; 
  88. } 
  89. } 

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配置
Java代码 复制代码

   1.     <!-- 把sampleMultiMethodController所有的请求映射到SimpleUrlHandlerMapping --> 
   2.     <bean id="handlerMapping"  
   3. class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> 
   4.         <property name="defaultHandler" ref=" sampleMultiMethodController "/> 
   5.     </bean> 
   6.  
   7.     <!-- 集增,删,改,查操作到一个类的controller --> 
   8.     <bean id="sampleMultiMethodController" 
   9.   class="com.prs.application.ehld.sample.web.controller.SampleMultiMethodController"> 
  10.         <property name="methodNameResolver"> 
  11.             <bean  
  12. class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver"> 
  13.                 <property name="mappings"> 
  14.                     <props> 
  15.                         <prop key="/ehld.sample.getuserinfolist.do">listUser</prop> 
  16.                         <prop key="/ehld.sample.edituserinfo.do">edtiUser</prop> 
  17.                         <prop key="/ehld.sample.saveuserinfo.do">saveUser</prop> 
  18.                     </props> 
  19.                 </property> 
  20.             </bean> 
  21.         </property> 
  22.         <property name="sampleAction" 
  23.  ref="com.prs.application.ehld.sample.biz.action.sampleAction"></property> 
  24.     </bean> 

<!-- 把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.SampleMultiMethodController">
<property name="methodNameResolver">
<bean
class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver">
<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应该配置简单明了,并且无需要在多个地方进行配置。 应该支持对绑定对象自定义名称。

Java代码 复制代码

   1. <bean   name="sampleMultiMethodController"  
   2. class="com.prs.application.ehld.sample.web.controller.SampleMultiMethodController"> 
   3.             <property name="commandName" value="userInfoDTO"/> 
   4.             <property name="formView" value="ehld.sample.userForm"/> 
   5.             <property name="successView" value="redirect:ehld.sample.getuserinfolist.do"/>         
   6.             <property name="urlMethodmappings"> 
   7.                 <props> 
   8.                     <!--显示用户信息列表 --> 
   9.                     <prop key="/ehld.sample.getuserinfolist.do">listUser</prop> 
  10.                     <!-- 编辑用户信息 -->    
  11.                     <prop key="/ehld.sample.edituserinfo.do">edtiUser</prop> 
  12.                     <!-- 保存用户信息--> 
  13.                     <prop key="/ehld.sample.saveuserinfo.do">saveUser</prop>             
  14.                 </props> 
  15.             </property> 
  16.             <property name="sampleAction"  
  17. ref="com.prs.application.ehld.sample.biz.action.sampleAction"></property> 
  18. </bean> 

<bean   name="sampleMultiMethodController"
class="com.prs.application.ehld.sample.web.controller.SampleMultiMethodController">
<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配置

4. 增强的MultiActionController实现
上面提到理想MultiActionController的构想,有三点需要实现。现在来讨论实现它们。
1. 把请求与具体方法之间的映射作为MultActionController自身的一个属性。也就是说MultiActionController提供一个“urlMethodMapping”的属性来保存请求路径与对应方法之间的映射关系。

我们知道MultiActionController有一个methodNameResolver的属性,而请求路径与方法之间的对应映射关系是由一个MethodNameResolver 的bean来保存的。我们一般可以配置一个PropertiesMethodNameResolver来作默认实现。把请求路径与方法之间的映射关系保存在PropertiesMethodNameResolver中的“mapping”属性中。

我们可以在MultiActionController中定义一个PropertiesMethodNameResolver类型的成员变量 “propertiesMethodNameResoler”。和定义一个Properties类型的成员变量“urlMethodmappings”
在MultiActionController的bean进行配置的时候把urlMethodmappings的值作为 propertiesMethodNameResoler的mapping的值。然后再调用MultiActionController的 setMethodNameResolver()方法,把propertiesMethodNameResoler设置为 MultiActionController的methodNameResolver的属性值。要做到这一些还应该实现InitializingBean 接口

Java代码 复制代码

   1. public class MultiMethodController extends MultiActionController implements 
   2.         InitializingBean { 
   3.  
   4.     private Properties urlMethodmappings; 
   5.         public void afterPropertiesSet() throws Exception { 
   6.         if (urlMethodmappings != null && !urlMethodmappings.isEmpty()) { 
   7.          
   8.             PropertiesMethodNameResolver propertiesMethodNameResolver  
   9. = new PropertiesMethodNameResolver(); 
  10.             propertiesMethodNameResolver.setMappings(urlMethodmappings); 
  11.             this.setMethodNameResolver(propertiesMethodNameResolver); 
  12.             if (this.logger.isInfoEnabled()) { 
  13.                 this.logger.info("binding success...... "); 
  14.             } 
  15.         } else { 
  16.             logger.info("no 'urlMethodmappings' set on MultiMethodController"); 
  17.         } 
  18.     } 
  19.     /**
  20.      * @return Returns the urlMethodmappings.
  21.      */ 
  22.     public Properties getUrlMethodmappings() { 
  23.         return urlMethodmappings; 
  24.     } 
  25.  
  26.     /**
  27.      * @param urlMethodmappings
  28.      *            The urlMethodmappings to set.
  29.      */ 
  30.     public void setUrlMethodmappings(Properties urlMethodmappings) { 
  31.         this.urlMethodmappings = urlMethodmappings; 
  32.     } 
  33. } 

public class MultiMethodController extends MultiActionController implements
InitializingBean {

private Properties urlMethodmappings;
public void afterPropertiesSet() throws Exception {
if (urlMethodmappings != null && !urlMethodmappings.isEmpty()) {

PropertiesMethodNameResolver propertiesMethodNameResolver
= new PropertiesMethodNameResolver();
propertiesMethodNameResolver.setMappings(urlMethodmappings);
this.setMethodNameResolver(propertiesMethodNameResolver);
if (this.logger.isInfoEnabled()) {
this.logger.info("binding success...... ");
}
} else {
logger.info("no 'urlMethodmappings' set on MultiMethodController");
}
}
/**
* @return Returns the urlMethodmappings.
*/
public Properties getUrlMethodmappings() {
return urlMethodmappings;
}

/**
* @param urlMethodmappings
*            The urlMethodmappings to set.
*/
public void setUrlMethodmappings(Properties urlMethodmappings) {
this.urlMethodmappings = urlMethodmappings;
}
}


Java代码 复制代码

   1. 在afterPropertiesSet中, 
   2. PropertiesMethodNameResolver  propertiesMethodNameResolver  
   3. = new PropertiesMethodNameResolver();  
   4.             创建一个默认的PropertiesMethodNameResolver的实例 
   5.             propertiesMethodNameResolver.setMappings(urlMethodmappings); 
   6.             把urlMethodmappings作为propertiesMethodNameResolver的mapping属性值 
   7.             this.setMethodNameResolver(propertiesMethodNameResolver); 
   8.             调用父类方法,把propertiesMethodNameResolver注入MethodNameResolver属性中 

在afterPropertiesSet中,
PropertiesMethodNameResolver  propertiesMethodNameResolver
= new PropertiesMethodNameResolver();
创建一个默认的PropertiesMethodNameResolver的实例
propertiesMethodNameResolver.setMappings(urlMethodmappings);
把urlMethodmappings作为propertiesMethodNameResolver的mapping属性值
this.setMethodNameResolver(propertiesMethodNameResolver);
调用父类方法,把propertiesMethodNameResolver注入MethodNameResolver属性中


2. 通过一个commandName属性,可以让用户自由决定绑定对象的名称
MultiActionController的
Java代码 复制代码

   1. getCommandName如下 
   2.             public static final String DEFAULT_COMMAND_NAME = "command"; 
   3. protected String getCommandName(Object command) { 
   4.                return DEFAULT_COMMAND_NAME; 
   5.             } 

getCommandName如下
public static final String DEFAULT_COMMAND_NAME = "command";
protected String getCommandName(Object command) {
       return DEFAULT_COMMAND_NAME;
}

MultiActionController并没有一个setCommandName的方法,所以我们需要一个setCommandName的方法,然后重写getCommandName(Object command)方法

Java代码 复制代码

   1. private String commandName =DEFAULT_COMMAND_NAME; 
   2.     public String getCommandName() { 
   3.         return commandName; 
   4.     } 
   5.     public void setCommandName(String commandName) { 
   6.         this.commandName = commandName; 
   7.     } 
   8.     protected String getCommandName(Object object) { 
   9.         return this.getCommandName(); 
  10.     } 

private String commandName =DEFAULT_COMMAND_NAME;
public String getCommandName() {
return commandName;
}
public void setCommandName(String commandName) {
this.commandName = commandName;
}
protected String getCommandName(Object object) {
return this.getCommandName();
}


如果没有设置commandName属性,默认值为“command”,通过setCommandName方法就可以自由的去决定comamnd对象的名称了。
这样我们基本上已经简化了MultiActionController的自身的配置,但是它仍然需要与一个UrlHandlerMapping联系,也就是增加或删除一个MutilActionController的bean。都需要修改某一个UrlHandlerMapping的bean的配置。这也就是我们上面说的理想MultiActionController的第3点。


3. 简化UrlHandlerMapping的关联配置
UrlHandlerMapping是请求路径与Controller之间的对应映射。UrlHandlerMapping有一个最简单的实现就是SimpleUrlHandlerMapping.
Java代码 复制代码

   1. <bean id="simpleUrlMapping"                        class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> 
   2.      <property name="mappings"> 
   3.       <props> 
   4.       <prop key="/welcom.do">oneController</prop> 
   5.       </props> 
   6.    </property>         
   7. </bean> 

<bean id="simpleUrlMapping"                     class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
     <property name="mappings">
      <props>
      <prop key="/welcom.do">oneController</prop>
      </props>
   </property>
</bean>


“/welcom.do”这个请求路径对应bean 名称为oneController的Controller实例。所以应将MultiActionController中的所有请求路径都保存在一个 UrlHandlerMapping的mappings属性中,作为key值,把MutilActionController 的bean实例作为value作。
DispatcherServlet在初始化时会在Context中查找所有类型为HandlerMapping的bean,将所有的 HandlerMapping实例保存在handlerMappings属性List中。当一个请求进入时,DispatcherServlet会依次查找handlerMappings List中的HandlerMapping实例是否匹配当前请求路径,如果匹配当前请求路径,就获取请求路径对应的Controller实例;如果 Controller实例是MultiActionController类型时,MultiActionController就会会根据当前请求路径去调用MultiActionController相应的方法。这就是一个MultiActionController的执行过程。
根据这样的原理,能够有一个类似SimpleUrlHandlerMapping的HandlerMapping能够在初始化的时候自动在当前 WebApplicationContext中查找所有MultiActionController类型的bean。然后依次生成一个以 MultiActionController的urlMethodmappings Map的所有key值作为key值,以MultiActionController实例为value值的一个Map,并把这个Map所有元素都添加到 SimpleUrlHandlerMapping的mappings属性中。这样就达到了我们自动化配置的效果。
我们把这个HandlerMapping 称为MultiMethodControllerUrlHandlerMapping,下面我们讲怎么具体去实现它。
5.实现MultiMethodControllerUrlHandlerMapping
我们在上面讨论过了怎么实现MultiMethodControllerUrlHandlerMapping,要实现为具体的代码,我们可以通过扩展 org.springframework.web.servlet.handler.AbstractUrlHandlerMapping。 AbstractUrlHandlerMapping扩展了 org.springframework.web.context.support.WebApplicationObjectSupport。 WebApplicationObjectSupport可以获得当前WebApplicationContext。
1. 重写initApplicationContext方法,在context中查找所有MultiActionController类型的bean,把 MultiActionController的urlMethodmappings属性的key值为key 值,MultiActionController实例为键值的键值对添加到一个urlMap中。
Java代码 复制代码

   1. public class MultiMethodControllerUrlHandlerMapping extends AbstractUrlHandlerMapping{ 
   2.     private  Map urlMap = new HashMap(); 
   3.     public void initApplicationContext() throws BeansException { 
   4.         initialUrlMap(); 
   5.     } 
   6.     protected void initialUrlMap()throws BeansException{ 
   7.         //找查所有MultiMethodController类型和子类型的bean到一个map中,bean Name为key值 ,bean实例为value值 
   8.         Map matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors( 
   9.                 getWebApplicationContext(), 
  10.                 MultiMethodController.class, true, false); 
  11.         List controllers = null; 
  12.         if(!matchingBeans.isEmpty()){ 
  13.             controllers = new ArrayList(matchingBeans.values()); 
  14.             for(int i = 0; controllers != null && i < controllers.size();i++){ 
  15.                 MultiMethodController controller = (MultiMethodController)controllers.get(i); 
  16.                 Properties urlPros = controller.getUrlMethodmappings();      
  17.                 Iterator itr = urlPros.keySet().iterator(); 
  18.                 for(;itr.hasNext();){ 
  19.                     String url = (String)itr.next(); 
  20.                     urlMap.put(url,controller); 
  21.                 } 
  22.             } 
  23.         } 
  24. } 

public class MultiMethodControllerUrlHandlerMapping extends AbstractUrlHandlerMapping{
private  Map urlMap = new HashMap();
public void initApplicationContext() throws BeansException {
initialUrlMap();
}
protected void initialUrlMap()throws BeansException{
//找查所有MultiMethodController类型和子类型的bean到一个map中,bean Name为key值 ,bean实例为value值
Map matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
getWebApplicationContext(),
MultiMethodController.class, true, false);
List controllers = null;
if(!matchingBeans.isEmpty()){
controllers = new ArrayList(matchingBeans.values());
for(int i = 0; controllers != null && i < controllers.size();i++){
MultiMethodController controller = (MultiMethodController)controllers.get(i);
Properties urlPros = controller.getUrlMethodmappings();
Iterator itr = urlPros.keySet().iterator();
for(;itr.hasNext();){
String url = (String)itr.next();
urlMap.put(url,controller);
}
}
}
}

2. 遍历urlMap,调用AbstractUrlHandlerMapping的registerHandler(String urlPath, Object handler)方法,依次将url与对应的handler注册到AbstractUrlHandlerMapping的handlerMap中。
Java代码 复制代码

   1. protected void registerUrlMap()throws BeansException{ 
   2.         if (this.urlMap.isEmpty()) { 
   3.             logger.info("Neither 'urlMap' nor 'mappings' set on MultiMethodControllerUrlHandlerMapping"); 
   4.         } 
   5.         else { 
   6.             Iterator itr = this.urlMap.keySet().iterator(); 
   7.             while (itr.hasNext()) { 
   8.                 String url = (String) itr.next(); 
   9.                 Object handler = this.urlMap.get(url); 
  10.                 // prepend with slash if it's not present 
  11.                 if (!url.startsWith("/")) { 
  12.                     url = "/" + url; 
  13.                 } 
  14.                 //父类方法 
  15.                 registerHandler(url, handler); 
  16.             } 
  17.         }        
  18.          
  19.     } 

protected void registerUrlMap()throws BeansException{
if (this.urlMap.isEmpty()) {
logger.info("Neither 'urlMap' nor 'mappings' set on MultiMethodControllerUrlHandlerMapping");
}
else {
Iterator itr = this.urlMap.keySet().iterator();
while (itr.hasNext()) {
String url = (String) itr.next();
Object handler = this.urlMap.get(url);
// prepend with slash if it's not present
if (!url.startsWith("/")) {
url = "/" + url;
}
//父类方法
registerHandler(url, handler);
}
}

}


然后在initApplicationContext方法中调用registerUrlMap方法
Java代码 复制代码

   1. public void initApplicationContext() throws BeansException { 
   2.         initialUrlMap(); 
   3.         registerUrlMap(); 
   4.     } 

public void initApplicationContext() throws BeansException {
initialUrlMap();
registerUrlMap();
}


3. 使用MultiMethodControllerUrlHandlerMapping
使用MultiMethodControllerUrlHandlerMapping,只需要在ApplicationContext中,定义成一个bean就可以了。
Java代码 复制代码

   1. id="multiMethodControllerUrlHandlerMapping" 
   2.   class="com.prs.application.ehld.web.handler.MultiMethodControllerUrlHandlerMapping"> 
   3.   <property name="order"> 
   4.      <value>3</value> 
   5.   </property> 
   6. </bean> 

id="multiMethodControllerUrlHandlerMapping"
  class="com.prs.application.ehld.web.handler.MultiMethodControllerUrlHandlerMapping">
  <property name="order">
     <value>3</value>
  </property>
</bean>


注意:在一个context如果定义多个HandlerMapping,需要为每一个HandlerMapping指定order属性。

你只需要在在context 中定义MultiMethodControllerUrlHandlerMapping,在使用MultiActionController时,只需要配置urlMethodmappings属性就可以了。当删除或增加一个MultiActionController的bean时,无需要连带配置任何 HandlerMapping. 简化了bean的配置。使得MultiActionControler的bean配置只关心自身的属性配置,而无需要去关心看起来与自身无关的 HandlerMapping的配置。使得整个配置更合乎人们正常的思维逻辑,减少配置的复杂性。
6.设计讨论
在这里我们将对以Spring为基础进行项目架构设计进行一些讨论.
1. MultiActionController还是AbstractController与SimpleFormController组合
在使用Spring MVC时,SimpleFormController用于表单编辑和提交;而复杂的功能则通过扩展AbstractcController完成。这就是所谓的AbstractController与SimpleFormController组合。以AbstractController与 SimpleFormController的结合来完成表示层逻辑。
Spring MVC虽然也提供了MultiActionController,但是它似乎天生就有点蹩脚。对数据绑定支持不是很好,在用于表单编辑和提交时不像 SimpleFormController那么强大。其实通过对MultiActionController的扩展和增强,完成可以实现与 SimpleFormController同样的功能,比如数据校验等,并且还比SimpleFormController具有更多的灵活性。
在OO技术中,有一个重要的原则:低耦合,高内聚;我们应该按职责来设计对象。按对象应该具有的职责来给对象设计相应的方法。如果把一个对象本来该具有的职责分散到不同类中去完成,那么这个些类是违反“低耦合,高内聚”原则的。一个类不是高内聚的,就不便于维护和扩展,造成大量重复代码的产生。同样把一组相关的功能分散到多个Controller去实现,是违反“低耦合,高内聚”原则的,可以就会产生大量的重复代码。比如参数获取,数据校验等。如果使用MultiActionController,把相关的功能由一个Controller的不同方法实现,集中在一个Controller类中处理,就使得这个Controller类是具有“高内聚”性的。所以,在项目应用中,相关的功能应该由一个MultiActionController的不同方法去实现。这样就便于代码的维护,提高代码的重用,减少bean配置,降低项目的复杂度。
2. 灵活性与简易化
Spring作为一个轻量级的j2ee基础框架,使用是非常灵活的。特别是可以通过xml文件来灵活的配置对象之间的依赖。但是,以Spring 作为框架的项目,bean的配置太多,反而增加了项目的复杂度。在开发过程中,应该把主要精力花在关注业务逻辑的实现上面,而不应该花在配置上面。灵活度越大也就导致了复杂度越高。当然,Spring是一个通用框架,应该具有这样的灵活性,才便于扩展,以满足各种应用需要。
在具体的项目中,就应该使架构使用起来简单,易用。特别是以Spring作为基础的架构中,应该通过设计降低配置的复杂度,尽可能的减少bean的配置和使配置简单化。
一个bean属性发生变化,不应该产生连带关系,使得其它bean也需要修改配置。这是不利于团队开发的。在团队开发中,开发人员应该只关心业务对象的bean配置。
像HandlerMapping这些属于框架基础bean配置一旦定义后就应该具有稳定性。不要因为业务对象bean的改变而需要开发人员随之进行修改。
3. 增强的MultiActionController与MultiMethodControllerUrlHandlerMapping
通过扩展MultiActionController,使得它得到增强,能够实现SimpleFormController的功能,同时使得配置更加直观和简易。
只需要定义一个MultiMethodControllerUrlHandlerMapping,使得开发人员只需要关注相关MultiActionController的配置,而无需去再关注和修改HandlerMapping的配置。
通过MultiMethodControllerUrlHandlerMapping 与增强的MultiActionController结合,更易于运用OO技术设计高内聚的Controller类,减化bean的配置。让开发人员把精力花在系统的业务逻辑的实现上,而不会去过度关心bean的配置。
7.完整的代码实现
这里把增强的MultiActionController称为MultiMethodController
1. MultiMethodController.java
Java代码 复制代码

   1. public class MultiMethodController extends MultiActionController implements 
   2.         InitializingBean { 
   3.  
   4.     private Properties urlMethodmappings; 
   5.      
   6.     private String commandName =DEFAULT_COMMAND_NAME; 
   7.      
   8.     private String formView ; 
   9.      
  10.     private String successView; 
  11.      
  12.  
  13.     /**
  14.      * @return Returns the formView.
  15.      */ 
  16.     public String getFormView() { 
  17.         return formView; 
  18.     } 
  19.  
  20.     /**
  21.      * @param formView The formView to set.
  22.      */ 
  23.     public void setFormView(String formView) { 
  24.         this.formView = formView; 
  25.     } 
  26.  
  27.     /**
  28.      * @return Returns the successView.
  29.      */ 
  30.     public String getSuccessView() { 
  31.         return successView; 
  32.     } 
  33.  
  34.     /**
  35.      * @param successView The successView to set.
  36.      */ 
  37.     public void setSuccessView(String successView) { 
  38.         this.successView = successView; 
  39.     } 
  40.  
  41.     /* (non-Javadoc)
  42.      * @see org.springframework.web.servlet.mvc.multiaction.MultiActionController#getCommandName(java.lang.Object)
  43.      */ 
  44.     protected String getCommandName(Object object) { 
  45.         return this.getCommandName(); 
  46.     } 
  47.  
  48.     /*
  49.      * (non-Javadoc)
  50.      * 
  51.      * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
  52.      */ 
  53.     public void afterPropertiesSet() throws Exception { 
  54.         if (urlMethodmappings != null && !urlMethodmappings.isEmpty()) { 
  55.          
  56.             PropertiesMethodNameResolver propertiesMethodNameResolver = new PropertiesMethodNameResolver(); 
  57.             propertiesMethodNameResolver.setMappings(urlMethodmappings); 
  58.             this.setMethodNameResolver(propertiesMethodNameResolver); 
  59.             if (this.logger.isInfoEnabled()) { 
  60.                 this.logger.info("binding success...... "); 
  61.             } 
  62.         } else { 
  63.             logger.info("no 'urlMethodmappings' set on MultiMethodController"); 
  64.         } 
  65.     } 
  66.  
  67.     /**
  68.      * @return Returns the urlMethodmappings.
  69.      */ 
  70.     public Properties getUrlMethodmappings() { 
  71.         return urlMethodmappings; 
  72.     } 
  73.  
  74.     /**
  75.      * @param urlMethodmappings
  76.      *            The urlMethodmappings to set.
  77.      */ 
  78.     public void setUrlMethodmappings(Properties urlMethodmappings) { 
  79.         this.urlMethodmappings = urlMethodmappings; 
  80.     } 
  81.  
  82.     /**
  83.      * @return Returns the commandName.
  84.      */ 
  85.     public String getCommandName() { 
  86.         return commandName; 
  87.     } 
  88.  
  89.     /**
  90.      * @param commandName The commandName to set.
  91.      */ 
  92.     public void setCommandName(String commandName) { 
  93.         this.commandName = commandName; 
  94.     } 
  95.  
  96. } 
  97.  
  98. 2.  MultiMethodControllerUrlHandlerMapping.java 
  99. public class MultiMethodControllerUrlHandlerMapping extends AbstractUrlHandlerMapping{ 
100.     private  Map urlMap = new HashMap(); 
101.     /**
102.      *映射URL 到 Controller 的bean 名称
103.      *这是一个配置HandMapping的典型的方式.
104.      *<p>支持直接URL匹配和"ant风格"模式的匹配
105.      *详细的语法,参见AntPathMatcher类
106.      *
107.      * @param mappings URL作为键,而bean 名称作为键值的Properties
108.      * @see org.springframework.util.AntPathMatcher
109.      */ 
110.     public void setMappings(Properties mappings){ 
111.         this.urlMap.putAll(mappings); 
112.     } 
113.  
114.     /**
115.      * @return Returns the urlMap.
116.      */ 
117.     public Map getUrlMap() { 
118.         return urlMap; 
119.     } 
120.  
121.  
122.     /**
123.      * @param urlMap The urlMap to set.
124.      */ 
125.     public void setUrlMap(Map urlMap) { 
126.         this.urlMap = urlMap; 
127.     } 
128.      
129.      
130.     public void initApplicationContext() throws BeansException { 
131.         initialUrlMap(); 
132.         registerUrlMap(); 
133.     } 
134.      
135.     protected void registerUrlMap()throws BeansException{ 
136.         if (this.urlMap.isEmpty()) { 
137.             logger.info("Neither 'urlMap' nor 'mappings' set on MultiMethodControllerUrlHandlerMapping"); 
138.         } 
139.         else { 
140.             Iterator itr = this.urlMap.keySet().iterator(); 
141.             while (itr.hasNext()) { 
142.                 String url = (String) itr.next(); 
143.                 Object handler = this.urlMap.get(url); 
144.                 // prepend with slash if it's not present 
145.                 if (!url.startsWith("/")) { 
146.                     url = "/" + url; 
147.                 } 
148.                 registerHandler(url, handler); 
149.             } 
150.         }        
151.          
152.     } 
153.      
154.     protected void initialUrlMap()throws BeansException{ 
155.         //找查所有MultiMethodController类型和子类型的bean到一个map中,bean Name为key值 ,bean实例为value值 
156.         Map matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors( 
157.                 getWebApplicationContext(), 
158.                 MultiMethodController.class, true, false); 
159.         List controllers = null; 
160.         if(!matchingBeans.isEmpty()){ 
161.             controllers = new ArrayList(matchingBeans.values()); 
162.             Collections.sort(controllers, new OrderComparator()); 
163.             for(int i = 0; controllers != null && i < controllers.size();i++){ 
164.                 MultiMethodController controller = (MultiMethodController)controllers.get(i); 
165.                 Properties urlPros = controller.getUrlMethodmappings();      
166.                 Iterator itr = urlPros.keySet().iterator(); 
167.                 for(;itr.hasNext();){ 
168.                     String url = (String)itr.next(); 
169.                     urlMap.put(url,controller); 
170.                 } 
171.             } 
172.         } 
173.     } 
174. } 
分享到:
评论

相关推荐

    springMVC带上传文件

    可以通过验证文件扩展名、限制上传大小、使用安全的文件命名策略等方式来增强安全性。 总的来说,`springMVC带上传文件`的功能实现涉及到了Spring MVC的控制器、模型、视图解析器的配置,以及文件上传的相关处理。...

    spring-ext-handler-mapping.rar_ext_spring ext_spring mvc

    PropertyMultiActionController可能是MultiActionController的一个变种,它可能通过属性(property)来决定调用哪个处理方法,增强了灵活性。不过,随着Spring MVC的发展,这种方式已经被注解驱动的Controller所取代...

    spring与struts的整合

    - **增强可维护性**:Spring和Struts的结合,可以让开发者在不修改Struts代码的情况下,通过Spring的配置文件调整业务逻辑,提高了系统的可维护性和扩展性。 - **统一配置管理**:通过Spring的IoC容器,可以集中管理...

    spring_mvc注解入门

    在传统的Spring MVC中,Controller通常需要实现`org.springframework.web.servlet.mvc.Controller`接口,或者是继承`SimpleFormController`或`MultiActionController`。但是使用注解后,Controller不再需要继承任何...

    使用 Spring 2.5 基于注解驱动的 Spring MVC.doc

    这与传统的实现 `org.springframework.web.servlet.mvc.Controller` 接口或者继承 `SimpleFormController` 或 `MultiActionController` 不同,`@Controller` 注解使得我们的类变成了一个纯粹的 POJO,无需额外的接口...

    spring-framework-3.0.6.RELEASE-with-docs.zip

    在3.0.6.RELEASE中,Spring Data Access层增强了对JPA2的支持,提供了更好的事务管理策略,并且支持动态SQL查询,使数据库操作更为简便。 五、消息支持 Spring 3.0.6.RELEASE提供了全面的消息传递支持,包括JMS...

    毕设 外文文献翻译-Spring的web MVC构架模式 (3).docx

    为了适应复杂的应用场景,Spring提供了多种抽象控制器,如AbstractController、AbstractCommandController、MultiActionController、SimpleFormController和AbstractWizardFormController,允许开发者按需选择。...

    毕设外文文献翻译-Spring的webMVC构架模式 (3).docx

    Spring支持多种类型的控制器,如AbstractController、AbstractCommandController、MultiActionController等,它们提供了不同程度的抽象和灵活性。与Struts不同,Spring的控制器可以不需要继承特定的基础类,而是...

    毕设外文文献翻译--Spring的webMVC构架模式.pdf

    此外,Spring MVC支持多种控制器类型,如AbstractController、AbstractCommandController、MultiActionController等,这使得开发者可以根据具体需求选择合适的控制器基类,增强了代码的可复用性和可维护性。...

    毕设 外文文献翻译-Spring的web MVC构架模式 (2).docx

    它提供了多种控制器基类,如AbstractController、AbstractCommandController、MultiActionController等,以适应不同的控制需求。与Struts相比,Spring不强制使用特定的表单或Action类,而是允许直接绑定业务对象,...

    SpringMVC配置

    开发者可以根据实际需求调整配置,如自定义更多的HandlerMapping策略、使用不同的视图技术(如Thymeleaf、Freemarker等)替换默认的JSP视图,以及集成Spring Security等安全框架增强应用的安全性。

    SpringMVC教程及实现原理

    - **org.springframework.context-3.0.5.RELEASE.jar**:构建在beans包基础之上,增强了对资源文件和国际化方面的支持。 - **org.springframework.core-3.0.5.RELEASE.jar**:Spring的核心包,包含了框架的基础组件...

    Spring培训资料

    - **MultiActionController**:允许在一个控制器中处理多个不同的请求路径。 - **选择合适的控制器**:根据具体需求选择最适合的控制器类型。 **4.4 数据绑定和数据校验** - **数据绑定**:Spring MVC提供了自动...

    Spring中文帮助文档

    2.6.2. 增强的测试支持 2.6.3. JMX 支持 2.6.4. 将Spring 应用程序上下文部署为JCA adapter 2.6.5. 计划任务 2.6.6. 对Java 5 (Tiger) 支持 2.7. 移植到Spring 2.5 2.7.1. 改变 2.8. 更新的样例应用 2.9. ...

    Spring API

    2.6.2. 增强的测试支持 2.6.3. JMX 支持 2.6.4. 将Spring 应用程序上下文部署为JCA adapter 2.6.5. 计划任务 2.6.6. 对Java 5 (Tiger) 支持 2.7. 移植到Spring 2.5 2.7.1. 改变 2.8. 更新的样例应用 2.9. ...

Global site tag (gtag.js) - Google Analytics