Spring框架研究之MultiActionController

Spring的MultiActionController允许将相关操作集中在同一个类中,提高代码的高内聚性。它通过不同的MethodNameResolver实现,如InternalPathMethodNameResolver、ParameterMethodNameResolver和PropertiesMethodNameResolver,来解析请求并调用相应的方法。在处理请求时,MultiActionController会进行Command对象的绑定和验证,然后调用具体方法,并根据返回结果生成ViewModel。通过一个登录案例展示了如何使用MultiActionController进行控制器的实现。
摘要由CSDN通过智能技术生成


最近一段时间Spring MVC吵得挺火的,项目中也有用到,于是趁这个机会研究了下MultiActionController.

MultiActionController的用途:

在使用Spring提供的控制器时,AbstractController和SimpleFormController是应用得最多的。AbstractController是最基本的Controller,可以给予用户最大的灵活性。

SimpleFormController则用于典型的表单编辑和提交。在一个需要增,删,改,查的需求中,增加和修改扩展SimpleFormController完成,删除和查询则扩展AbstractController完成。

但是像上面那样完成某一业务对象的增,删,改,查,都属于一类相关的业务。把一类相关的操作分布到不同的类去完成,违返“高内聚”的设计原则。这样四个业务操作需要四个类来完成,造成太多的类文件,难以维护和配置。

所以Spring借鉴Struts的DispatchAction提供了类似功能的MultiActionController。可以实现不同的请求路径对应MultiActionController中的不同方法,这样就可以把相关的操作都在一个类的相关方法中完成。这样使得这个类具有“高内聚”,也利于系统的维护,还避免了重复代码。增加和修改操作的数据验证逻辑是很相似的,使用MultiActionController后就可以让增加和修改操作共用一段数据验证逻辑代码。


MultiActioncontroller的结构:

public class MultiActionController extends AbstractController implements LastModified {
  

本文查看的spring3.1.0的源代码,由上述声明可知,MultiActionController类扩展至AbstractController对象,主要业务逻辑在重写方法:

/**
	 * Template method. Subclasses must implement this.
	 * The contract is the same as for <code>handleRequest</code>.
	 * @see #handleRequest
	 */
	protected abstract ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
	    throws Exception;

MultiActionController中对上述方面的具体实现如下:

/**
	 * Determine a handler method and invoke it.
	 * @see MethodNameResolver#getHandlerMethodName
	 * @see #invokeNamedMethod
	 * @see #handleNoSuchRequestHandlingMethod
	 */
	@Override
	protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		try {
			String methodName = this.methodNameResolver.getHandlerMethodName(request);
			return invokeNamedMethod(methodName, request, response);
		}
		catch (NoSuchRequestHandlingMethodException ex) {
			return handleNoSuchRequestHandlingMethod(ex, request, response);
		}
	}

由上述代码可知,具体的业务逻辑是:

String methodName = this.methodNameResolver.getHandlerMethodName(request);
1) 通过配置的methodNameResolver确定要引用的方法名。

return invokeNamedMethod(methodName, request, response);
2) 根据确定的方法名调用响应的方法,执行业务逻辑。



1。1)  methodNameResolver的确定,

methodNameResolver变量类型为接口 MethodNameResolver, 实现MethodNameResolver接口的常用的有以下三个:
 A)  InternalPathMethodNameResolver   该类型为默认实现,即若没有配置methodNameResolver属性时使用。 它的主要用法如下:

Maps the resource name after the last slash, ignoring an extension. 
E.g. "/foo/bar/baz.html" to "baz", assuming a "/foo/bar/baz.html" controller mapping to the corresponding MultiActionController handler. method. 


中文意思就是: 以最后一个斜杠为分界线,取得最后的部分,去掉后缀名就是你的映射方法名。

 B)  ParameterMethodNameResolver 这个用的很普遍, 默认的paramName为action。 具体用法如下:

配置该类的paramName为你想要用来指定方法属性的名字,比如什么action、method、command都行,什么都行,不配置的话,就是默认的action。

名称定位器就会获取该属性(名称为paramName配置的值)的值作为方法名。


 C)  PropertiesMethodNameResolver 这个可以单独配置properties文件来指定url--methodName的映射。每个都需要配置,重用性不好。具体用法:

The most flexible out-of-the-box implementation of the MethodNameResolver interface. 
Uses java.util.Properties to define the mapping between the URL of incoming requests and the corresponding method name. 
Such properties can be held in an XML document. 

Properties format is /welcome.html=displayGenresPage Note that method overloading isn't allowed, so there's no need to specify arguments. 

Supports direct matches, e.g. a registered "/test" matches "/test", and a various Ant-style pattern matches,
 e.g. a registered "/t*" matches both "/test" and "/team". For details, see the AntPathMatcher javadoc.



2)invokeNamedMethod(methodName, request, response)的详细流程:

/**
	 * Invokes the named method.
	 * <p>Uses a custom exception handler if possible; otherwise, throw an
	 * unchecked exception; wrap a checked exception or Throwable.
	 */
	protected final ModelAndView invokeNamedMethod(
			String methodName, HttpServletRequest request, HttpServletResponse response) throws Exception {

		Method method = this.handlerMethodMap.get(methodName);
		if (method == null) {
			throw new NoSuchRequestHandlingMethodException(methodName, getClass());
		}

		try {
			Class[] paramTypes = method.getParameterTypes();
			List<Object> params = new ArrayList<Object>(4);
			params.add(request);
			params.add(response);

			if (paramTypes.length >= 3 && paramTypes[2].equals(HttpSession.class)) {
				HttpSession session = request.getSession(false);
				if (session == null) {
					throw new HttpSessionRequiredException(
							"Pre-existing session required for handler method '" + methodName + "'");
				}
				params.add(session);
			}

			// If last parameter isn't of HttpSession type, it's a command.
			if (paramTypes.length >= 3 &&
					!paramTypes[paramTypes.length - 1].equals(HttpSession.class)) {
				Object command = newCommandObject(paramTypes[paramTypes.length - 1]);
				params.add(command);
				bind(request, command);
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值