SpringMVC源码(七)Controller控制器5-MultiActionController

来源:互联网 发布:php输出js代码 编辑:程序博客网 时间:2024/06/06 11:50
MultiActionController 多动作控制器 :

前面的控制器一般都是对应一个处理方法,如果对数据进行CRUD操作,那么就需要四个控制器,当我们随着方法的增加,控制器的数量便会大幅度增加.增加了项目的臃肿程度,是不可取的.为了解决这个难题,springmvc 的MultiActionController控制器便闪亮登场.MultiActionController是用于处理多个HTTP请求的处理器,支持在一个控制器里面定义多个功能处理方法.

同时MultiActionController 也提供了两个重要属性:

delegate  :功能处理的委托对象,即我们要调用请求处理方法所在对象。

methodNameResolver:功能处理方法名解析器,根据请求的url信息来解析它将调用的方法,需要在配置文件中定义此解析器 。

MultiActionController 是如何做到不同的url请求都能得到正确的处理方法呢?

Spring Web MVC提供的MethodNameResolver(方法名解析器) 属性 ,它会根据HTTP请求URL映射得到应该调用的处理器方法.通过反射调用处理器方法,并且封装返回结果作为模型和视图返回给简单控制器适配器。每个处理器方法可以有一个对应的最后修改方法,最后修改方法名是处理器方法名加上LastModified后缀构成的。最后修改方法也是通过反射调用并且返回结果的。

methodNameResolver提供的三种方式:
org.springframework.web.servlet.mvc.multiaction.InternalPathMethodNameResolver
org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver
org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver
1.InternalPathMethodNameResolver
MultiActionController的默认实现,提供从请求URL路径解析功能方法的方法名,从请求的最后一个路径(/)开始,并忽略扩展名;如请求URL是“/user/list.html”,则解析的功能处理方法名为“list”,即调用list方法。该解析器还可以指定前缀和后缀,通过prefix和suffix属性,如指定prefix=”test_”,则功能方法名将变为test_list;
2. PropertiesMethodNameResolver
提供自定义的从请求URL解析功能方法的方法名,使用一组用户自定义的模式到功能方法名的映射,映射使用Properties对象存放,
3.ParameterMethodNameResolver(推荐使用)
提供从请求参数解析功能处理方法的方法名。

下面是MultiActionController的核心代码:

//判断方法是否是功能处理方法  private boolean isHandlerMethod(Method method) {      //得到方法返回值类型      Class returnType = method.getReturnType();      //返回值类型必须是ModelAndView、Map、String、void中的一种,否则不是功能处理方法      if (ModelAndView.class.equals(returnType) || Map.class.equals(returnType) || String.class.equals(returnType) ||              void.class.equals(returnType)) {          Class[] parameterTypes = method.getParameterTypes();          //功能处理方法参数个数必须>=2,且第一个是HttpServletRequest类型、第二个是HttpServletResponse          //且不能Controller接口的handleRequest(HttpServletRequest request, HttpServletResponse response),这个方法是由系统调用          return (parameterTypes.length >= 2 &&                  HttpServletRequest.class.equals(parameterTypes[0]) &&                  HttpServletResponse.class.equals(parameterTypes[1]) &&                  !("handleRequest".equals(method.getName()) && parameterTypes.length == 2));      }      return false;  }  

实现方法:

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);}} 

通过上面的代码可以很清楚的看到利用反射获取到了方法的名称,然后再去调用这个方法.如果没有这个方法的存在,那么就会抛出handleNoSuchRequestHandlingMethod异常.

invokeNamedMethod的具体方法:

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);}Object returnValue = method.invoke(this.delegate, params.toArray(new Object[params.size()]));return massageReturnValueIfNecessary(returnValue);}catch (InvocationTargetException ex) {// The handler method threw an exception.return handleException(request, response, ex.getTargetException());}catch (Exception ex) {// The binding process threw an exception.return handleException(request, response, ex);}}

详细请看:

点击打开链接