首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件架构设计 >

Spring架构加强MultiActionController

2013-09-06 
Spring架构增强MultiActionControllerSpring架构增强MultiActionController 在使用Spring提供的控制器时,A

Spring架构增强MultiActionController

Spring架构增强MultiActionController

在使用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"
ref=" sampleMultiMethodController "/>
</bean>

<!-- 集增,删,改,查操作到一个类的controller -->
<bean id="sampleMultiMethodController"
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的构想,有三点需要实现。现在来讨论实现它们。

4.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接口。

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;
}
}
在afterPropertiesSet中, PropertiesMethodNameResolver propertiesMethodNameResolver
= new PropertiesMethodNameResolver();
创建一个默认的PropertiesMethodNameResolver的实例

propertiesMethodNameResolver.setMappings(urlMethodmappings);
把urlMethodmappings作为propertiesMethodNameResolver的mapping属性值
this.setMethodNameResolver(propertiesMethodNameResolver);

调用父类方法,把propertiesMethodNameResolver注入MethodNameResolver属性中。

注意,在这里我命名为MultiMethodController是为了与MultiActionController区别。
   
通过这样的代码,简化了原本复杂的配置。

4.2通过一个commandName属性,可以让用户自由决定绑定对象的名称

MultiActionController的getCommandName如下:
public static final String DEFAULT_COMMAND_NAME = "command";
protected String getCommandName(Object command) ...{
return DEFAULT_COMMAND_NAME;
}
MultiActionController并没有一个setCommandName的方法,所以我们需要一个setCommandName的方法,然后重写getCommandName(Object command)方法
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点。

4.3简化UrlHandlerMapping的关联配置

UrlHandlerMapping是请求路径与Controller之间的对应映射。UrlHandlerMapping有一个最简单的实现就是SimpleUrlHandlerMapping。
<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,下面我们讲怎么具体去实现它。

原文:http://www.51cto.com/specbook/223/36243.htm

热点排行