MVC模型中的控制器负责解析用户的输入信息,并将之变换处理后传入一个model,而这个 model则可能被呈现给发起请求的用户。Spring以非常抽象的方式体现了控制器的理念,从而开发人员在创建controller时将有多种选择。
Spring包含了3类controller:处理HTML表单的controller,基于command的controller,和向导风格的 controller。
Spring中Controller的基本类是org.springframework.web.servlet.mvc.Controller,这是一个相当简洁的接口,源代码如下:
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.WebApplicationObjectSupp ort
|_ 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的源代码:
从上述代码可以看出,AbstractorController的工作流程如下:
1.DispatcherServlet调用handleRequest方法;
2.检查被支持的方法(GET/POST/PUT之一),若不支持则抛出ServletException;
3.若需要发起一个session,则尝试获取一个session,若获取不到,则抛出ServletException;
4.根据cacheSeconds属性,设定缓存头标的数据;
5.调用受保护的抽象方法handleRequestInternal,这个方法应由AbstractController的子类提供实际的功能实现,并返回ModelAndView对象。
当开发人员使用AbstractController作为自己所设计的控制器的基类时,只需覆盖handleRequestInternal(HttpServletRequest, HttpServletResponse)方法即可,并返回一个ModelAndView对象,示例如下:
而配置文件中定义示例如下:
在本例中,若使这个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目录下。
servlet-mapping定义所有以”.do”结尾开头的url请求都会被Spring 的
dispatcherServlet处理转发。默认情况下DispatcherServlet会读取<servlet- name>-servlet.xml文件的配置信息初始化,该文件中urlMapping的定义决定当前请求转发给哪个controller来处理,这里则定义了一个 dispatcherServlet-servlet.xml文件。
第二步,定义 dispatcherServlet-servlet.xml文件
其中,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三个,其源代码如下:
第四步,定义视图,此例中即是/WEB-INF/jsp/showme.jsp
第五步,测试。在Eclipse内启动Tomcat,在浏览器地址栏内分别输入,便可看到相应的页面输出信息:
http://localhost:8080/sample.do?whichMethod=insert
http://localhost:8080/sample.do?whichMethod=update
http://localhost:8080/sample.do?whichMethod=delete
1 |
package org.springframework.web.servlet.mvc; |
2 |
import javax.servlet.http.HttpServletRequest; |
3 |
import javax.servlet.http.HttpServletResponse; |
4 |
import org.springframework.web.servlet.ModelAndView; |
5 |
public interface Controller
{ |
6 |
ModelAndView
handleRequest(HttpServletRequest request, HttpServletResponse response) throwsException; |
7 |
} |
1.
java.lang.Object
|_
*
*
*
*
*
*
01 |
package org.springframework.web.servlet.mvc; |
02 |
import javax.servlet.http.HttpServletRequest; |
03 |
import javax.servlet.http.HttpServletResponse; |
04 |
import javax.servlet.http.HttpSession; |
05 |
import org.springframework.web.servlet.ModelAndView; |
06 |
import org.springframework.web.servlet.support.WebContentGenerator; |
07 |
import org.springframework.web.util.WebUtils; |
08 |
public abstract class AbstractController extends WebContentGenerator implementsController
{ |
09 |
private boolean synchronizeOnSession
= false; |
10 |
public final void setSynchronizeOnSession(boolean synchronizeOnSession)
{ |
11 |
this.synchronizeOnSession
= synchronizeOnSession; |
12 |
} |
13 |
public final boolean isSynchronizeOnSession()
{ |
14 |
return synchronizeOnSession; |
15 |
} |
16 |
public finalModelAndView
handleRequest(HttpServletRequest request, HttpServletResponse response) |
17 |
throws Exception
{ |
18 |
checkAndPrepare(request,
response, this instanceof LastModified); |
19 |
if (this.synchronizeOnSession)
{ |
20 |
HttpSession
session = request.getSession(false); |
21 |
if (session
!= null)
{ |
22 |
Object
mutex = WebUtils.getSessionMutex(session); |
23 |
synchronized (mutex)
{ |
24 |
return handleRequestInternal(request,
response); |
25 |
} |
26 |
} |
27 |
} |
28 |
|
29 |
return handleRequestInternal(request,
response); |
30 |
} |
31 |
protected abstractModelAndView
handleRequestInternal(HttpServletRequest request, HttpServletResponse response) |
32 |
throws Exception; |
33 |
} |
从上述代码可以看出,AbstractorController的工作流程如下:
1.DispatcherServlet调用handleRequest方法;
2.检查被支持的方法(GET/POST/PUT之一),若不支持则抛出ServletException;
3.若需要发起一个session,则尝试获取一个session,若获取不到,则抛出ServletException;
4.根据cacheSeconds属性,设定缓存头标的数据;
5.调用受保护的抽象方法handleRequestInternal,这个方法应由AbstractController的子类提供实际的功能实现,并返回ModelAndView对象。
01 |
package samples; |
02 |
public class SampleController extends AbstractController
{ |
03 |
public ModelAndView
handleRequestInternal( |
04 |
HttpServletRequest
request, |
05 |
HttpServletResponse
response) throws Exception
{ |
06 |
ModelAndView
modelAndView = new ModelAndView("hello"); |
07 |
modelAndView.addObject("message", "Hello
World!"); |
08 |
return modelAndView; |
09 |
} |
10 |
} |
1 |
<bean id="sampleController" class="samples.SampleController"> |
2 |
<property name="cacheSeconds" value="120"/> |
3 |
</bean> |
2.
UrlFilenameViewControlle
org.springframework.web.servlet.mvc.multiaction,它能将客户请求与处理方法名字映射起来,并触发正确的方法。MultiActionController事实上是AbstractController的一个子类,而在应用中,MultiActionController的实现方式有两种:其一是继承MultiActionController,其二是在配置文件中定义一个代理bean,由它来定义哪个控制器是多动作的。
1.InternalPathMethodNameRe
2.ParameterMethodNameResol
3.PropertiesMethodNameReso
01 |
<?xml version="1.0" encoding="ISO-8859-1"?> |
02 |
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" |
03 |
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
04 |
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_5.xsd" |
05 |
version="2.5"> |
06 |
<servlet> |
07 |
<servlet-name>dispatcherServlet</servlet-name> |
08 |
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> |
09 |
<init-param> |
10 |
<param-name>contextConfigLocation</param-name> |
11 |
<param-value>/WEB-INF/dispatcherServlet-servlet.xml</param-value> |
12 |
</init-param> |
13 |
<load-on-startup>1</load-on-startup> |
14 |
</servlet> |
15 |
<servlet-mapping> |
16 |
<servlet-name>dispatcherServlet</servlet-name> |
17 |
<url-pattern>*.do</url-pattern> |
18 |
</servlet-mapping> |
19 |
</web-app> |
01 |
<?xml version="1.0" encoding="UTF-8"?> |
02 |
<!DOCTYPE
beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" |
03 |
"http://www.springframework.org/dtd/spring-beans-2.0.dtd"> |
04 |
<beans> |
05 |
<bean id="urlMapping"class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> |
06 |
<property name="mappings"> |
07 |
<props> |
08 |
<prop key="sample.do">sampleMultiActionController</prop> |
09 |
</props> |
10 |
</property> |
11 |
</bean> |
12 |
<bean id="viewResolver"class="org.springframework.web.servlet.view.InternalResourceViewResolver"> |
13 |
<property name="viewClass"> |
14 |
<value>org.springframework.web.servlet.view.InternalResourceView</value> |
15 |
</property> |
16 |
<property name="prefix"> |
17 |
<value>/WEB-INF/jsp/</value> |
18 |
</property> |
19 |
<property name="suffix"> |
20 |
<value>.jsp</value> |
21 |
</property> |
22 |
</bean> |
23 |
|
24 |
|
25 |
<bean id="sampleMultiActionController"class="com.test.SampleMultiMActionController"> |
26 |
<property name="methodNameResolver"> |
27 |
<ref bean="paraMethodResolver"/> |
28 |
</property> |
29 |
<!--viewName属性将依赖注入sampleMultiActionController类--> |
30 |
<property name="viewName"> |
31 |
<value>showme</value> |
32 |
</property> |
33 |
</bean> |
34 |
|
35 |
<bean id="paraMethodResolver"class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver"> |
36 |
<property name="paramName" value="whichMethod"/> |
37 |
</bean> |
38 |
</beans> |
01 |
import javax.servlet.http.HttpServletRequest; |
02 |
import javax.servlet.http.HttpServletResponse; |
03 |
import org.springframework.web.servlet.ModelAndView; |
04 |
import org.springframework.web.servlet.mvc.Controller; |
05 |
import java.io.IOException; |
06 |
import java.util.*; |
07 |
import javax.servlet.ServletException; |
08 |
import org.apache.log4j.Logger; |
09 |
import org.springframework.web.bind.*; |
10 |
import org.springframework.web.servlet.ModelAndView; |
11 |
import org.springframework.web.servlet.mvc.Controller; |
12 |
org.springframework.web.servlet.mvc.multiaction.MultiActionController; |
13 |
public class SampleMultiActionController extends MultiActionController
{ |
14 |
private Logger
logger=Logger.getLogger(this.getClass().getName()); |
15 |
private String
viewName; |
16 |
//依赖注入一个名为viewName的参数,例如一个JSP文件,作为展示model的视图 |
17 |
public String
getViewName (){ |
18 |
return this.viewName; |
19 |
} |
20 |
public void setViewName
(String viewName){ |
21 |
this.
viewName =viewName; |
22 |
} |
23 |
|
24 |
|
25 |
public ModelAndView
insert(HttpServletRequest req, |
26 |
HttpServletResponse
res) throwsServletRequestBindingException,
IOException { |
27 |
Map
model = new HashMap(); |
28 |
model.put("dataList", "新增数据..."); |
29 |
return new ModelAndView(getViewName(),model); |
30 |
} |
31 |
|
32 |
public ModelAndView
update(HttpServletRequest req, |
33 |
HttpServletResponse
res) throwsServletRequestBindingException,
IOException { |
34 |
Map
model = new HashMap(); |
35 |
model.put("dataList", "修改数据..."); |
36 |
return new ModelAndView(getViewName(),model); |
37 |
} |
38 |
|
39 |
public ModelAndView
delete(HttpServletRequest req, |
40 |
HttpServletResponse
res) throwsServletRequestBindingException,
IOException { |
41 |
Map
model = new HashMap(); |
42 |
model.put("dataList", "删除数据..."); |
43 |
return new ModelAndView(getViewName(),model); |
44 |
} |
45 |
} |
01 |
<%@page
c%> |
02 |
<%@
taglib prefix="c" uri="http://java.sun.com/jstl/core_rt" %> |
03 |
<%@
taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt"%> |
04 |
<!DOCTYPE
HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> |
05 |
<html> |
06 |
<head>MuiltiActionController示例</head> |
07 |
<body> |
08 |
<c:out value="${model.dataList}"/> |
09 |
</body> |
10 |
</html> |
http://localhost:8080/sample.do?whichMethod=insert
http://localhost:8080/sample.do?whichMethod=update
http://localhost:8080/sample.do?whichMethod=delete
本文深入探讨Spring MVC框架中Controller的设计理念及其实现方式,包括基本的Controller接口、AbstractController类及其工作流程,还介绍了MultiActionController如何实现多动作处理。
3962

被折叠的 条评论
为什么被折叠?



