Spring MVC 中的 Controller

本文深入探讨Spring MVC框架中Controller的设计理念及其实现方式,包括基本的Controller接口、AbstractController类,以及多动作控制器MultiActionController的使用方法。
摘要由CSDN通过智能技术生成
MVC模型中的控制器负责解析用户的输入信息,并将之变换处理后传入一个model,而这个 model则可能被呈现给发起请求的用户。Spring以非常抽象的方式体现了控制器的理念,从而开发人员在创建controller时将有多种选择。 Spring包含了3类controller:处理HTML表单的controller,基于command的controller,和向导风格的 controller。
 
      Spring中Controller的基本类是org.springframework.web.servlet.mvc.Controller,这是一个相当简洁的接口,源代码如下:

?
1
2
3
4
5
6
7
package org.springframework.web.servlet.mvc;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
public interface Controller {
     ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)  throws Exception;
}
        Controller接口仅仅定义了一个方法用于负责处理客户请求,并返回适当的模型和视图,这也是所有控制器都需要完成的职责。ModelAndView与Controller,这便是Spring  MVC框架实现的基础。尽管Controller相当抽象,但Spring提供了多种Controller接口实现类。
1.  AbstractController 
        AbstractController是WebContentGenerator的子类,并实现了Controller接口。AbstractController是最重要的Controller接口实现之一  ,它提供了一些很基本的功能特征,例如生成HTTP协议的缓存头标数据,设定GET/POST动作等等。
        考察一下AbstratorController所在的类层次:
java.lang.Object
|_ org.springframework.context.support.ApplicationObjectSupport
  |_ org.springframework.web.context.support.WebApplicationObjectSupport
    |_   org.springframework.web.servlet.support.WebContentGenerator
        |_ org.springframework.web.servlet.mvc.AbstractController
 
        AbstratorController从其超类中继承许多属性,这些属性可以通过配置文件注入:
supportedMethods  :指明本Controller应该接受的方法,缺省值“GET,POST”,开发人员也可以自己修改本属性以反应欲支持的方法。若一个请求带有该方法设定,但Controller并不支持,那么这个信息将被通知客户。
requiresSession:指明本Controller是否需要一个HTTP会话以完成它的工作,若Contrller在接收一个请求时并没有HTTP会话存在,那么将抛出一个ServletException。本属性的缺省值是false。
synchronizeSession:若在客户的HTTP会话中,需要以同步方式处理Controller,则使用本属性。
cacheSeconds:当需要Controller为客户的HTTP响应生成一个缓存指令时,可以为cacheSeconds指定一个正整数。本属性缺省值为-1,即不设定缓存。
useExpiresHeader:指示Controller为客户的HTTP响应指定一个兼容HTTP  1.0版本中的"Expires"头标数据。本属性缺省值是true。
useCacheHeader:指示Controller为客户的HTTP响应指定一个兼容HTTP  1.1版本中的"Cache-Control"头标数据。本属性缺省值是true。
        我们阅读一下Spring  src目录中的AbstractController的源代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package org.springframework.web.servlet.mvc;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.support.WebContentGenerator;
import org.springframework.web.util.WebUtils;
public abstract class AbstractController  extends WebContentGenerator  implements Controller {
     private boolean synchronizeOnSession =  false ;
     public final void setSynchronizeOnSession( boolean synchronizeOnSession) {
         this .synchronizeOnSession = synchronizeOnSession;
     }
     public final boolean isSynchronizeOnSession() {
         return synchronizeOnSession;
     }
     public final ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
               throws Exception {
         checkAndPrepare(request, response,  this instanceof LastModified);
         if ( this .synchronizeOnSession) {
               HttpSession session = request.getSession( false );
               if (session !=  null ) {
                   Object mutex = WebUtils.getSessionMutex(session);
                   synchronized (mutex) {
                       return handleRequestInternal(request, response);
                   }
               }
         }
         
         return handleRequestInternal(request, response);
     }
     protected abstract ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
       throws Exception;
}

从上述代码可以看出,AbstractorController的工作流程如下:
1.DispatcherServlet调用handleRequest方法;
2.检查被支持的方法(GET/POST/PUT之一),若不支持则抛出ServletException;
3.若需要发起一个session,则尝试获取一个session,若获取不到,则抛出ServletException; 
4.根据cacheSeconds属性,设定缓存头标的数据;
5.调用受保护的抽象方法handleRequestInternal,这个方法应由AbstractController的子类提供实际的功能实现,并返回ModelAndView对象。
       
        当开发人员使用AbstractController作为自己所设计的控制器的基类时,只需覆盖handleRequestInternal(HttpServletRequest,  HttpServletResponse)方法即可,并返回一个ModelAndView对象,示例如下:
?
1
2
3
4
5
6
7
8
9
10
package samples;
public class SampleController  extends AbstractController {
public ModelAndView handleRequestInternal(
HttpServletRequest request,
HttpServletResponse response)  throws Exception {
     ModelAndView modelAndView =  new ModelAndView( "hello" );
     modelAndView.addObject( "message" "Hello World!" );
     return modelAndView;
}
}

        而配置文件中定义示例如下:
?
1
2
3
< bean id = "sampleController" class = "samples.SampleController" >
     < property name = "cacheSeconds" value = "120" />
</ bean >

       
        在本例中,若使这个SampleController将在给客户的HTTP响应中指定120秒的缓存。SampleController返回了一个一个编码的视图(通常不建议这样设计)。
2.  其他简单的Controller
        尽管开发人员可以自己扩展AbstractController,不过Spring提供了许多具体的实现,可以用于简单的MVC应用。
        ParameterizableViewContr oller类与上面的示例基本相同,除了开发人员可以自己指定所返回视图的名字,这样便不需要在Java类中写视图的名字。
UrlFilenameViewControlle r检查URL,查找文件请求的文件名,并以之作为视图的名字。例如“ http://www.springframework.org/index.html ”的文件名是“index”。
3. MultiActionController
          Spring提供了一个多动作控制器MultiActionController,开发人员藉此可以将多个动作聚合在同一个控制器之内,实现功能集成,从而不必为控制器定义多个入口点。例如对商品信息进行查询、增删改等操作,这个动作可以用一个Contoller来实现。
          这个多动作控制器是Spring中一个独立的Java类包,即
org.springframework.web.servlet.mvc.multiaction,它能将客户请求与处理方法名字映射起来,并触发正确的方法。MultiActionController事实上是AbstractController的一个子类,而在应用中,MultiActionController的实现方式有两种:其一是继承MultiActionController,其二是在配置文件中定义一个代理bean,由它来定义哪个控制器是多动作的。
         
          对于控制器中的多个方法,MultiActionController是通过MethodNameResolver来选择执行的。MultiActionController中的MethodNameResolver包括:
1.InternalPathMethodNameRe solver:这是MultiActionController缺省的MethodNameResolver,它是根据URL样式来解析方法名的,实际上就是根据URL中的“文件名”决定的,例如请求“ http://www.springframework.org/testing.view ”将令MultiActionController调用testing(HttpServletRequest,HttpServletResponse)方法。
2.ParameterMethodNameResol ver:根据请求中的参数来解析并执行方法名,例如请求“ http://www.springframework.org/index.view?testParam=testIt ”将令MultiActionController调用testIt(HttpServletRequest,  HttpServletResponse)方法。
3.PropertiesMethodNameReso lver:根据查询一个key/value列表来解析并执行方法名。
          对于多动作控制器的使用,我们看一个简单的例子,并利用Eclipse和Tomcat来完成。
          第一步,定义web.xml。web.xml放置在WEB-INF目录下。
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<? xml version = "1.0" encoding = "ISO-8859-1" ?>
< web-app xmlns = "http://java.sun.com/xml/ns/j2ee"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation = "http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_5.xsd"
   version = "2.5" >
< servlet >
      < servlet-name >dispatcherServlet</ servlet-name >
      < servlet-class >org.springframework.web.servlet.DispatcherServlet</ servlet-class >
      < init-param >
            < param-name >contextConfigLocation</ param-name >
            < param-value >/WEB-INF/dispatcherServlet-servlet.xml</ param-value >
      </ init-param >
      < load-on-startup >1</ load-on-startup >
</ servlet >
< servlet-mapping >
      < servlet-name >dispatcherServlet</ servlet-name >
      < url-pattern >*.do</ url-pattern >
</ servlet-mapping >
</ web-app >

          servlet-mapping定义所有以”.do”结尾开头的url请求都会被Spring  的 dispatcherServlet处理转发。默认情况下DispatcherServlet会读取<servlet- name>-servlet.xml文件的配置信息初始化,该文件中urlMapping的定义决定当前请求转发给哪个controller来处理,这里则定义了一个  dispatcherServlet-servlet.xml文件。
          第二步,定义  dispatcherServlet-servlet.xml文件

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<? xml version = "1.0" encoding = "UTF-8" ?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
"http://www.springframework.org/dtd/spring-beans-2.0.dtd">
< beans >
      < bean id = "urlMapping" class = "org.springframework.web.servlet.handler.SimpleUrlHandlerMapping" >
             < property name = "mappings" >
                  < props >
                        < prop key = "sample.do" >sampleMultiActionController</ prop >
                  </ props >
             </ property >
      </ bean >
      < bean id = "viewResolver" class = "org.springframework.web.servlet.view.InternalResourceViewResolver" >
             < property name = "viewClass" >
                  < value >org.springframework.web.servlet.view.InternalResourceView</ value >
             </ property >
             < property name = "prefix" >
                  < value >/WEB-INF/jsp/</ value >
             </ property >
             < property name = "suffix" >
                  < value >.jsp</ value >
             </ property >
      </ bean >
      
       
      < bean id = "sampleMultiActionController" class = "com.test.SampleMultiMActionController" >
            < property name = "methodNameResolver" >
                  < ref bean = "paraMethodResolver" />
            </ property >
      <!--viewName属性将依赖注入sampleMultiActionController类-->
            < property name = "viewName" >
                  < value >showme</ value >
            </ property >
      </ bean >
      
      < bean id = "paraMethodResolver" class = "org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver" >
            < property name = "paramName" value = "whichMethod" />
      </ bean >
</ beans >

         
          其中,urlMapping定义客户端的sample.do请求由名字为  sampleMultiActionControl ler  的控制器来处理,由于是多动作处理器,所以需要定义MethodNameResolver来通知web.xml中定义的dispatcherServlet应该调用sampleMultiActionControl ler  的哪个方法。这里用的是InternalPathMethodNameRe solver,本例说明了sampleMultiActionControl ler将在/WEB-INF/jsp/目录下的寻找一个showme.jsp文件作为显示model的视图。
          第三步,定义一个SampleMultiActionControl ler类,它是MultiActionController的子类,并有insert、update、delete三个,其源代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import java.io.IOException;
import java.util.*;
import javax.servlet.ServletException;
import org.apache.log4j.Logger;
import org.springframework.web.bind.*;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
org.springframework.web.servlet.mvc.multiaction.MultiActionController;
public class SampleMultiActionController  extends MultiActionController {
      private Logger logger=Logger.getLogger( this .getClass().getName());
      private String viewName;
      //依赖注入一个名为viewName的参数,例如一个JSP文件,作为展示model的视图
      public String getViewName (){
            return this .viewName;
      }
      public void setViewName (String viewName){
            this . viewName =viewName;
      }
      
      
      public ModelAndView insert(HttpServletRequest req,
                  HttpServletResponse res)  throws ServletRequestBindingException, IOException {
            Map model =  new HashMap();
            model.put( "dataList" "新增数据..." );
            return new ModelAndView(getViewName(),model);
      }
      
      public ModelAndView update(HttpServletRequest req,
                  HttpServletResponse res)  throws ServletRequestBindingException, IOException {
            Map model =  new HashMap();
            model.put( "dataList" "修改数据..." );
            return new ModelAndView(getViewName(),model);
      }
      
      public ModelAndView delete(HttpServletRequest req,
                  HttpServletResponse res)  throws ServletRequestBindingException, IOException {
            Map model =  new HashMap();
            model.put( "dataList" "删除数据..." );
            return new ModelAndView(getViewName(),model);
      }
}


          第四步,定义视图,此例中即是/WEB-INF/jsp/showme.jsp

?
1
2
3
4
5
6
7
8
9
10
<%@page c%>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core_rt" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
< html >
< head >MuiltiActionController示例</ head >
< body >
   < c:out value = "${model.dataList}" />
</ body >
</ html >


          第五步,测试。在Eclipse内启动Tomcat,在浏览器地址栏内分别输入,便可看到相应的页面输出信息:
http://localhost:8080/sample.do?whichMethod=insert
http://localhost:8080/sample.do?whichMethod=update
http://localhost:8080/sample.do?whichMethod=delete
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值