-大部分素材来自于《Programming Jakarta Struts》一书
lzasp800(原作)
copy form
www.CSDN.net 2004-05-05
关键字 Struts MVC
1. Struts 简介
Struts 是一个技术框架,由Craig R. McClanahan编写,并且在2000 年的时候捐献给了ASF,目前,有很多组织和
个人参与Struts 框架的开发,使得Struts保持高速成长,同时,利用Struts开发的应用越来越多,使其成为web 应用
MVC 模式中VC 部分事实上的标准。
1.1 Web技术历史
1.1.1 CGI
web 应用开发中历史上,CGI(common gateway interface)是最早使用的一种技术,通过为不同的平台,不同的
web server 编写插件编写应用接口,来满足通过web方式编写应用的需求。当时流行的方式包含NSAPI/ISAPI,使
用Perl来编写CGI 程序。CGI最大的问题就是线程并发的问题,当时给很多人的感觉是CGI 访问速度慢,其主要原
因是应用程序所编写的CGI 没有考虑多线程。
1.1.2 Servlet
作为一种跨平台语言的
服务器端技术,其一经产生就备受瞩目,采用Servlet开发的应用,不用考虑平台,多
线程等让人头疼的问题,使得开发人员专注于业务逻辑的实现,大大解放了生产力。但是,在Servlet中嵌入html
无疑是开发人员的噩梦,与同时期微软的ASP 相比,Servlet 在开发效率方面让人不敢恭维。
1.1.3 Java Server Pages
JSP从很大程度上时参考了ASP的想法,使得采用Java 语言开发服务器端应用非常容易,同时因为java与生俱来的
跨平台、安全性、易用性优势,当然,还有开发人员的高工资J,使得JSP 逐渐在Web 服务器端应用开发中占据了主
流位置。
2. Struts 安装
Struts作为一个J2EE 框架,很容易和你的web 应用结合起来,你仅仅需要作以下几个步骤:
1、 下在Struts1.1 二进制压缩包,将压缩包解压到%STRUTS_HOME%目录,目录结构如下如示:
2、 建立你的标准web 应用程序,所谓标准应用程序是指在web 应用程序的根目录下有一个WEB-INFO目录,WEB-INF
下有classes,lib目录,classes下面有个web.xml文件。本文后续假设你的web 应用在%WEB_ROOT%目录下。
3、 将%STRUTS_HOME%/lib下所有文件copy 到%WEB_ROOT%/WEB-INF/lib 下。
4、 配置%WEB_ROOT%/WEB-INF/classes/web.xml以满足Struts需要,具体如下:
1、 在配置文件中映射ActionServlet,ActionServlet用于接受所有访问者的请求。在Struts应用中,所有对
应用程序的请求,都会被WEB SERVER 定向到ActionServlet进行统一控制、分配处理,ActionServlet可以
看作是Struts框架的核心,枢纽。
<web-app>
<servlet>
<servlet-name>controller</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
</servlet>
</web-app>
2、 配置servlet映射,通过servlet映射可以将用户访问web应用的扩展名映射到具体处理的servlet,例如,
将所有以.do为扩展名的页面的请求交给ActionServlet处理。
<web-app>
<servlet>
<servlet-name>controller</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>controller</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
另外,也可以采用如下方式进行映射,该方式将所有对/action/目录下文件的访问请求交给ActionServlet处
理。
<web-app>
<servlet>
<servlet-name> controller </servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>controller</servlet-name>
<url-pattern>>/action/*</url-pattern>
</servlet-mapping>
</web-app>
3、 配置ActionServlet的初始化参数,Struts1.1 有一些指定的初始化参数,用于指明Struts应用所需要的配
置文件,debug等级等。
<web-app>
<servlet>
<servlet-name>controller</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<init-param>
<param-name>host</param-name>
<param-value>localhost</param-value>
</init-param>
<init-param>
<param-name>port</param-name>
<param-value>7001</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name> controller </servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
初始化参数利用<init-param>进行配置,配置采用名称-值对的方式,一个<param-name>对应一个<param-value>,
初始化参数可以任意定义,例如host,port,但是有一些在Struts1.1中是具有特别意义的,列举如下:
表2-1. Struts1.1 中用到的初始化参数
参数名 含义/默认值
config
以相对路径的方式指明Struts应用程序的配置文件位置。如不
设置,则默认值为
/WEB-INF/struts-config.xml。
config/sub1 以相对路径的方式指明子应用程序的配置文件位置,一般来说,很少用到子应用程序,在此不多描述。
debug 设置Servlet 的debug级别,控制日志记录的详细程度。默认为0,记录相对最少的日志信息。
detail
设置Digester的debug级别,Digester是Struts框架所使用的用来解析xml配置文件的一个框架,通过该
设置,可以查看不同详细等级的解析日志。默认为0,记录相对最少的日志信息。
4、 配置标签库,标签库是Struts 自带的一些组件库,采用JSP 规范中Tag-lib的方式供大家使用,正
是因为存在这么丰富的标签库,使得采用Struts的开发才显得这么方便,高效。
<web-app>
<servlet>
<servlet-name>controller</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<init-param>
<param-name>host</param-name>
<param-value>localhost</param-value>
</init-param>
<init-param>
<param-name>port</param-name>
<param-value>7001</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>controller</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<taglib>
<taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-html.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-bean.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/WEB-INF/struts-logic.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-logic.tld</taglib-location>
</taglib>
</web-app>
标签库采用<taglib>定义,<taglib>含有两个子元素,<taglib-uri>和<taglib-location>,<taglib-uri>
用户定义标签库的唯一表示符,可以理解为名字,以后要在jsp页面中使用这个标签库,靠的就是它。
<taglib-location>指明标签库存在的物理路径,当然,和配置文件一样,也是相对路径。
5、 设置welcome文件列表(可选步骤)
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
6、 设置错误处理(可选步骤),通常的http访问异常包含404 Not Found和500 Internal Error,为了
提供给用户更为友好的显示,可以做如下配置:
<web-app>
<error-page>
<error-code>404</error-code>
<location>/common/404.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/common/500.jsp</location>
</error-page>
</web-app>
通过如上配置,当用户访问应用中不存在的页面时,将会将用户导向到/common/404.jsp页面。同样地,
当出现异常错误时,将会把/common/500.jsp显示给用户。
7、 最后,一个完整的web.xml示例如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<servlet>
<servlet-name>storefront</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>3</param-value>
</init-param>
<init-param>
<param-name>detail</param-name>
<param-value>3</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>storefront</servlet-name>
<url-pattern>/action/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<error-page>
<error-code>404</error-code>
<location>/common/404.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/common/500.jsp</location>
</error-page>
<taglib>
<taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-html.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-bean.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/WEB-INF/struts-logic.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-logic.tld</taglib-location>
</taglib>
</web-app>
1、 到此为止,Struts 的开发环境安装算是告一段落。
1. Struts 框架
在介绍Struts 框架之前,先来看看web 开发的两种模式,这两种模式自JSP 开发流行以来,就争论不断,它们
分别是JSP Model 1和JSP Model 2。
1.1 JSP Model 1
下图是JSP Model 1 的构架示意图:
用户通过
浏览器之间访问web 应用的JSP 页面, JSP 提供UI显示,JavaBeans 处理
数据库访问和业务逻辑。这种开
发方式最大的优势是直接、简单,对于小型应用,可以很方便、快速地进行开发。
1.2 JSP Model 2
下图是JSP Model 2 的构架示意图:
JSP Model 2 和JSP Model 1 最大的区别是引入了MVC 模式的概念,即M(Model:业务逻辑),V(View:
系统
UI),C(Controller:控制)分离,用户的所有请求提交给Controller,由Controller进行统一分配,并且采用推的方式将不
同的UI显示给用户。这样做得好处是:
1、 可以统一控制用户的行为,例如在Controller 中添加统一日志记录等功能是非常方便的。
2、 职责分离,有利于各部分的维护。用户不直接访问分散的UI,这样可以通过配置文件或则流程定义的方式,在
不同的环节、时间将不同的页面推向给用户。
1.3 Struts
通过了解JSP Model 1和JSP Model 2,我想大家心里都已经有了选择,在这里,我不想说哪一种构架更好,在不
同的环境中,使用恰到好处的技术才是最好的。普遍来说,MVC 分离是个不错的选择。
Struts 框架正是MVC 分离的一个杰出作品。首先我们来看一下Struts1.1的UML图,以便于我们对Struts 有个全
局的了解:
先不用急着看懂这张图,在下面的学习过程中,我们会慢慢地了解这张图中各个组件的含义。
接下来,我们从MVC 的角度对Struts框架进行探索。
1.3.1 Controller
首先介绍MVC 中的C,上面提到了,JSP Model 1 和JSP Model 2 最大的却别就是C,那么在Struts中,这个C是
什么呢?他是如何实现的呢?下面我们再来看看这个图:
这是JSP Model 2
的构架图,也是Struts 的构架图,Struts 使用一个Servlet 作为Controller,处理用户的请求,并分派给Model 进行业
务处理,在合适的时候将合适的View 推向给用户。这个Servlet 是org.apache.struts.action.ActionServlet
或其子类。ActionServlet 类扩展自javax.servlet.http.HttpServlet 类,其职责是将http请求提交给合
适的处理器(Processor) 进行处理。关于处理器我们在稍后会介绍, 是
org.apache.struts.action.RequestProcessor 或其子类的一个实例。
1.3.1.1 Controller(控制器)机制
J2EE 的前端控制器(Front Controller)设计模式中利用一个前端控制器来接受所有客户请求,为应用提供一个中心控制点,
在该控制点上,可以很方便地添加一些全局性的,如加密、国际化、日志等通用操作。Controller 的实现机制正是建立在前端
控制器的设计模式基础上。
前面我们介绍过,Struts的控制器拥有一些职责,其中最主要的是以下几个:
?/SPAN> 接收客户请求。
?/SPAN> 映射请求到指定的业务操作。
?/SPAN> 获取业务操作的结果并以有效的方式提供给客户。
?/SPAN> 根据业务操作的结果和当前的状态把不同的UI推向给客户。
在Struts 框架中,控制器中不同的组件负责不同的控制职责,下图是Struts框架中关于控制器部分的一个组件图:
在上图中,很明显地可以看出,ActionServlet
处于核心位置,那么,我们就先来了解一下ActionServlet。
1.3.1.2 ActionServlet 类
org.apache.struts.action.ActionServlet在Struts应用程序中扮演接收器的角色,所有客户端的请求在被其它类处理
之前都得通过ActionServlet 的控制。
当 ActionServlet 的实例接收到一个HTTP请求,不管是通过get方法或post方法,ActionServlet的process( )方法被
调用并用以处理客户请求。process( )方法实现显示如下:
protected void process(HttpServletRequest request,HttpServletResponse response)
throws IOException, ServletException {
RequestUtils.selectApplication( request, getServletContext( ) );
getApplicationConfig( request ).getProcessor( ).process( request, response );
}
该方法的实现很简单,RequestUtils.selectApplication( request, getServletContext( ) );语句是
用来根据用户访问的上下文路径来选择处理的应用,如果你只有一个Struts配置文件,就表示你只有一个Struts应用。
关于如何建立多个Struts 应用,本
教程不作详细讲解,请参考相应资料。
getApplicationConfig( request ).getProcessor( ).process( request, response );语句用来获取一
个处理器,并将客户请求提交给处理器处理。
1.3.1.3 Struts初始化处理流程
根据在web.xml中配置的初始化参数,Servlet容器将决定在在容器的第一次启动,或第一次客户请求ActionServlet的
时机加载ActionServlet ,不管哪种方式加载,和其它Servlet一样,ActionServlet的init( )方法将被调用,开始初始化
过程。让我们来看看在初始化过程中将发生些什么,理解了这些,对于我们debug和扩展自己的应用更加得心应手。
1 初始化框架的内部消息绑定,这些消息用来输出提示,警告,和错误信息到日志文件中。
org.apache.struts.action.ActionResources 用来获取内部消息;
2 加载web.xml中定义的不同参数,用以控制ActionServlet的不同行为,这些参数包括
config, debug, detail, and convertNull ;
3 加载并初始化web.xml中定义的servlet 名称和servlet映射信息。通过初始化,框架的各种DTD被注册,DTD用
来在下一步校验配置文件的有效性;
4、 为默认应用加载并初始化Struts配置文件,配置文件即初始化参数config 指定的文件。默认配置文件被解析,
产生一个ApplicationConfig 对象存于ServletContext 中。可以通过关键字
org.apache.struts.action.APPLICATION 从ServletContext中获取ApplicationConfig;
5 Struts配置文件中指定的每一个消息资源都被加载,初始化,并存在ServletContext的合适区域(基于每个
message-resources元素的key属性),如果key 属性没有设置,则为org.apache.struts.action.MESSAGE;
6 Struts配置文件中声明的每一个数据源被加载并且初始化,如果没有配置数据源,这一步跳过;
7 加载并初始化Struts配置文件中指定的插件。每一个插件的init()方法被调用;
8 当默认应用加载完成,init()方法判断是否有应用模块需要加载,如果有,重复步骤4—7万成应用模块的加载。
下图是对上面文字说明的图形化表示:
RequestProcessor 类
前面提到过,当ActionServlet接收到客户请求后,会进行一连串的初始化操作,然后,就会将客户请求转交给合适的
处理器进行处理,这个合适的处理器就是org.apache.struts.action.RequestProcessor或其子类的一个实例(根据Struts
配置文件中的配置)。提供了默认实现,如果需要自定义这些行为,可以重载这个类定义自己的处理行为,当你想要自定义操
作时,Struts推荐你重载这个类而不是ActionServlet。
下面的代码片断提供了RequestProcessor的默认行为实现代码:
public void process(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
// Wrap multipart requests with a special wrapper
request = processMultipart(request);
// Identify the path component we will use to select a mapping
String path = processPath(request, response);
if (path == null) {
return;
}
if (log.isInfoEnabled( )) {
log.info("Processing a '" + request.getMethod( ) +
"' for path '" + path + "'");
}
// Select a Locale for the current user if requested
processLocale(request, response);
// Set the content type and no-caching headers if requested
processContent(request, response);
processNoCache(request, response);
// General-purpose preprocessing hook
if (!processPreprocess(request, response)) {
return;
}
// Identify the mapping for this request
ActionMapping mapping = processMapping(request, response, path);
if (mapping == null) {
return;
}
// Check for any role required to perform this action
if (!processRoles(request, response, mapping)) {
return;
}
// Process any ActionForm bean related to this request
ActionForm form = processActionForm(request, response, mapping);
processPopulate(request, response, form, mapping);
if (!processValidate(request, response, form, mapping)) {
return;
}
// Process a forward or include specified by this mapping
if (!processForward(request, response, mapping)) {
return;
}
if (!processInclude(request, response, mapping)) {
return;
}
// Create or acquire the Action instance to process this request
Action action = processActionCreate(request, response, mapping);
if (action == null) {
return;
}
// Call the Action instance itself
ActionForward forward =
processActionPerform(request, response, action, form, mapping);
// Process the returned ActionForward instance
processActionForward(request, response, forward);
}
接下来,让我们一步一步地了解process()方法到底做了什么。
1、 调用processMultipart( )方法。如果HttpServletRequest是POST方式,且请求为multipart/form-data ,
Struts框架将请求对象包装成处理multipart 请求专用的请求对象,否则,只是简单地返回原有的请求对象。一
般来说,除非需要处理文件上传,否则不用关心multipart 功能的具体细节。
2、 调用processPath( ) 方法,该方法用来从请求URL中获应用取路径部分。获取到的信息在稍后的步骤中用于
选择合适的Struts Action调用。
3、 调用processLocale( ) 方法处理一些国际化的事务。
4、 调用方法来决定processContent( )请求的content type
编码(encoding)方式。content type可以配合在配置
文件中,也可以在jsp文件中配置,默认为text/html。
5、 根据noCache属性的设置调用processNoCache( ) 方法,如果noCache设置为true。则添加合适的响应头到响
应对象中,使得页面保留在浏览器的Cache中。这些响应头包含Pragma, Cache-Control, 和Expires 。
6、 调用processPreprocess( )方法,这个方法在这儿设置一个钩子,方法的默认实现只是简单地返回true,这样
给了自定义处理器的开发者提供了一个合适的地方让你添加自己的业务逻辑。因为这个方法在调用Action之前
被调用,如果你重载这个方法,只需要返回false,则Action就不会被调用。例如,你可以重载这个方法用户检
查客户session,如果不通过就返回false。
7、 调用processMapping( )方法,根据客户请求信息中的path 信息来决定是否返回ActionMapping对象实例。如
果不能够找到path 的映射,则客户将会得到一个error 响应。
8、 通过调用processRoles( )方法检查是否为Action配置了安全角色。如果配置了角色要求,则请求对象的
isUserInRole( )方法被调用,如果用户属于这些角色,则客户会得到显示一个error 响应。
9、 调用processActionForm( )方法检查是否存在为ActionMapping配置的ActionForm 。如果存在,则在有效区
域内查找是否存在该ActionForm 的实例,存在,则复用,不存在,则创建一个实例。然后将实例保存与再配置
文件中配置好的有效区域(request,session,application)内,并用Action元素的name属性作为该实例的关键字。
10、 调用processPopulate( )方法,如果存来存在为ActionMapping配置的ActionForm,则封装请求对象中的数据
到ActionForm 中,在进行封装之前,先调用ActionForm 的reset( )方法进行属性值的默认化。
11、 调用processValidate( )方法。如果ActionForm被配置好,并且action元素的属性validate被设
置为true ,则进一步调用validate( )方法进行规则校验。如果validate( )方法校验
失败,就会保存一
个ActionErrors 对象到请求区域中,请求将会自动重定向到action映射的input属性所指定的页面中。如
果校验通过或在action 映射中没有配置ActionForm,则继续处理请求。
12、 根据action 映射是否配置了forward属性或include属性来决定下一步操作。如果配置了任意一个,则相应
地调用RequestDispatcher对象的forward( )方法或include( )方法,调用后,对客户请求的处理结束。否则,
继续处理请求。
13、 调用processActionCreate( )方法创建或获取一个Action对象实例处理请求。processActionCreate( )方法会
在缓存中查找是否存在已经创建好的Action实例,如果存在,则复用,否则,则重新创建并将其村于缓存中。
14、 调用processActionPerform( )方法,该方法用于在一个try/catch 代码块中调用action 实例的execute( )方法,
这样确保action 的execute( )方法一旦发生执行异常能够被RequestProcessor捕获。
15、 调用processActionForward( )方法,并传入action的execute( )方法所返回的ActionForward对象实例,方
法通过检查ActionForward对象实例,决定采用redirect或forword方式进行重定向。究竟采用redirect还是
forword取决于forward元素的redirect属性值。
扩展RequestProcessor
如果不想利用Struts 提供的处理器,则可以扩展它。通过两个步骤即可实现:
1、 创建一个新的类,该类必须是org.apache.struts.action.RequestProcessor 的子类;
2、 在Struts配置文件中进行声明,例如:(粗体部分为你的自定义处理器类)
<controller
contentType="text/html;charset=UTF-8"
debug="3"
locale="true"
nocache="true"
processorClass="com.struts.framework.CustomRequestProcessor"/>
1.1.1.1 Action 类
如果说ActionServlet 是Struts 框架的入口,RequestProcessor 是消化过滤系统,则
org.apache.struts.action.Action 类可以说是整个框架的心脏。他是客户请求和业务操作的连接桥,也可以将其看
作是业务操作的客户代理。
在前面对ReqeustProcessor 类的学习中,我们了解到一旦确定并得到了一个action 实例,ReqeustProcessor
会调用action 的execute()方法处理客户请求,你需要扩展action 类,并实现它的execute()方法,在此方法中添
加你自己的处理代码。下面给出是一个示例,这个action 用来处理用户的登录请求:
package com.oreilly.struts.storefront.security;
import java.util.Locale;
import javax.servlet.http.*;
import org.apache.struts.action.*;
import com.oreilly.struts.storefront.customer.view.UserView;
import com.oreilly.struts.storefront.framework.exceptions.BaseException;
import com.oreilly.struts.storefront.framework.UserContainer;
import com.oreilly.struts.storefront.framework.StorefrontBaseAction;
import com.oreilly.struts.storefront.framework.util.IConstants;
import com.oreilly.struts.storefront.service.IStorefrontService;
/**
* Implements the logic to authenticate a user for the Storefront application.
*/
public class LoginAction extends StorefrontBaseAction {
/**
* Called by the controller when the user attempts to log in to the
* Storefront application.
*/
public ActionForward execute( ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response )
throws Exception{
// The email and password should have already been validated by the ActionForm
String email = ((LoginForm)form).getEmail( );
String password = ((LoginForm)form).getPassword( );
// Log in through the security service
IStorefrontService serviceImpl = getStorefrontService( );
UserView userView = serviceImpl.authenticate(email, password);
// Create a single container object to store user data
UserContainer existingContainer = null;
HttpSession session = request.getSession(false);
if ( session != null ){
existingContainer = getUserContainer(request);
session.invalidate( );
}else{
existingContainer = new UserContainer( );
}
// Create a new session for the user
session = request.getSession(true);
// Store the UserView in the container and store the container in the session
existingContainer.setUserView(userView);
session.setAttribute(IConstants.USER_CONTAINER_KEY, existingContainer);
// Return a Success forward
return mapping.findForward(IConstants.SUCCESS_KEY);
}
}
1.1.1.1.1 Action类缓冲
Action 类被设计为线程安全的,在每个应用中每个Action 类只会被实例化一次,供所有线程共享。
RequestProcessor 利用一个HashMap 用来保存Action 实例。
思考题?
所有线程共享一个Action 类实例意味着什么?我们在编程中需要注意些什么呢?
1.1.1.2 ActionForward类
从前面的介绍我们已经了解到,Action 的execute( )方法返回一个ActionForward 对象。ActionForward 对
象是JSP页面、Java servlet 等web资源的抽象表现。
ActionForward 的用途是为了减少应用和物理资源(JSP 页面,Java servlet)的耦合,物理资源只需要在配置文件中指
定(利用name,path 属性和forward 元素的redirect 属性),而不是在代码中指定。RequestDispatcher 利用
ActionForward来执行重定向操作。
要在Action 中返回一个ActionForward 对象,你可以动态地创建一个ActionForward 对象,不过更为通用的解
决方案是,通过在Struts配置文件中进行action 映射,然后通过关键字去查找一个ActionForward 。下面是代码示例:
return mapping.findForward( "Success" );
上面的代码中,"Success"作为参数被传递到ActionMapping的findFoward( )方法中,findFoward( )方法在
Struts配置文件的global-forwards 区域,以及被调用的action 的forward元素中查找名字和"Success"相匹配的元
素。下面是action 元素中的forward示例:
<action
input="/security/signin.jsp"
name="loginForm"
path="/signin"
scope="request"
type="com.oreilly.struts.storefront.security.LoginAction"
validate="true">
<forward name="Success" path="/index.jsp" redirect="true"/>
<forward name="Failure" path="/security/signin.jsp" redirect="true"/>
</action>
1.1.1.1 Action 和业务逻辑
思考题?
Action属于MVC 中的Controller还是Model?为什么?
1.1.1.2 使用Struts内置的Action
Struts1.1 框架的org.apache.struts.actions 包中包含了5 个内置的Action,用来执行一些通用的操作,你可以把
它们用在你的项目中,以节省你的开发时间。接下来我们分别介绍这5个内置的Action。
1.1.1.2.1 org.apache.struts.actions.ForwardAction 类
很多情况下,你仅仅需要引导客户从一个JSP 页面跳转到另外一个JSP页面,按照我们通常的做法,可以做一个链接让用户
直接访问要跳转到的页面。但是MVC 模式不推荐你这么做,因为,Controller 的职责就是接收所有的客户请求,然后将
客户请求提交给一个合适的模块进行处理,并将合适的UI推给用户,如果直接方式JSP页面,则跳过了Controller 的控
制,则无法享受Controller 所提供的优点。为了解决这个问题,并且不用你去为了执行一个简单的重定向操作而创建一
个Action 类 ,Struts 框架提供了ForwardAction 类,这个Action 只是简单地执行一个重定向操作,重定向的目的地
通过parameter 属性配置。要使用ForwardAction 类,只需要在Struts 配置文件中将Action 的type 属性配置为
org.apache.struts.actions.ForwardAction:
<action
input="/index.jsp"
name="loginForm"
path="/viewsignin"
parameter="/security/signin.jsp"
scope="request"
type="org.apache.struts.actions.ForwardAction"
validate="false"/>
</action>
当你访问/viewsignin 的时候,就会自动重定向到/security/signin.jsp。