﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-Sung in Blog-文章分类-Ｓｔｒｕｔｓ</title><link>http://www.blogjava.net/qq13367612/category/4133.html</link><description>&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font class="subhead" size=3&gt;&lt;b&gt;一些技术文章 &amp; 一些生活杂碎&lt;/b&gt;&lt;/font&gt;</description><language>zh-cn</language><lastBuildDate>Tue, 27 Feb 2007 08:38:57 GMT</lastBuildDate><pubDate>Tue, 27 Feb 2007 08:38:57 GMT</pubDate><ttl>60</ttl><item><title>深入Struts 1.1(分离struts配置文件)</title><link>http://www.blogjava.net/qq13367612/articles/18978.html</link><dc:creator>Sung</dc:creator><author>Sung</author><pubDate>Wed, 09 Nov 2005 06:16:00 GMT</pubDate><guid>http://www.blogjava.net/qq13367612/articles/18978.html</guid><wfw:comment>http://www.blogjava.net/qq13367612/comments/18978.html</wfw:comment><comments>http://www.blogjava.net/qq13367612/articles/18978.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qq13367612/comments/commentRss/18978.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qq13367612/services/trackbacks/18978.html</trackback:ping><description><![CDATA[<BLOCKQUOTE>作为基于MVC模式的Web应用最经典框架，Struts已经正式推出了1.1版本，该版本在以往版本的基础上，提供了许多激动人心的新功能。本文就将带你走进Struts 1.1去深入地了解这些功能。</BLOCKQUOTE>
<P><B xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:h="http://www.w3.org/1999/xhtml" xmlns:dw="http://www.ibm.com/developerworks/">说明：</B>希望本文的读者能有一定的Struts使用基础。 </P>
<P><A name=1><SPAN class=atitle2>Model 2</SPAN></A><BR></P>
<P>Struts是基于Model 2之上的，而Model 2是经典的MVC（模型－视图－控制器）模型的Web应用变体，这个改变主要是由于网络应用的特性--HTTP协议的无状态性引起的。Model 2的目的和MVC一样，也是利用控制器来分离模型和视图，达到一种层间松散耦合的效果，提高系统灵活性、复用性和可维护性。在多数情况下，你可以将Model 2与MVC等同起来。</P>
<P>下图表示一个基于Java技术的典型网络应用，从中可以看出Model 2中的各个部分是如何对应于Java中各种现有技术的。</P>
<P><A name=N1004E><B></B></A><BR><IMG alt="" src="http://www-128.ibm.com/developerworks/cn/java/l-struts1-1/image001.gif" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:h="http://www.w3.org/1999/xhtml" xmlns:dw="http://www.ibm.com/developerworks/"> </P>
<P>在利用Model 2之前，我们是把所有的表示逻辑和业务逻辑都集中在一起（比如大杂烩似的JSP），有时也称这种应用模式为Model 1，Model 1的主要缺点就是紧耦合，复用性差以及维护成本高。</P>
<P><A name=2><SPAN class=atitle2>Struts 1.1 和Model 2</SPAN></A><BR></P>
<P>既然Struts 1.1是基于Model 2之上，那它的底层机制也就是MVC，下面是Struts 1.1中的MVC实现示意图：</P>
<P><A name=N10068><B></B></A><BR><IMG alt="" src="http://www-128.ibm.com/developerworks/cn/java/l-struts1-1/image002.jpg" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:h="http://www.w3.org/1999/xhtml" xmlns:dw="http://www.ibm.com/developerworks/"> </P><I xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:h="http://www.w3.org/1999/xhtml" xmlns:dw="http://www.ibm.com/developerworks/">图解说明：其中不同颜色代表MVC的不同部分：红色（控制器）、紫色（模型）和绿色（视图） </I>
<P>首先，控制器（ActionServlet）进行初始化工作，读取配置文件（struts-config.xml），为不同的Struts模块初始化相应的ModuleConfig对象。比如配置文件中的Action映射定义都保存在ActionConfig集合中。相应地有ControlConfig集合、FormBeanConfig集合、ForwardConfig集合和MessageResourcesConfig集合等。</P>
<P><I xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:h="http://www.w3.org/1999/xhtml" xmlns:dw="http://www.ibm.com/developerworks/"><B>提示：</B>模块是在Struts 1.1中新提出的概念，在稍后的内容中我们将详细介绍，你现在可以简单地把模块看作是一个子系统，它们共同组成整个应用，同时又各自独立。Struts 1.1中所有的处理都是在特定模块环境中进行的。模块的提出主要是为了解决Struts 1.0中单配置文件的问题。 </I></P>
<P>控制器接收HTTP请求，并从ActionConfig中找出对应于该请求的Action子类，如果没有对应的Action，控制器直接将请求转发给JSP或者静态页面。否则控制器将请求分发至具体Action类进行处理。</P>
<P>在控制器调用具体Action的execute方法之前，ActionForm对象将利用HTTP请求中的参数来填充自己（可选步骤，需要在配置文件中指定）。具体的ActionForm对象应该是ActionForm的子类对象，它其实就是一个JavaBean。此外，还可以在ActionForm类中调用validate方法来检查请求参数的合法性，并且可以返回一个包含所有错误信息的ActionErrors对象。如果执行成功，ActionForm自动将这些参数信息以JavaBean（一般称之为form bean）的方式保存在Servlet Context中，这样它们就可以被其它Action对象或者JSP调用。</P>
<P>Struts将这些ActionForm的配置信息都放在FormBeanConfig集合中，通过它们Struts能够知道针对某个客户请求是否需要创建相应的ActionForm实例。</P>
<P>Action很简单，一般只包含一个execute方法，它负责执行相应的业务逻辑，如果需要，它也进行相应的数据检查。执行完成之后，返回一个ActionForward对象，控制器通过该ActionForward对象来进行转发工作。我们主张将获取数据和执行业务逻辑的功能放到具体的JavaBean当中，而Action只负责完成与控制有关的功能。遵循该原则，所以在上图中我将Action对象归为控制器部分。</P>
<P><I xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:h="http://www.w3.org/1999/xhtml" xmlns:dw="http://www.ibm.com/developerworks/"><B>提示：</B>其实在Struts 1.1中，ActionMapping的作用完全可以由ActionConfig来替代，只不过由于它是公共API的一部分以及兼容性的问题得以保留。ActionMapping通过继承ActionConfig来获得与其一致的功能，你可以等同地看待它们。同理，其它例如ActionForward与ForwardConfig的关系也是如此。 </I></P>
<P>下图给出了客户端从发出请求到获得响应整个过程的图解说明。</P>
<P><A name=N1009B><B></B></A><BR><IMG alt="" src="http://www-128.ibm.com/developerworks/cn/java/l-struts1-1/image003.jpg" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:h="http://www.w3.org/1999/xhtml" xmlns:dw="http://www.ibm.com/developerworks/"> </P>
<P>下面我们就来详细地讨论一下其中的每个部分，在这之前，先来了解一下模块的概念。</P>
<P><A name=3><SPAN class=atitle2>模块</SPAN></A><BR></P>
<P>我们知道，在Struts 1.0中，我们只能在web.xml中为ActionServlet指定一个配置文件，这对于我们这些网上的教学例子来说当然没什么问题，但是在实际的应用开发过程中，可能会有些麻烦。因为许多开发人员都可能同时需要修改配置文件，但是配置文件只能同时被一个人修改，这样肯定会造成一定程度上的资源争夺，势必会影响开发效率和引起开发人员的抱怨。</P>
<P>在Struts 1.1中，为了解决这个并行开发的问题，提出了两种解决方案： 
<OL xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:h="http://www.w3.org/1999/xhtml" xmlns:dw="http://www.ibm.com/developerworks/">
<LI>多个配置文件的支持 
<LI>模块的支持 </LI></OL>
<P></P>
<P>支持多个配置文件，是指你能够为ActionServlet同时指定多个xml配置文件，文件之间以逗号分隔，比如Struts提供的MailReader演示例子中就采用该种方法。</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc border=1>
<TBODY>
<TR>
<TD><PRE><CODE>
  &lt;!-- Action Servlet Configuration --&gt;
  &lt;servlet&gt;
	&lt;servlet-name&gt;action&lt;/servlet-name&gt;
	&lt;servlet-class&gt;org.apache.struts.action.ActionServlet&lt;/servlet-class&gt;
	&lt;init-param&gt;
		&lt;param-name&gt;config&lt;/param-name&gt;
		&lt;param-value&gt;/WEB-INF/struts-config.xml, /WEB-INF/struts-config-registration.xml&lt;/param-value&gt;
	&lt;/init-param&gt; 
	&lt;load-on-startup&gt;1&lt;/load-on-startup&gt;
  &lt;/servlet&gt;

</CODE></PRE></TD></TR></TBODY></TABLE>
<P>这种方法可以很好地解决修改冲突的问题，不同的开发人员可以在不同的配置文件中设置自己的Action、ActionForm等等（当然不是说每个开发人员都需要自己的配置文件，可以按照系统的功能模块进行划分）。但是，这里还是存在一个潜在的问题，就是可能不同的配置文件之间会产生冲突，因为在ActionServlet初始化的时候这几个文件最终还是需要合并到一起的。比如，在struts-config.xml中配置了一个名为success的&lt;forward&gt;，而在struts-config-registration.xml中也配置了一个同样的&lt;forward&gt;，那么执行起来就会产生冲突。</P>
<P>为了彻底解决这种冲突，Struts 1.1中引进了模块（Module）的概念。一个模块就是一个独立的子系统，你可以在其中进行任意所需的配置，同时又不必担心和其它的配置文件产生冲突。因为前面我们讲过，ActionServlet是将不同的模块信息保存在不同的ModuleConfig对象中的。要使用模块的功能，需要进行以下的准备工作：</P>
<P>1、为每个模块准备一个配置文件</P>
<P>2、配置web.xml文件，通知控制器</P>
<P>决定采用多个模块以后，你需要将这些信息告诉控制器，这需要在web.xml文件进行配置。下面是一个典型的多模块配置：</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc border=1>
<TBODY>
<TR>
<TD><PRE><CODE>
&lt;init-param&gt;
	&lt;param-name&gt;config&lt;/param-name&gt;
	&lt;param-value&gt;/WEB-INF/struts-config.xml&lt;/param-value&gt;
&lt;/init-param&gt;
&lt;init-param&gt;
	&lt;param-name&gt;config/customer&lt;/param-name&gt; 
	&lt;param-value&gt;/WEB-INF/struts-config-customer.xml&lt;/param-value&gt;
&lt;/init-param&gt;
&lt;init-param&gt; 
	&lt;param-name&gt;config/order&lt;/param-name&gt;
	&lt;param-value&gt;/WEB-INF/struts-config-order.xml&lt;/param-value&gt;
&lt;/init-param&gt;

</CODE></PRE></TD></TR></TBODY></TABLE>
<P>要配置多个模块，你需要在原有的一个&lt;init-param&gt;（在Struts 1.1中将其对应的模块称为缺省模块）的基础之上，增加模块对应的&lt;init-param&gt;。其中&lt;param-name&gt;表示为config/XXX的形式，其中XXX为对应的模块名，&lt;param-value&gt;中还是指定模块对应的配置文件。上面这个例子说明该应用有三个模块，分别是缺省模块、customer和order，它们分别对应不同的配置文件。</P>
<P>3、准备各个模块所需的ActionForm、Action和JSP等资源</P>
<P>但是要注意的是，模块的出现也同时带来了一个问题，即如何在不同模块间进行转发？有两种方法可以实现模块间的转发，一种就是在&lt;forward&gt;（全局或者本地）中定义，另外一种就是利用org.apache.struts.actions.SwitchAction。</P>
<P>下面就是一个全局的例子：</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc border=1>
<TBODY>
<TR>
<TD><PRE><CODE>
    ... 
    &lt;struts-config&gt;
	... 
	&lt;global-forwards&gt;
		&lt;forward name="toModuleB"
			contextRelative="true"  
			path="/moduleB/index.do" 
		redirect="true"/&gt;   
	... 
	&lt;/global-forwards&gt;  
	...   
    &lt;/struts-config&gt;
</CODE></PRE></TD></TR></TBODY></TABLE>
<P>可以看出，只需要在原有的path属性前加上模块名，同时将contextRelative属性置为true即可。此外，你也可以在&lt;action&gt;中定义一个类似的本地&lt;forward&gt;。</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc border=1>
<TBODY>
<TR>
<TD><PRE><CODE>
  &lt;action-mappings&gt;
	&lt;!-- Action mapping for profile form --&gt;
	&lt;action path="/login" 
	type="com.ncu.test.LoginAction"  
	name="loginForm"     
	scope="request"      
	input="tile.userLogin"
	validate="true"&gt;     
	&lt;forward name="success" contextRelative="true" path="/moduleA/login.do"/&gt; 
	&lt;/action&gt; 
  &lt;/action-mappings&gt;
</CODE></PRE></TD></TR></TBODY></TABLE>
<P>如果你已经处在其他模块，需要转回到缺省模块，那应该类似下面这样定义，即模块名为空。</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc border=1>
<TBODY>
<TR>
<TD><PRE><CODE>
&lt;forward name="success" contextRelative="true" path="/login.do"/&gt;

</CODE></PRE></TD></TR></TBODY></TABLE>
<P>此外，你也可以使用org.apache.struts.actions.SwitchAction，例如：</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc border=1>
<TBODY>
<TR>
<TD><PRE><CODE>
    ...
    &lt;action-mappings&gt; 
	&lt;action path="/toModule" 
	type="org.apache.struts.actions.SwitchAction"/&gt;  
	...    
    &lt;/action-mappings&gt;  
    ...
</CODE></PRE></TD></TR></TBODY></TABLE>
<P><A name=4><SPAN class=atitle2>ActionServlet</SPAN></A><BR></P>
<P>我们首先来了解MVC中的控制器。在Struts 1.1中缺省采用ActionServlet类来充当控制器。当然如果ActionServlet不能满足你的需求，你也可以通过继承它来实现自己的类。这可以在/WEB-INF/web.xml中来具体指定。</P>
<P>要掌握ActionServlet，就必须了解它所扮演的角色。首先，ActionServlet表示MVC结构中的控制器部分，它需要完成控制器所需的前端控制及转发请求等职责。其次，ActionServlet被实现为一个专门处理HTTP请求的Servlet，它同时具有servlet的特点。在Struts 1.1中它主要完成以下功能： 
<UL xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:h="http://www.w3.org/1999/xhtml" xmlns:dw="http://www.ibm.com/developerworks/">
<LI>接收客户端请求 
<LI>根据客户端的URI将请求映射到一个相应的Action类 
<LI>从请求中获取数据填充Form Bean（如果需要） 
<LI>调用Action类的execute()方法获取数据或者执行业务逻辑 
<LI>选择正确的视图响应客户 </LI></UL>
<P></P>
<P>此外，ActionServlet还负责初始化和清除应用配置信息的任务。ActionServlet的初始化工作在init方法中完成，它可以分为两个部分：初始化ActionServlet自身的一些信息以及每个模块的配置信息。前者主要通过initInternal、initOther和initServlet三个方法来完成。</P>
<P>我们可以在/WEB-INF/web.xml中指定具体的控制器以及初始参数，由于版本的变化以及Struts 1.1中模块概念的引进，一些初始参数被废弃或者移入到/WEB-INF/struts-config.xml中定义。下面列出所有被废弃的参数，相应地在web.xml文件中也不鼓励再使用。</P>
<UL xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:h="http://www.w3.org/1999/xhtml" xmlns:dw="http://www.ibm.com/developerworks/">
<LI>application 
<LI>bufferSize 
<LI>content 
<LI>debug 
<LI>factory 
<LI>formBean 
<LI>forward 
<LI>locale 
<LI>mapping 
<LI>maxFileSize 
<LI>multipartClass 
<LI>nocache 
<LI>null 
<LI>tempDir </LI></UL>
<P>ActionServlet根据不同的模块来初始化ModuleConfig类，并在其中以XXXconfig集合的方式保存该模块的各种配置信息，比如ActionConfig，FormBeanConfig等。</P>
<P>初始化工作完成之后，ActionServlet准备接收客户请求。针对每个请求，方法process(HttpServletRequest request, HttpServletResponse response)将被调用。该方法指定具体的模块，然后调用该模块的RequestProcessor的process方法。</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc border=1>
<TBODY>
<TR>
<TD><PRE><CODE>
protected void process(HttpServletRequest request, 
		HttpServletResponse response) 
		throws IOException, ServletException {

	RequestUtils.selectModule(request, getServletContext());        
	getRequestProcessor(getModuleConfig(request)).process(request, response);
}
</CODE></PRE></TD></TR></TBODY></TABLE>
<P>RequestProcessor包含了Struts控制器的所有处理逻辑，它调用不同的processXXX方法来完成不同的处理。下表列出其中几个主要的方法：</P>
<P>
<TABLE border=1>
<TBODY>
<TR>
<TD>方法</TD>
<TD>功能</TD></TR>
<TR>
<TD>processPath</TD>
<TD>获取客户端的请求路径</TD></TR>
<TR>
<TD>processMapping</TD>
<TD>利用路径来获得相应的ActionMapping</TD></TR>
<TR>
<TD>processActionForm</TD>
<TD>初始化ActionForm（如果需要）并存入正确的scope中</TD></TR>
<TR>
<TD>processActionCreate</TD>
<TD>初始化Action</TD></TR>
<TR>
<TD>processActionPerform</TD>
<TD>调用Action的execute方法</TD></TR>
<TR>
<TD>processForwardConfig</TD>
<TD>处理Action返回的ActionForward</TD></TR></TBODY></TABLE></P>
<P><A name=5><SPAN class=atitle2>ActionForm</SPAN></A><BR></P>
<P>对于ActionForm你可以从以下几个方面来理解它： 
<OL xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:h="http://www.w3.org/1999/xhtml" xmlns:dw="http://www.ibm.com/developerworks/">
<LI>ActionForm表示HTTP窗体中的数据，可以将其看作是模型和视图的中介，它负责保存视图中的数据供模型或者视图使用。Struts 1.1文档中把它比作HTTP和Action之间的防火墙，这体现了ActionForm具有的过滤保护的作用，只有通过ActionForm验证的数据才能够发送到Action处理。 
<LI>ActionForm是与一个或多个ActionConfig关联的JavaBean，在相应的action的execute方法被调用之前，ActionForm会自动利用请求参数来填充自己（初始化属性）。 
<LI>ActionForm是一个抽象类，你必须通过继承来实现自己的类。 </LI></OL>
<P></P>
<P>ActionForm首先利用属性的getter和setter方法来实现初始化，初始化完毕后，ActionForm的validate方法被调用，你可以在其中来检查请求参数的正确性和有效性，并且可以将错误信息以ActionErrors的形式返回到输入窗体。否则，ActionForm将被作为参数传给action的execute方法以供使用。</P>
<P>ActionForm bean的生命周期可以设置为session（缺省）和request，当设置为session时，记得在reset方法中将所有的属性重新设置为初始值。</P>
<P>由于ActionForm对应于HTTP窗体，所以随着页面的增多，你的ActionForm将会急速增加。而且可能同一类型页面字段将会在不同的ActionForm中出现，并且在每个ActionForm中都存在相同的验证代码。为了解决这个问题，你可以为整个应用实现一个ActionForm或者至少一个模块对应于一个ActionForm。</P>
<P>但是，聚合的代价就是复用性很差，而且难维护。针对这个问题，在Struts 1.1中提出了DynaActionForm的概念。</P>
<P><B xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:h="http://www.w3.org/1999/xhtml" xmlns:dw="http://www.ibm.com/developerworks/">DynaActionForm类</B> </P>
<P>DynaActionForm的目的就是减少ActionForm的数目，利用它你不必创建一个个具体的ActionForm类，而是在配置文件中配置出所需的虚拟ActionForm。例如，在下表中通过指定&lt;form-bean&gt;的type为"org.apache.struts.action.DynaActionForm"来创建一个动态的ActionForm--loginForm。</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc border=1>
<TBODY>
<TR>
<TD><PRE><CODE>
&lt;form-beans&gt;
	&lt;form-bean name="loginForm" type="org.apache.struts.action.DynaActionForm"&gt;  
		&lt;form-property name="actionClass" type="java.lang.String"/&gt;
		&lt;form-property name="username" type="java.lang.String"/&gt;
		&lt;form-property name="password" type="java.lang.String"/&gt; 
	&lt;/form-bean&gt; 
&lt;/form-beans&gt;

</CODE></PRE></TD></TR></TBODY></TABLE>
<P>动态的ActionForm的使用方法跟普通的ActionForm相同，但是要注意一点。普通的ActionForm对象需要为每个属性提供getter和setter方法，以上面的例子而言，我们需要提供getUsername() 和 setUsername()方法取得和设置username属性，同样地有一对方法用于取得和设置password属性和actionClass属性。</P>
<P>如果使用DynaActionForm，它将属性保存在一个HashMap类对象中，同时提供相应的get(name) 和 set(name)方法，其中参数name是要访问的属性名。例如要访问DynaActionForm中username的值，可以采用类似的代码：</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc border=1>
<TBODY>
<TR>
<TD><PRE><CODE>
String username = (String)form.get("username")；

</CODE></PRE></TD></TR></TBODY></TABLE>
<P>由于值存放于一个HashMap对象，所以要记得对get()方法返回的Object对象做强制性类型转换。正是由于这点区别，如果你在Action中非常频繁地使用ActionForm对象，建议还是使用普通的ActionForm对象。</P>
<P>在Struts 1.1中，除了DynaActionForm以外，还提供了表单输入自动验证的功能，在包org.apache.struts.validator中提供了许多有用的类，其中最常见的就是DynaValidatorForm类。</P>
<P><B xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:h="http://www.w3.org/1999/xhtml" xmlns:dw="http://www.ibm.com/developerworks/">DynaValidatorForm类</B> </P>
<P>DynaValidatorForm是DynaActionForm的子类，它能够提供动态ActionForm和自动表单输入验证的功能。和使用DynaActionForm类似，你必须首先在配置文件中进行配置：</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc border=1>
<TBODY>
<TR>
<TD><PRE><CODE>
&lt;form-beans&gt;
	&lt;form-bean name="loginForm" type="org.apache.struts.validator.DynaValidatorForm"&gt; 
		&lt;form-property name="actionClass" type="java.lang.String"/&gt;     
		&lt;form-property name="username" type="java.lang.String"/&gt; 
		&lt;form-property name="password" type="java.lang.String"/&gt;  
	&lt;/form-bean&gt;
&lt;/form-beans&gt;

</CODE></PRE></TD></TR></TBODY></TABLE>
<P>同时要定义验证的插件：</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc border=1>
<TBODY>
<TR>
<TD><PRE><CODE>
  &lt;plug-in className="org.apache.struts.validator.ValidatorPlugIn"&gt;
	&lt;set-property property="pathnames"  
	value="/WEB-INF/validator-rules.xml,  
	/WEB-INF/validation.xml"/&gt;
  &lt;/plug-in&gt;

</CODE></PRE></TD></TR></TBODY></TABLE>
<P>其中的validator.xml和validator-rules.xml分别表示验证定义和验证规则的内容（可以合并在一起），比如针对上例中的DynaValidatorForm，我们有如下验证定义（validator.xml）：</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc border=1>
<TBODY>
<TR>
<TD><PRE><CODE>
&lt;?xml version="1.0" encoding="ISO-8859-1" ?&gt;
&lt;!DOCTYPE form-validation PUBLIC  
"-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.0//EN"  
"http://jakarta.apache.org/commons/dtds/validator_1_0.dtd"&gt;
&lt;!--    Validation Rules    $Id: validation.xml--&gt;

&lt;form-validation&gt;  
&lt;!-- ========== Default Language Form Definitions ===================== --&gt;
&lt;formset&gt;  
	&lt;form name="loginForm"&gt;     
		&lt;field property="username" depends="required, minlength,maxlength"&gt; 
			&lt;arg0   key="prompt.username"/&gt;          
			&lt;arg1   key="${var:minlength}" name="minlength" resource="false"/&gt;       
			&lt;arg2   key="${var:maxlength}" name="maxlength" resource="false"/&gt;              
			&lt;var&gt;                
				&lt;var-name&gt;maxlength&lt;/var-name&gt;    
				&lt;var-value&gt;16&lt;/var-value&gt;         
			&lt;/var&gt;          
			&lt;var&gt;      
				&lt;var-name&gt;minlength&lt;/var-name&gt;     
				&lt;var-value&gt;3&lt;/var-value&gt;         
			&lt;/var&gt;       
		&lt;/field&gt;     
		&lt;field property="password" depends="required, minlength,maxlength" bundle="alternate"&gt;          
			&lt;arg0   key="prompt.password"/&gt;   
			&lt;arg1   key="${var:minlength}" name="minlength" resource="false"/&gt;          
			&lt;arg2   key="${var:maxlength}" name="maxlength" resource="false"/&gt;  
			&lt;var&gt;              
				&lt;var-name&gt;maxlength&lt;/var-name&gt;     
				&lt;var-value&gt;16&lt;/var-value&gt;        
			&lt;/var&gt;          
			&lt;var&gt;      
				&lt;var-name&gt;minlength&lt;/var-name&gt; 
				&lt;var-value&gt;3&lt;/var-value&gt;       
			&lt;/var&gt;        
		&lt;/field&gt;    
	&lt;/form&gt;   
&lt;/formset&gt;
&lt;/form-validation&gt;
</CODE></PRE></TD></TR></TBODY></TABLE>
<P>从上述定义中，我们可以看到对于字段username有三项验证：required, minlength, maxlength，意思是该字段不能为空，而且长度在3和16之间。而validator-rules.xml文件则可以采用Struts提供的缺省文件。注意在&lt;form-bean&gt;中定义的form是如何与validation.xml中的form关联起来的。最后，要启动自动验证功能，还需要将Action配置的validate属性设置为true。</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc border=1>
<TBODY>
<TR>
<TD><PRE><CODE>

&lt;action path="/login"  
type="com.ncu.test.LoginAction"
name="loginForm"          
scope="request"         
input="tile.userLogin"validate="true"&gt;

</CODE></PRE></TD></TR></TBODY></TABLE>
<P>此时，Struts将根据xml配置文件中的定义来检验表单输入，并将不符合要求的错误信息输出到页面。但是你可能会想：这个功能虽然好，可是什么检验都跑到服务器端执行，效率方面和用户易用性方面是不是有些问题？你可能会怀念起那简单的JavaScript客户端验证。</P>
<P>不用担心，在Struts 1.1中也支持JavaScript客户端验证。如果你选择了客户端验证，当某个表单被提交以后，Struts 1.1启动客户端验证，如果浏览器不支持JavaScript验证，则服务器端验证被启动，这种双重验证机制能够最大限度地满足各种开发者的需要。JavaScript验证代码也是在validator-rules.xml文件中定义的。要启动客户端验证，你必须在相应的JSP文件中做如下设置： 
<OL xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:h="http://www.w3.org/1999/xhtml" xmlns:dw="http://www.ibm.com/developerworks/">
<LI>为&lt;html:form&gt;增加onsubmit属性 
<LI>设置Javascript支持 </LI></OL>
<P></P>
<P>下表中列出了一JSP文件的示例代码，红字部分为Javascript验证所需代码。</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc border=1>
<TBODY>
<TR>
<TD><PRE><CODE>
&lt;%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %&gt;
&lt;table bgcolor="#9AFF9A" cellspacing="0" cellpadding="10" border="1" width="100%"&gt;
	&lt;tr&gt;
	&lt;td&gt; 
	&lt;table cellspacing="0" cellpadding="0" border="0" width="100%"&gt; 
	&lt;tr bgcolor="#696969"&gt; 
		&lt;td align="center"&gt;     
		&lt;font color="#FFFFFF"&gt;Panel 3: Profile&lt;/font&gt;  
		&lt;/td&gt;
		&lt;/tr&gt; 
	&lt;tr&gt;  
		&lt;td&gt;&lt;br&gt; 
		&lt;html:errors/&gt;  
		&lt;html:form action="/login.do" focus="username"  onsubmit="return validateLoginForm(this);"&gt;  
		&lt;html:hidden property="actionClass"/&gt;   
		&lt;center&gt;      
		&lt;table&gt;      
			&lt;tr&gt;        
			&lt;td&gt;UserName:&lt;/td&gt;   
			&lt;td&gt;&lt;html:text property="username" size="20"/&gt;&lt;/td&gt; 
			&lt;/tr&gt; 
			&lt;tr&gt;  
			&lt;td&gt;Password:&lt;/td&gt;   
			&lt;td&gt;&lt;html:password property="password" size="20"/&gt;&lt;/td&gt;    
			&lt;/tr&gt;  
			&lt;tr&gt;  
			&lt;td colspan=2&gt;&lt;html:submit property="submitProperty" value="Submit"/&gt;&lt;/td&gt;     
		&lt;/table&gt;   
		&lt;/center&gt;  
		&lt;/html:form&gt; 
		&lt;html:javascript formName="loginForm" dynamicJavascript="true" staticJavascript="false"/&gt;  
	
	&lt;script language="Javascript1.1" src="staticJavascript.jsp"&gt;&lt;/script&gt;  
	&lt;/td&gt; 
	&lt;/tr&gt; 
	&lt;/table&gt;
	&lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;
</CODE></PRE></TD></TR></TBODY></TABLE>
<P>其中onsubmit的值为"return validateLoginForm(this);"，它的语法为：</P>
<P>return validate + struts-config.xml中定义的form-bean名称 + (this);</P>
<P>staticJavascript.jsp的内容为：</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc border=1>
<TBODY>
<TR>
<TD><PRE><CODE>
&lt;%@ page language="java" %&gt;
&lt;%-- set document type to Javascript (addresses a bug in Netscape according to a web resource --%&gt;
&lt;%@ page contentType="application/x-javascript" %&gt;
&lt;%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %&gt;
&lt;html:javascript dynamicJavascript="false" staticJavascript="true"/&gt;


</CODE></PRE></TD></TR></TBODY></TABLE>
<P>如果validator-rules.xml中定义的基本验证功能不能满足你的需求，你可以自己添加所需的验证类型。</P>
<P><A name=6><SPAN class=atitle2>Action</SPAN></A><BR></P>
<P>我们通过继承Action类来实现具体的执行类。具体Action类的功能一般都在execute（以前是perform方法）方法中完成，其中主要涉及到以下几个方面： 
<OL xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:h="http://www.w3.org/1999/xhtml" xmlns:dw="http://www.ibm.com/developerworks/">
<LI>辅助ActionForm进行一些表单数据的检查。 
<LI>执行必要的业务逻辑，比如存取数据库，调用实体bean等。 
<LI>更新服务器端的bean数据，后续对象中可能会用到这些数据，比如在JSP中利用bean:write来获得这些数据。 
<LI>根据处理结果决定程序的去处，并以ActionForward对象的形式返回给ActionServlet。 </LI></OL>
<P></P>
<P><I xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:h="http://www.w3.org/1999/xhtml" xmlns:dw="http://www.ibm.com/developerworks/"><B>提示：</B>由于在Action和ActionForm中都可以实现验证方法，那么如何来安排它们之间的分工呢？一般来说，我们秉着MVC分离的原则，也就是视图级的验证工作放在ActionForm来完成，比如输入不能为空，email格式是否正确，利用ValidatorForm可以很轻松地完成这些工作。而与具体业务相关的验证则放入Action中，这样就可以获得最大ActionForm重用性的可能。 </I></P>
<P>前面我们提到过，我们主张将业务逻辑执行分离到单独的JavaBean中，而Action只负责错误处理和流程控制。而且考虑到重用性的原因，在执行业务逻辑的JavaBean中不要引用任何与Web应用相关的对象，比如HttpServletRequest，HttpServletResponse等对象，而应该将其转化为普通的Java对象。关于这一点，可以参考Petstore中WAF框架的实现思路。</P>
<P>此外，你可能还注意到execute与perform的一个区别：execute方法简单地掷出Exception异常，而perform方法则掷出ServletException和IOException异常。这不是说Struts 1.1在异常处理功能方面弱化了，而是为了配合Struts 1.1中一个很好的功能--宣称式异常处理机制。</P>
<P><A name=7><SPAN class=atitle2>宣称式异常处理</SPAN></A><BR></P>
<P>和EJB中的宣称式事务处理概念类似，宣称式异常处理其实就是可配置的异常处理，你可以在配置文件中指定由谁来处理Action类中掷出的某种异常。你可以按照以下步骤来完成该功能： 
<OL xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:h="http://www.w3.org/1999/xhtml" xmlns:dw="http://www.ibm.com/developerworks/">
<LI>实现org.apache.struts.action.ExceptionHandler的子类，覆盖execute方法，在该方法中处理异常并且返回一个ActionForward对象 
<LI>在配置文件中配置异常处理对象，你可以配置一个全局的处理类或者单独为每个Action配置处理类 </LI></OL>
<P></P>
<P>下表就定义了一个全局的处理类CustomizedExceptionHandler，它被用来处理所有的异常。</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc border=1>
<TBODY>
<TR>
<TD><PRE><CODE>
&lt;global-exceptions&gt; 
&lt;exception 
	handler="com.yourcorp.CustomizedExceptionHandler" 
	key="global.error.message" 
	path="/error.jsp"    
	scope="request"    
	type="java.lang.Exception"/&gt;
&lt;/global-exceptions&gt;

</CODE></PRE></TD></TR></TBODY></TABLE>
<P>其中具体的参数含义，可以参考ExceptionHandler.java源文件。</P>
<P><A name=8><SPAN class=atitle2>taglib</SPAN></A><BR></P>
<P>讲完了模型和控制器，接下来我们要涉及的是视图。视图的角色主要是由JSP来完成，从JSP的规范中可以看出，在视图层可以"折腾"的技术不是很多，主要的就是自定义标记库的应用。Struts 1.1在原有的四个标记库的基础上新增了两个标记库--Tiles和Nested。</P>
<P>其中Tiles除了替代Template的基本模板功能外，还增加了布局定义、虚拟页面定义和动态页面生成等功能。Tiles强大的模板功能能够使页面获得最大的重用性和灵活性，此外可以结合Tiles配置文件中的页面定义和Action的转发逻辑，即你可以将一个Action转发到一个在Tiles配置文件中定义的虚拟页面，从而减少页面的数量。比如，下表中的Action定义了一个转发路径，它的终点是tile.userMain，而后者是你在Tiles配置文件中定义的一个页面。</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc border=1>
<TBODY>
<TR>
<TD><PRE><CODE>
&lt;!-- ========== Action Mapping Definitions ============================== --&gt;
&lt;action-mappings&gt;  
&lt;!-- Action mapping for profile form --&gt; 
	&lt;action path="/login"   
		type="com.ncu.test.LoginAction"      
		name="loginForm"    
		scope="request"     
		input="tile.userLogin"
		validate="true"&gt;     
		&lt;forward name="success" path="tile.userMain"/&gt;   
	&lt;/action&gt; 
&lt;/action-mappings&gt;
</CODE></PRE></TD></TR></TBODY></TABLE>
<P>Tiles配置文件：tiles-defs.xml</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc border=1>
<TBODY>
<TR>
<TD><PRE><CODE>
&lt;!DOCTYPE tiles-definitions PUBLIC 
"-//Apache Software Foundation//DTD Tiles Configuration//EN"       "http://jakarta.apache.org/struts/dtds/tiles-config.dtd"&gt;
&lt;tiles-definitions&gt;  
&lt;!-- =======================================================  --&gt; 
&lt;!-- Master definitions                                       --&gt;
&lt;!-- =======================================================  --&gt; 
&lt;!-- Page layout used as root for all pages. --&gt; 

&lt;definition name="rootLayout" path="/tiles-layouts/rootLayout.jsp"&gt; 
	&lt;put name="titleString" value="CHANGE-ME"/&gt;   
	&lt;put name="topMenu" value="/tiles-components/topMenu.jsp"/&gt; 
	&lt;put name="leftMenu" value="/tiles-components/panel1.jsp"/&gt;  
	&lt;put name="body" value="CHANGE-ME"/&gt;   
	&lt;put name="footer" value="/tiles-components/footer.jsp"/&gt; 
&lt;/definition&gt; 

&lt;!-- =======================================================  --&gt; 
&lt;!-- Page definitions 					--&gt;  
&lt;!-- =======================================================  --&gt; 

&lt;!-- User Login page --&gt; 
&lt;definition name="tile.userLogin" extends="rootLayout"&gt; 
	&lt;put name="titleString" value="User Login"/&gt;  
	&lt;put name="body" value="/src/userLogin.jsp"/&gt; 
&lt;/definition&gt;  
&lt;!-- User Main page --&gt; 
&lt;definition name="tile.userMain" extends="rootLayout"&gt; 
	&lt;put name="titleString" value="User Main"/&gt;  
	&lt;put name="body" value="/src/userMain.jsp"/&gt; 
&lt;/definition&gt;
&lt;/tiles-definitions&gt;
</CODE></PRE></TD></TR></TBODY></TABLE>
<P>而Nested标记库的作用是让以上这些基本标记库能够嵌套使用，发挥更大的作用。</P>
<P><A name=9><SPAN class=atitle2>Commons Logging 接口</SPAN></A><BR></P>
<P>所谓的Commons Logging接口，是指将日志功能的使用与日志具体实现分开，通过配置文件来指定具体使用的日志实现。这样你就可以在Struts 1.1中通过统一的接口来使用日志功能，而不去管具体是利用的哪种日志实现，有点于类似JDBC的功能。Struts 1.1中支持的日志实现包括：Log4J，JDK Logging API， LogKit，NoOpLog和SimpleLog。</P>
<P>你可以按照如下的方式来使用Commons Logging接口（可以参照Struts源文中的许多类实现）：</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc border=1>
<TBODY>
<TR>
<TD><PRE><CODE>
package com.foo;
// ...
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
//...
	public class Foo {    
	// ...    
	private static Log log = LogFactory.getLog(Foo.class);
	// ...    
	public void setBar(Bar bar) {       
		if (log.isTraceEnabled()) {         
			log.trace("Setting bar to " + bar);   
		}      
	this.bar = bar;   
	}
// ...
}
</CODE></PRE></TD></TR></TBODY></TABLE>
<P>而开启日志功能最简单的办法就是在WEB-INF/classes目录下添加以下两个文件：</P>
<P>commons-logging.properties文件：</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc border=1>
<TBODY>
<TR>
<TD><PRE><CODE>
# Note: The Tiles framework now uses the commons-logging package to output different information or debug statements. 
Please refer to this package documentation to enable it. The simplest way to enable logging is to create two files in 
WEB-INF/classes:
# commons-logging.properties
# org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog
# simplelog.properties
# # Logging detail level,
# # Must be one of ("trace", "debug", "info", "warn", "error", or "fatal").
#org.apache.commons.logging.simplelog.defaultlog=trace
org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog

</CODE></PRE></TD></TR></TBODY></TABLE>
<P>simplelog.properties文件：</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc border=1>
<TBODY>
<TR>
<TD><PRE><CODE>
# Logging detail level,
# Must be one of ("trace", "debug", "info", "warn", "error", or "fatal").
org.apache.commons.logging.simplelog.defaultlog=fatal

</CODE></PRE></TD></TR></TBODY></TABLE>
<P>这里我们采用的日志实现是SimpleLog，你可以在simplelog.properties文件指定日志明细的级别：trace，debug，info，warn，error和fatal，从trace到fatal错误级别越来越高，同时输出的日志信息也越来越少。而这些级别是和org.apache.commons.logging.log接口中的方法一一对应的。这些级别是向后包含的，也就是前面的级别包含后面级别的信息。</P><img src ="http://www.blogjava.net/qq13367612/aggbug/18978.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qq13367612/" target="_blank">Sung</a> 2005-11-09 14:16 <a href="http://www.blogjava.net/qq13367612/articles/18978.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用Validator检查你的表单</title><link>http://www.blogjava.net/qq13367612/articles/17646.html</link><dc:creator>Sung</dc:creator><author>Sung</author><pubDate>Tue, 01 Nov 2005 02:29:00 GMT</pubDate><guid>http://www.blogjava.net/qq13367612/articles/17646.html</guid><wfw:comment>http://www.blogjava.net/qq13367612/comments/17646.html</wfw:comment><comments>http://www.blogjava.net/qq13367612/articles/17646.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qq13367612/comments/commentRss/17646.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qq13367612/services/trackbacks/17646.html</trackback:ping><description><![CDATA[<P><SPAN class=italicbodycopy><B><EM><FONT face=Arial size=2>用Validator（验证器）提供的丰富的内置验证方法简化Struts的开发过程。</FONT></EM></B></SPAN> </P>
<P><SPAN class=bodycopy><FONT face=Arial size=2>Struts框架的一个主要好处是它提供了对接收到的表单数据进行验证的内置界面。如果有任何验证失败，则应用程序都会重新显示HTML表单，这样就可以改正无效的数据了。如果验证成功，则处理过程会继续进行。Struts框架的简单验证界面会减少与处理数据验证有关的令人头疼的事情，这样你就可以把精力集中到验证代码上，而不是放到捕获数据、重新显示不完整或无效数据的技巧上。</FONT></SPAN></P>
<P class=bodycopy>但是，Struts内置的验证界面也有缺点。例如，在整个应用程序中验证代码常常会大量重复，因为许多域需要相同的验证逻辑。对一些相似字段的验证逻辑进行任何修改都要求在几个地方修改代码，还要重新编译受影响的代码。为了解决这个问题并增强Struts验证界面的功能，作为Struts的第三方附加件创建了Validator框架。后来，Validator被集成到核心Struts代码库中，并从Struts中分离出来，现在它是一个独立的Jakarta Commons项目。虽然Validator是一个独立的框架，但它仍能与其他程序封装在一起后提供，并与Struts无缝集成。</P>
<P><SPAN class=parahead1><STRONG><FONT face=Arial>Validator概述</FONT></STRONG></SPAN> </P>
<P><SPAN class=bodycopy><FONT face=Arial size=2>没有Validator，你就不得不编写验证表单数据所需的全部代码，并把它放入Form Bean对象的validate( )方法中。对于想在其上进行数据验证的每个Form Bean域来说，都需要编写逻辑代码来实现验证。此外，你还必须编写代码来存储验证失败时的出错消息。 </FONT></SPAN></P>
<P class=bodycopy>有了Validator，你就不必在Form Bean中编写用于验证或存储错误消息的任何代码。相反，Form Bean提供了Validator的一个ActionForm子类，它提供验证或存储错误消息的功能。 </P>
<P class=bodycopy>可把Validator框架作为一个可用于Form Bean验证的可插入的验证例行程序系统来进行安装。每个验证例行程序都只是一个Java方法，负责执行特定类型的验证任务，验证可能通过，也可能失败。 默认情况下，Validator与几个有用的验证例行程序封装在一起来提供，这些例行程序能满足大多数情况下的验证要求。但是，如果Validator框架没有提供你需要的验证例行程序，那么你可以自己创建定制的验证例行程序，并将它插入到该框架中。此外，Validator还支持服务器端和客户端（JavaScript）的验证，而Form Bean只提供服务器端验证界面。 </P>
<P><SPAN class=bodycopy><FONT face=Arial size=2>Validator使用两个XML配置文件来分别确定安装哪个验证例行程序和如何将它们应用于给定的应用程序。第一个配置文件validator-rules.xml说明应该被插入到框架中的验证例行程序，并提供每个验证的逻辑的名称。validator-rules.xml文件还定义了每个验证例行程序的客户端JavaScript代码。可以配置Validator让它把这个JavaScript代码发送到浏览器上，这样验证就可以在客户端和服务器端进行了。 </FONT></SPAN></P>
<P><SPAN class=bodycopy><FONT face=Arial size=2>第二个配置文件validation.xml确定哪个验证例行程序应用到哪个Form Bean。文件中的定义使用struts-config.xml文件给出的Form Bean的逻辑名称以及validator-rules.xml文件给出的验证例行程序的逻辑名称，以便把二者关联起来。</FONT></SPAN> </P>
<P class=bodycopy>使用Validator框架包括启用Validator插件、配置Validator的两个配置文件，以及创建提供Validator的ActionForm子类的Form Beans。下面详细解释如何配置和使用Validator。 </P>
<P><SPAN class=parahead1><STRONG><FONT face=Arial>启用Validator插件</FONT></STRONG></SPAN> </P>
<P><SPAN class=bodycopy><FONT face=Arial size=2>虽然Validator框架是与Struts封装在一起提供的，但在默认状况下Validator并不被启用。为了启用Validator，要向你的应用程序的struts-config.xml文件中添加下面的插件定义。 </FONT></SPAN></P>
<P><FONT face=Arial size=2></FONT><PRE>&lt;!-- Validator Configuration --&gt;
&lt;plug-in className="org.apache.struts
.validator.ValidatorPlugIn"&gt;
  &lt;set-property property="pathnames"
               value="/WEB-INF/
  validator-rules.xml, /WEB-INF/

  validation.xml"/&gt;
&lt;/plug-in&gt;
</PRE>
<P></P>
<P><SPAN class=bodycopy><FONT face=Arial size=2>该定义告诉Struts为你的应用程序加载并初始化Validator插件。在初始化时，该插件装入由路径名属性指定的、用逗号分隔的Validator配置文件清单。每个配置文件的路径应该用与Web应用程序的相关的路径来指定，如前面的例子所示。 </FONT></SPAN></P>
<P class=bodycopy>请注意，你的应用程序的struts-config.xml文件必须与Struts Configuration Document Type Definition（Struts配置文档类型定义，DTD）一致，后者规定文件中元素出现的顺序。所以，你必须把Validator插件定义放到该文件的适当位置。确保文件中元素适当排列的最简便方法就是使用诸如Struts Console的工具，它自动格式化你的配置文件，以便与DTD保持一致。</P>
<P><SPAN class=parahead1><STRONG><FONT face=Arial>配置validator-rules.xml </FONT></STRONG></SPAN></P>
<P class=bodycopy>Validator框架可以设置为可插入系统，其验证例行程序仅仅是插入到该系统中执行具体验证的Java方法。validator-rules.xml文件说明性地插入Validator用于执行验证的验证例行程序中。Struts示例应用程序带有这个文件的预配置拷贝。在大多数情况下，你不必修改这个预配置拷贝，除非你要向该框架中添加自己定制的验证。</P>
<P><SPAN class=bodycopy><A href="http://www.oracle.com/global/cn/oramag/oracle/04-jan/o14dev_struts_l1.html" target=_blank><SPAN class=bodylink><FONT face=Arial color=#000000 size=2>清单1</FONT></SPAN></A><FONT face=Arial size=2> 是一个示例validator-rules.xml文件，说明如何将验证例行程序插入到Validator中。validator-rules.xml文件中的每个验证例行程序都有自己的定义，它用validator标记声明，利用name属性为该验证例行程序指定逻辑名，并指定该例行程序的类和方法。该例行程序的逻辑名称供该文件中的其他例行程序以及validation.xml文件中的验证定义用于引用该例行程序。</FONT></SPAN> </P>
<P class=bodycopy>请注意，validator标记放在javascript的标记中，javascript标记用于定义客户端JavaScript代码，以便在客户端执行与服务器端相同的验证。 </P>
<P class=parahead1>提供的验证程序</P>
<P class=bodycopy>默认情况下，Validator中包括几个基本验证例行程序，你可以用它们来处理大多数验证问题。这些例行程序具有逻辑名称，如required（用于输入要求的值）、CreditCard（用于输入信用卡号码值）、email（用于输入电子邮件地址值），等等。</P>
<P class=parahead1>创建Form Bean</P>
<P><SPAN class=bodycopy><FONT face=Arial size=2>为了使用Validator，你的应用程序的Form Bean必须归到Validator的ActionForm的某一子类，而不是ActionForm本身。Validator的ActionForm子类提供了ActionForm的validate( )方法（它嵌入到Validator框架中）的实施过程。你不必从头编写验证代码并把它投入validate( )方法中，相反，可以完全忽略该方法，因为Validator为你提供了验证代码。 </FONT></SPAN></P>
<P class=bodycopy>与Struts提供的核心功能相类似，Validator提供给你两种可供选择的方法来创建Form Bean。 你可以选择的第一种方法就是像下面这样创建一个特定的Form Bean对象：</P>
<P><PRE>package com.jamesholmes.minihr;

import org.apache.struts.validator
.ValidatorForm;


public class LogonForm extends ValidatorForm {
  private String username;
  private String password;
  
  public String getUsername() {
    return username;
  }
  
  public void setUsername(String 
username) {
    this.username = username;
  }


  public String getPassword() {
    return password;
  }
public void setPassword(String 
password) {
    this.password = password;
  }
}
</PRE><SPAN class=bodycopy>
<P></P></SPAN>
<P class=bodycopy>这个类与你不是用Validator所创建的类相似，但它提供ValidatorForm而不是ActionForm。这个类也不提供ActionForm的空reset( )和validate( )方法的实施过程，因为ValidatorForm提供了相应过程。</P>
<P class=bodycopy>在struts-config.xml文件中配置这个特定Form Bean的方法与配置正则Form Bean的方法相同：</P>
<P><PRE>&lt;form-beans&gt;
  &lt;form-bean name="logonForm"
            type="com.jamesholmes
  .minihr.LogonForm"/&gt;
&lt;/form-beans&gt;
</PRE>
<P></P>
<P><SPAN class=bodycopy><FONT face=Arial size=2>用表单标记的name属性给特定Form Bean指定的逻辑名是在定义validation.xml文件中的验证时所使用的名称，如下所示：</FONT></SPAN></P>
<P><FONT face=Arial size=2></FONT><PRE>&lt;!DOCTYPE form-validation 
PUBLIC "-//Apache Software Foundation//
       DTD Commons Validator Rules
       Configuration 1.0//EN"
       "http://jakarta.apache.org/
      commons/dtds/validator_1_0.dtd"&gt;


&lt;form-validation&gt;
  &lt;formset&gt;
    &lt;form name="logonForm"&gt;
      &lt;field property="username" 
            depends="required"&gt;
        &lt;arg0 key="prompt.username"/&gt;
      &lt;/field&gt;
    &lt;/form&gt;
  &lt;/formset&gt;
&lt;/form-validation&gt;
</PRE>
<P></P>
<P><SPAN class=bodycopy><FONT face=Arial size=2>Validator使用该表单标记的name属性的值将验证定义与要应用这些定义的Form Bean的名称相匹配。 </FONT></SPAN></P>
<P class=bodycopy>创建Form Bean时可以选择的第二种方法是在struts-config.xml文件中定义一个动态Form Bean，如下所示：</P>
<P><PRE>&lt;form-beans&gt;
  &lt;form-bean name="logonForm"
            type="org.apache
.struts.validator.DynaValidatorForm"&gt;
    &lt;form-property name="username"
            type="java.lang.String"/&gt;
    &lt;form-property name="password"
            type="java.lang.String"/&gt;
  &lt;/form-bean&gt;
&lt;/form-beans&gt;
</PRE>
<P></P>
<P><SPAN class=bodycopy><FONT face=Arial size=2>动态Form Bean不要求创建特定的Form Bean对象；相反，要定义Form Bean应该具有的属性和类型，而Struts为你动态创建Form Bean。 Validator允许你使用这个概念，就像在核心Struts中使用这个概念一样。与使用Validator的惟一区别就是要指定Form Bean是org.apache.struts.validator.DynaValidatorForm类型，而不是org.apache.struts.action.DynaActionForm类型。</FONT></SPAN></P>
<P class=bodycopy>分配给动态Form Bean的逻辑名是在定义validation.xml文件中的验证时使用的名称。Validator使用与之相匹配的名称将这些验证与Form Bean联系在一起。 </P>
<P class=bodycopy>除了创建Form Bean的这两种标准方法之外，Validator还提供了一个高级特性，用于将多个验证定义与一个Form Bean定义联系起来。当你使用基于validatorForm或基于DynaValidatorForm的Form Bean时，Validator使用struts-config.xml文件中的Form Bean的逻辑名称，将Form Bean映射到validation.xml文件中的验证定义。这种机制在大多数情况下非常有用，但在某些时候，Form Bean要在多个操作中共享。 一个操作可能使用Form Bean的所有域（fields），而另一个操作可能只使用这些域的一个子集。因为验证定义被连接到Form Bean，所以只使用域的一个子集的操作就无法绕过对未使用域的验证。当验证Form Bean时，就会对未使用的域生成错误消息，因为Validator无从知道不去验证未使用的域，它只是简单地把它们看作缺失或无效。</P>
<P class=bodycopy>为了解决这个问题，Validator提供了两个附加的ActionForm子类，它使你能够将验证与操作相关联，而不是与Form Bean相关联。这样你就可以根据哪个操作正在使用Form Bean来指定把哪些验证用于该Form Bean了。对于特定的Form Bean，你要像下面这样声明org.apache.struts.validator.ValidatorActionForm子类：</P>
<P><PRE>public class AddressForm extends ValidatorActionForm {
  ...
}
</PRE>
<P></P>
<P class=bodycopy>对于动态Form Bean，在struts-config.xml文件中为Form Bean定义指定org.apache.struts.validator.DynaValidatorActionForm的类型，如下所示： </P>
<P><PRE>&lt;form-bean name="addressForm"
          type="org.apache.struts
.validator.DynaValidatorActionForm"&gt;
  ...
&lt;/form-bean&gt;
</PRE>
<P></P>
<P class=bodycopy>在validation.xml文件中，把一组验证映射到一个操作路径，而不是映射到Form Bean名，因为如果你定义了Create Address和Edit Address两个操作（它们使用同一个Form Bean），那么每个操作都会有一个惟一的操作名，如下所示： </P>
<P><PRE>&lt;action-mappings&gt;
  &lt;action path="/createAddress"
         type="com.jamesholmes
  .minihr.CreateAddressAction"
         name="addressForm"/&gt;
  &lt;action path="/editAddress"
         type="com.jamesholmes
  .minihr.EditAddressAction"
         name="addressForm"/&gt;

&lt;/action-mappings&gt;
</PRE>
<P></P>
<P class=bodycopy>下面的validation.xml文件片断显示了两组验证，它们用于同一个Form Bean，但却有不同的操作路径：</P>
<P><PRE>&lt;formset&gt;
  &lt;form name="/createAddress"&gt;
    &lt;field property="city"
          depends="required"&gt;
      &lt;arg0 key="prompt.city"/&gt;
    &lt;/field&gt;
  &lt;/form&gt;
  &lt;form name="/editAddress"&gt;
    &lt;field property="state"
          depends="required"&gt;
      &lt;arg0 key="prompt.state"/&gt;
    &lt;/field&gt;
  &lt;/form&gt;
&lt;/formset&gt;
</PRE>
<P></P>
<P class=bodycopy>因为Form Bean要么属于ValidatorActionForm子类，要么属于DynaValidatorActionForm子类，所以Validator知道用一个操作路径代替Form Bean的逻辑名称来找出用于Form Bean的验证。</P>
<P class=parahead1>配置validation.xml文件</P>
<P class=bodycopy>validation.xml文件用于声明将应用到Form Beans的一组验证。要验证的每个Form Bean在这个文件中都有自己的定义。在这个定义中，指定要应用到该Form Bean的各域的验证。下面是一个validation.xml文件的例子，说明如何定义验证：</P>
<P><PRE>&lt;!DOCTYPE form-validation 
PUBLIC "-//Apache Software Foundation//
       DTD Commons Validator Rules
       Configuration 1.0//EN"
       "http://jakarta.apache.org/
      commons/dtds/validator_1_0.dtd"&gt;

&lt;form-validation&gt;
  &lt;formset&gt;
    &lt;form name="logonForm"&gt;
      &lt;field property="username"
            depends="required"&gt;
        &lt;arg0 key="prompt.username"/&gt;

      &lt;/field&gt;
      &lt;field property="password"
            depends="required"&gt;
        &lt;arg0 key="prompt.password"/&gt;
      &lt;/field&gt;
    &lt;/form&gt;
  &lt;/formset&gt;
&lt;/form-validation&gt;
</PRE>
<P></P>
<P><SPAN class=bodycopy><FONT face=Arial size=2>validation.xml文件的第一个元素是form-validation。这个元素是该文件的主元素，而且只定义一次。在form-validation元素内定义form-set元素，它包括多个表单元素。一般来说，在文件中只定义一个form-set元素，但是如果要将验证国际化，那就要在每个地方单独使用一个form-set元素。</FONT></SPAN></P>
<P><SPAN class=bodycopy><FONT face=Arial size=2>每个表单元素使用name属性将名称与其所包含的域验证集关联起来。Validator使用这个逻辑名称将这些验证映射到在struts-config.xml文件中定义的一个Form Bean。根据要验证的Form Bean的类型，Validator力求将该名称与Form Bean的逻辑名称或操作路径相匹配。在表单元素内，field元素定义要应用到Form Bean的特定域的验证。field元素的property属性对应于特定Form Bean中的域名。depends属性利用validator-rules.xml文件指定验证例行程序的逻辑名称，这些例行程序将应用到域验证中。</FONT></SPAN> </P>
<P class=parahead1>配置ApplicationResources.properties </P>
<P class=bodycopy>Validator使用Struts的资源绑定（Resource Bundle）机制将错误消息具体化。不用在框架中对错误消息进行硬编码，Validator使你能在ApplicationResources.properties文件中为一个消息指定一个键值，如果验证失败则将返回该键值。validator-rules.xml文件中的每个验证例行程序都用validator标记的msg属性指定错误消息的键值，如下所示： </P>
<P><PRE>&lt;validator name="required"
          classname="org.apache

.struts.validator.FieldChecks"
          method="validateRequired"
          methodParams="java.lang
.Object, org.apache.commons.validator
.ValidatorAction, org.apache.commons
.validator.Field, org.apache.struts
.action.ActionErrors, javax.servlet
.http.HttpServletRequest"
          msg="errors.required"&gt;
</PRE>
<P></P>
<P class=bodycopy>如果在验证例行程序运行时验证失败，则返回与msg属性指定的键值对应的消息。</P>
<P><SPAN class=bodycopy><FONT face=Arial size=2>下面的片段显示来自ApplicationResources.properties文件的验证出错时的默认消息集，它们由Struts示例应用程序提供。每个消息的键值对应于每个由validator-rules.xml文件中的验证例行程序所指定的消息，它们由Struts示例应用程序提供。</FONT></SPAN> </P>
<P><PRE># Error messages for Validator framework validations
errors.required={0} is required.
errors.minlength={0} cannot be less than {1} characters.
errors.maxlength={0} cannot be greater than {2} characters.
errors.invalid={0} is invalid.
errors.byte={0} must be a byte.
errors.short={0} must be a short.
errors.integer={0} must be an integer.
errors.long={0} must be a long.0.   errors.float={0} must be a float.

errors.double={0} must be a double.
errors.date={0} is not a date.
errors.range={0} is not in the range {1} through {2}.
errors.creditcard={0} is not a valid credit card number.
errors.email={0} is an invalid e-mail address.
</PRE>
<P></P>
<P><SPAN class=bodycopy><FONT face=Arial size=2>请注意，每条消息都有占位符，形式为{0}、{1}或{2}。在运行期间，占位符被另一个值代替，如所验证的域的名称。这一特性特别有用，它使你能够创建可被几个不同的域重复使用的通用验证错误消息。 </FONT></SPAN></P>
<P class=bodycopy>例如，下面给出required验证的错误消息errors.required： </P>
<P><PRE>errors.required={0} is required.
</PRE>
<P></P>
<P class=bodycopy>当你使用validation.xml文件中的该required验证时，必须定义用于替换该错误消息中的{0}的值，如下所示：</P>
<P><PRE>&lt;form name="auctionForm"&gt;
  &lt;field property="bid" depends="required"&gt;
    &lt;arg0 key="prompt.bid"/&gt;
  &lt;/field&gt;
&lt;/form&gt;
</PRE>
<P></P>
<P class=bodycopy>错误消息最多可以有4个占位符：{0}和{3}。这些占位符分别称为arg0到arg3，你可以通过使用arg0~arg3标记来指定它们。在上面的例子中，arg0标记指定了用于替换{0}占位符的值。该标记的key属性指定来自ApplicationResources.properties文件的一个消息键值，它的值用于替换占位符，如下所示： </P>
<P><PRE>prompt.bid=Auction Bid
</PRE>
<P></P>
<P class=bodycopy>使用消息键值代替占位符的值，这一方法使你不必在validation.xml文件中对替换值反复硬编码。但是，如果你不想使用Resource Bundle的键值/值机制来指定占位符的值，则可以使用arg0标记的如下语法显式地指定占位符的值：</P>
<P><PRE>&lt;arg0 key="Auction Bid" resource="false"/&gt;
</PRE>
<P></P>
<P class=bodycopy>在这个例子中，resource属性的值设为false，以便通知Validator要把该key属性指定的值作为占位符的值，而不要作为ApplicationResources.properties文件中消息的一个键值。</P>
<P class=parahead1>启用客户端验证 </P>
<P><SPAN class=bodycopy><FONT face=Arial size=2>Validator除了提供了简化服务器端表单数据验证过程的框架外，它还提供了执行客户端验证时易于使用的方法。在validator-rules.xml文件中定义的每一个验证例行程序都可以随意指定JavaScript代码，这些代码可以在浏览器（客户端上的）中运行，从而执行与服务器端进行的验证相同的验证过程。在客户端进行验证时，除非所有表单都通过验证，否则这些表单不允许被提交。</FONT></SPAN></P>
<P><SPAN class=bodycopy><FONT face=Arial size=2>为了启用客户端验证，必须在每个需要验证的JSP中放上Struts HTML Tag Library（标记库）的javascript标记，如下所示：</FONT></SPAN> </P>
<P><PRE>&lt;html:javascript formName="logonForm"/&gt;
</PRE>
<P></P>
<P class=bodycopy>javascript标记要求使用formName属性来为想要对其执行验证的表单指定validation.xml文件中给出的表单定义名，如下所示： </P>
<P><PRE>&lt;form name="logonForm"&gt;
  &lt;field property="username"
        depends="required"&gt;
    &lt;arg0 key="prompt.username"/&gt;
  &lt;/field&gt;
  &lt;field property="password"
        depends="required"&gt;
    &lt;arg0 key="prompt.password"/&gt;
  &lt;/field&gt;
&lt;/form&gt;
</PRE>
<P></P>
<P class=bodycopy>为表单定义指定的服务器端的所有验证都将在客户端运行。由于客户端验证用JavaScript执行，所以可以有多种方法不去执行它。要确保验证过程总是能运行，不论你是否选择启用了客户端验证，Validator都在服务器端执行这些验证。</P>
<P><SPAN class=parahead1><STRONG><FONT face=Arial>结论</FONT></STRONG></SPAN> </P>
<P class=bodycopy>Validator框架针对表单数据的验证提供了可配置的系统，从而为核心Struts框架添加了很多有价值的功能。通过把Validator框架用于你的应用程序，你可以节约时间并简化Struts应用程序的开发过程。 </P><img src ="http://www.blogjava.net/qq13367612/aggbug/17646.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qq13367612/" target="_blank">Sung</a> 2005-11-01 10:29 <a href="http://www.blogjava.net/qq13367612/articles/17646.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>配置Struts应用</title><link>http://www.blogjava.net/qq13367612/articles/17079.html</link><dc:creator>Sung</dc:creator><author>Sung</author><pubDate>Thu, 27 Oct 2005 09:32:00 GMT</pubDate><guid>http://www.blogjava.net/qq13367612/articles/17079.html</guid><wfw:comment>http://www.blogjava.net/qq13367612/comments/17079.html</wfw:comment><comments>http://www.blogjava.net/qq13367612/articles/17079.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qq13367612/comments/commentRss/17079.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qq13367612/services/trackbacks/17079.html</trackback:ping><description><![CDATA[<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=4>Struts应用采用两个基于XML的配置文件来配置,分别是web.xml和struts-cofig.xml文件.web.xml文件是配置所有web应用的而struts-config.xml文件是struts专用的配置文件,事实上也是可以根据需要给这个配置文件起其他名称的.<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=4>Web应用的发布描述文件:web应用发布描述文件可以在应用开着者,发布者和组装者之间传递配置信息,Web容器在启动的时候从该文件中读取配置信息,根据它来装载和配置web应用.文档类型定义DTD对XML文档的格式做了定义,DTD吧XML文档划分为元素,属性,实体每一种XML文档都有独自的DTD文件.可以从网上下载.<WEB-APP>元素是web.xml的根元素,其他元素必须嵌入在<WEB-APP>元素之内.要注意的是子元素也是有顺序的比如必须是首先<SERVLET>,然后<SERVLET-MAPPING>最后<TAGLIB>.<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN style="FONT-FAMILY: 宋体"><FONT size=4>为<SPAN lang=EN-US>Struts应用配置Web.xml文件:首先最重要的一步是配置ActionServlet,这个用<SERVLET>标签的servlet-name属性起一个名字叫action,然后用servlet-class属性指定ActionServlet的类.然后用<SERVLET-MAPPING>标签的servlet-name属性指定action,在用url-pattern指定接收范围是*.do的请求.不管应用中包含了多少子应用,都只需要配置一个ActionServlet,类来出来应用中的不同的功能,其实者就是不必要的,因为Servlet本身就是多线程的,而且目前Struts只允许配置一个ActionServlet.声明ActionServlet的初始化参数:<SERVLET>的<INIT-PARAM>子元素用来配置Servlet的初始化参数.param-name设置config参数名.param-value设置struts-config.xml的路径参数值.<o:p></o:p></SPAN></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN style="FONT-FAMILY: 宋体"><FONT size=4>配置欢迎使用清单<SPAN lang=EN-US>:如果客户访问Web的时候值是访问了WEB应用的根目录URL.没有具体的指定文件,Web会自动调用Web的欢迎文件.<WELCOME-FILE-LIST>元素来配置的.通过其中的<WELCOME-FILE>欢迎页面</WELCOME-FILE>来配置.<o:p></o:p></SPAN></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN style="FONT-FAMILY: 宋体"><FONT size=4>配置错误处理<SPAN lang=EN-US>:尽管Struts框架功能强大的错误处理机制,但是不能保证处理所有的错误或者异常.当错误发生时,如果框架不能处理这种错误,把错误抛弃给Web容器,在默认的情况下web容器会想客户端返回错误信息.如果想避免让客户看到原始的错误信息,可以在Web应用发布描述文件中配置<ERROR-PAGE>元素.通过<ERROR-CODE>404来定义错误的类型.然后通过<LOCATION>要处理错误的JSP页面来对错误进行处理.还可以用<EXCEPTION-TYPE>来设置异常,然后通过<LOCATION>来处理异常的JSP页面来处理异常.<o:p></o:p></SPAN></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN style="FONT-FAMILY: 宋体"><FONT size=4>配置<SPAN lang=EN-US>Struts标签库:这个就和以前学到的JSP自定义标签类似,配置元素为<TAGLIB>来配置.<TAGLIB-URI>这个指定标签库的uri,类似起一个名称.<TAGLIB-LOCATION>这个是标签库的位置也就是实际所在的路径.通过这样的方法引入一个标签库,然后在前台JSP页面就可以通过自己定义的URI来调用标签.<o:p></o:p></SPAN></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=4>Struts配置文件:struts-config.xml文件.首先研讨一下org.apache.struts.config包,在struts应用启动的时候会把Struts配置文件信息读取到内存中,并把它们存放在config包中相关的JavaBean类的实例中.包中的每一个类都和struts配置文件中特定的配置元素对应,ModuleConfig在Struts框架中扮演了十分重要的角色,它是整个config包的核心,在Struts运行时来存放整个应用的配置信息.如果有多个子应用都会有一个ModuleConfig对象,它和Struts文件根元素的<STRUTS-CONFIG>对应.根元素中包含<FORM-BEAN><ACTION><FORWARD>等元素.<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><STRUTS-CONFIG><FONT size=4>元素:时Struts配置文件的根元素,和它对应的配置类ModuleConfig类,<STRUTS-CONFIG>元素有8个子元素.他们的DTD定义是data-sources?form-bean? global-exception?global-forwards?action-mapping?controller?message-resources?plug-in*在Struts配置文件中,必须按照DTD指定的先手顺序来配置<STRUTS-CONFIG>元素的各个子元素,如果颠倒了这些子元素的顺序,会产生错误.<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><DATA-SOURCES><FONT size=4>元素:用来配置应用所需要的数据源,数据源负责创建和特定的数据库的连接.许多数据源采用连接池的机制实现.以便提高数据库访问的性能.JAVA语言提供了javax.sql.DataSource接口,所有的数据源都必须实现这个接口.许多应用服务器和Web服务器都提供了数据源组件.很多数据库厂商也提供了数据源的实现.<DATA-SOURCES>元素包含多个<DATA-SOURCE>子元素永远配置特定的数据源.他们可以包含多个<SET-PROPERTY>子元素用于设置数据源的各种属性.配置了数据源以后,就可以在Action类中访问数据源,在Action中定义了getDataSource(HttpRequest)方法,用于获取数据源对象的引用.然后可以利用DataSource对象调用getConnection获取一个连接对象对数据库进行操作.在配置文件中声明多个数据源的时候需要为每一个数据源分配唯一的Key值,通过这个来表示特定的数据源.获取特定的数据源的时候可以用dataSource = getDataSource(reqeust,”A”);<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FORM-BEANS><FONT size=4>元素:用来配置多个ActionForm,包含一个或者N个<FORM-BEAN>子元素.每个<FORM-BEAN>元素都包含多个属性.className指定和<FORM-BEAN>匹配的类.name指定该ActionForm的唯一标识符,这个属性是必须的以后作为引用使用.type指定ActionForm类的完整类名,这个属性也是必须的.注意包名也要加上.<FORM-PROPERTY>是指定动态的Form的元素,以后会深入了解.<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><GLOBAL-EXCEPTION><FONT size=4>元素:用于配置异常处理,元素可以包含一个或者多个<EXCEPTION>元素,用来设置JAVA异常和异常处理类ExceptionHandler之间的映射.className指定和元素对应的配置类,默认的不用动.handler指定异常处理类默认是ExceptionHandler.key指定在本地资源文件中异常的消息Key,path指定当前异常发生的时候转发的路径.scope指定ActionMessages实例存放的范围.type指定需要处理异常类的名字,必须的.bundle指定Resource Bundle.<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><GLOBAL-FORWARDS><FONT size=4>元素:用来声明全局转发,元素可以有一个或者N个<FORWARD>元素组成,用于把一个逻辑名映射到特定的URL,通过这种方法Action类或者JSP页面无需指定URL,只要指定逻辑名称就可以实现请求转发或者重定向.这样可以减少控制组件和视图的聚合.易于维护.className对应的配置类.contextRelative如果为true表示当path属性以/开头的时候,给出的是对应的上下文URL默认是false.name转发路径的逻辑名,必须写.path转发或者重定向的URL,必须写必须是以/开头.redirect设置为true的时候表示执行重定向操作,此项为false的时候,表示执行请求转发操作.重定向与请求转发的区别以后就是重定向是把请求生成应答给客户端然后在重新发送给定向的URL,浏览器地址栏会有显示.而转发就是直接把请求转发给本应用的另一个文件,不生成应答所以客户端IE没显示.<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><ACTION-MAPPING><FONT size=4>元素:包含一个或者N个<ACTION>元素,描述了从特定的请求路径到响应的Action的映射.在<ACTION>元素中可以包含多个<EXCEPTION>和<FORWARD>子元素,他们分别配置局部异常处理和局部转发.attribute设置Action关联的ActionForm在request或者session范围内的key.就是在request或者session共享内的名称.className对应配置元素的类.默认的是ActionMapping.forward指定转发URL路径include指定包含URL路径.input指定包含表单的URL,当表单验证失败的时候发送的URL.name,指定和该Action关联的Form名字.该名字必须是在form-bean中定义过的,可写可不写.path必须/开头的方位Action的路径.parameter指定Action配置参数.在Action的execute()方法中可以调用ActionMapping的getParameter()方法来读取匹配的参数.roles指定允许调用该Action的安全角色,多个角色之间逗号格开.scope指定Form的存在范围.默认是session.tyep指定Action的完整类名.unknown如果是true表示可以处理用户发出的所有的无效的ActionURL默认是false.validate指定是否调用ActionForm的validate方法.<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><CONTROLLER><FONT size=4>元素:用于配置ActionServlet.buffreSize指定上载文件的输入缓冲大小.该属性为可选默认4096.className指定元素对应的配置类,ControllerConfig.然后是contentType指定响应结果内容类型和字符编码,该属性为可选,默认是text/html如果在Action或者JSP网页也设置了类型内容,会覆盖这个.locale指定是否把Locale对象保存到当前用户的session中默认false.tempDir指定处理文件上载的临时工作目录.nochache如果是true在响应结果中加入特定的头参数.<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><MESSAGE-RESOURCES><FONT size=4>元素:用来配置Resource Bundle.用于存放本地文本消息文件.className元素对应的配置类.MessageResourcesConfig.factory指定消息的工厂类.key指定文件存放的Servlet对象中采用的属性Key.null指定如何处理未知消息.parameter指定消息的文件名.<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><PLUG-IN><FONT size=4>元素:用于配置Struts插件.<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN style="FONT-FAMILY: 宋体"><FONT size=4>配置多应用模块<SPAN lang=EN-US>:所有的子应用都可以共享同一个ActionServlet实例,但是每个子应用都有单独的配置文件.把应用划分为多个子应用模块.首先为每个应用创建单独的Struts配置文件,在web.xml的ActionServlet配置代码中添加几个子应用信息.采用<FORWARD>元素来实现应用之间的切换.<o:p></o:p></SPAN></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=4>Digester组件:是一个Apache的另一个开源代码项目.当Struts被初始化的时候,首先会读取并解析配置文件,框架采用Digester组件来且西配置文件.然后创建config包中的对象.者对象用于存放配置信息.<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN style="FONT-FAMILY: 宋体"><FONT size=4>其实配置文件不难<SPAN lang=EN-US>,只要都理其中的原理就OK了.真正实际的项目开发中,采用的工具例如Eclipse系列,提供了相应的插件,在创建一个Struts工程的时候配置文件的标签都是自动生成的,而我们只需要往里面填写属性就OK了. </SPAN></FONT></SPAN></P><img src ="http://www.blogjava.net/qq13367612/aggbug/17079.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qq13367612/" target="_blank">Sung</a> 2005-10-27 17:32 <a href="http://www.blogjava.net/qq13367612/articles/17079.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Struts视图组件</title><link>http://www.blogjava.net/qq13367612/articles/17078.html</link><dc:creator>Sung</dc:creator><author>Sung</author><pubDate>Thu, 27 Oct 2005 09:31:00 GMT</pubDate><guid>http://www.blogjava.net/qq13367612/articles/17078.html</guid><wfw:comment>http://www.blogjava.net/qq13367612/comments/17078.html</wfw:comment><comments>http://www.blogjava.net/qq13367612/articles/17078.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qq13367612/comments/commentRss/17078.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qq13367612/services/trackbacks/17078.html</trackback:ping><description><![CDATA[<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=4>Struts框架的视图负责为客户端提供动态的网页内容.主要是由JSP网页构成.还提供了Struts客户化标签和ActionForm Bean,这些组件提供对国际化,接收用户表单输入的数据,表单验证和错误处理等功能.视图是模型的外在表现形式,用户通过视图来了解模型的状态,同一个模型可以有多种视图.框架中视图由JSP组件构成,除此之外还包括以下组件:<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l0 level1 lfo1; tab-stops: list 39.0pt"><FONT size=4><SPAN lang=EN-US style="FONT-FAMILY: 宋体">1)<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN lang=EN-US style="FONT-FAMILY: 宋体">HTML文档<o:p></o:p></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l0 level1 lfo1; tab-stops: list 39.0pt"><FONT size=4><SPAN lang=EN-US style="FONT-FAMILY: 宋体">2)<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN lang=EN-US style="FONT-FAMILY: 宋体">JSP客户化标签<o:p></o:p></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l0 level1 lfo1; tab-stops: list 39.0pt"><FONT size=4><SPAN lang=EN-US style="FONT-FAMILY: 宋体">3)<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN lang=EN-US style="FONT-FAMILY: 宋体">JavaScripet和stylesheet<o:p></o:p></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l0 level1 lfo1; tab-stops: list 39.0pt"><FONT size=4><SPAN lang=EN-US style="FONT-FAMILY: 宋体">4)<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体">多媒体文件<SPAN lang=EN-US><o:p></o:p></SPAN></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l0 level1 lfo1; tab-stops: list 39.0pt"><FONT size=4><SPAN lang=EN-US style="FONT-FAMILY: 宋体">5)<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体">消息资源<SPAN lang=EN-US>(Resource Bundle)<o:p></o:p></SPAN></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l0 level1 lfo1; tab-stops: list 39.0pt"><FONT size=4><SPAN lang=EN-US style="FONT-FAMILY: 宋体">6)<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN lang=EN-US style="FONT-FAMILY: 宋体">ActionForm Bean<o:p></o:p></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=4>ActionForm属于一种Bean,什么是Bean呢?是可重用的平台独立的JAVA组件,JavaBean<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN style="FONT-FAMILY: 宋体"><FONT size=4>支持属性<SPAN lang=EN-US>,事件,方法和持久化.Struts框架仅仅利用了JavaBean的一小部分特性.Bean和普通的JAVA类很相似,不过它应该遵守以下的规范:<o:p></o:p></SPAN></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l2 level1 lfo2; tab-stops: list 39.0pt"><FONT size=4><SPAN lang=EN-US style="FONT-FAMILY: 宋体">1)<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体">必须提供不带参数的构造方法<SPAN lang=EN-US><o:p></o:p></SPAN></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l2 level1 lfo2; tab-stops: list 39.0pt"><FONT size=4><SPAN lang=EN-US style="FONT-FAMILY: 宋体">2)<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体">为<SPAN lang=EN-US>Bean的所有属性提供公共的get/set方法<o:p></o:p></SPAN></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l2 level1 lfo2; tab-stops: list 39.0pt"><FONT size=4><SPAN lang=EN-US style="FONT-FAMILY: 宋体">3)<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体">对于<SPAN lang=EN-US>boolean类型的属性要提供isXXX()方法,那么该方法返回Boolean类型的属性<o:p></o:p></SPAN></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l2 level1 lfo2; tab-stops: list 39.0pt"><FONT size=4><SPAN lang=EN-US style="FONT-FAMILY: 宋体">4)<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体">对于数组类型的属性<SPAN lang=EN-US>,应该提供getXXX(int index)和setXXX(index,value)方法来读取和设置数组元素.<o:p></o:p></SPAN></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=4>Struts利用JavaBean来创建数据传输对象,Data Transfer Object简称DTO,用于不同的层之间传递数据.<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=4>ActionForm是Struts框架提供的DTO,用于在视图层和控制器之间传递HTML表单数据,控制层可以从ActionForm中读取用于输入的表单数据,也可以把来自模型的数据保存到ActionForm中,然后返回给视图.ActionForm具有表单验证的功能.由于ActionForm类使用了ServletAPI,因此不提倡直接把ActionForm传递给模型,而是应该在控制层把它的数据重新组装到自定义的DTO中,在把它传递给模型层.在配置文件中<ACTION>元素的scope属性设置ActionForm的范围默认是session.Action的生命周期如下:<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l1 level1 lfo3; tab-stops: list 39.0pt"><FONT size=4><SPAN lang=EN-US style="FONT-FAMILY: 宋体">1)<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体">控制器接收到请求<SPAN lang=EN-US><o:p></o:p></SPAN></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l1 level1 lfo3; tab-stops: list 39.0pt"><FONT size=4><SPAN lang=EN-US style="FONT-FAMILY: 宋体">2)<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体">从<SPAN lang=EN-US>request或者session范围内取出ActionForm的实例,没有就新建一个<o:p></o:p></SPAN></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l1 level1 lfo3; tab-stops: list 39.0pt"><FONT size=4><SPAN lang=EN-US style="FONT-FAMILY: 宋体">3)<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体">调用<SPAN lang=EN-US>Form的reset()方法<o:p></o:p></SPAN></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l1 level1 lfo3; tab-stops: list 39.0pt"><FONT size=4><SPAN lang=EN-US style="FONT-FAMILY: 宋体">4)<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体">把<SPAN lang=EN-US>ActionForm实例保存到request或者session范围中<o:p></o:p></SPAN></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l1 level1 lfo3; tab-stops: list 39.0pt"><FONT size=4><SPAN lang=EN-US style="FONT-FAMILY: 宋体">5)<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体">把用户输入的表单数据装到<SPAN lang=EN-US>ActionForm中<o:p></o:p></SPAN></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l1 level1 lfo3; tab-stops: list 39.0pt"><FONT size=4><SPAN lang=EN-US style="FONT-FAMILY: 宋体">6)<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体">如果<SPAN lang=EN-US>validate属性是true则调用validate方法<o:p></o:p></SPAN></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l1 level1 lfo3; tab-stops: list 39.0pt"><FONT size=4><SPAN lang=EN-US style="FONT-FAMILY: 宋体">7)<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体">验证成功就把<SPAN lang=EN-US>ActionForm实例以参数传递给Action的execute方法,如果失败把请求转发给<ACTION>的input属性指定的Web组件(大多JSP),ActionForm依然保存在request或者session范围内.<o:p></o:p></SPAN></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=4>Struts框架的ActionForm类是抽象类,必须在应用中创建它的子类,来捕获具体的HTML表单数据.其中的属性和表单的属性一一对应.如果配置文件中<FORM-BEAN>元素的name属性和<ACTION>元素的name属性匹配,<ACTION>元素中的的validate属性为true.的时候.validate方法会被调用,基类的返回值是null,如果扩展了ActionForm类,那么应该覆盖validate方法,这个方法主要负责检验格式和语法,而不负责检查数据是否符合业务逻辑.对于一个请求控制器首先调用的是ActionForm的reset()方法,然后在把用户输入的表单数据组装到ActionFrom中.这个方法负责恢复属性的默认值,例如把boolean类型的属性设置成true或者false,把字符串设置为null或者某个初始值.感觉如果ActionForm在request范围内,那么对于每个新的请求都会创建新的ActionForm实例,当新的实例创建后,它的属性就是默认值,所以在写reset()方法就没什么意义了.如果是在session范围内,一个实例可以接收多次请求,那么reset()方法就非常有用了!如果是从request或者session范围中取出Form的值,可以用例如Form f=(Form)session.getAttribute(“Form”)的方法取出.这时Form的名字就是共享对象中的一个key不过如果是在Action的execute()方法中就很简单了,可以Form f=(Form)Form这样来获取一个Form也可以通过其中的具体的get方法来获取具体的属性,注意一定要转换类型.有的时候,由于表单的数量太多,无法在同一个页面显示,可以把他们拆分成多个表单,分多个页面显示.在这种情况下,即可以为每一个表单创建一个单独的ActionForm,也可以只创建一个,和多个表单对应.<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN style="FONT-FAMILY: 宋体"><FONT size=4>下面研讨以下如何使用动态的<SPAN lang=EN-US>ActionForm,在Struts框架中,ActionForm对象用来包装HTML表单数据,并能够动态返回用于显示给用户的数据.自己写的Form必须符合JavaBean的规范,继承ActionForm同时可以选择的重写reset()和validate()方法.虽然ActionForm简化了Web开发,但是对于大型的项目如果HTML表单改变对应的ActionForm也一定要修改,所以Strust1.1对此做出了修改引入了动态的DynaActionForm类.它支持载配置文件中完成ActionForm的全部配置,没必要写额外的程序来创建具体的ActionForm类,配置动态的方法是在配置文件中一个<FORM-BEAN>元素.如下:<o:p></o:p></SPAN></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FORM-BEANS><o:p><FONT size=4></FONT></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 10.5pt; mso-char-indent-count: 1.0; mso-char-indent-size: 10.5pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><SPAN style="mso-spacerun: yes"><FONT size=4>&nbsp;&nbsp; </FONT></SPAN><FORM-BEAN <o:p name="”loginForm”"></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 84pt; mso-char-indent-count: 8.0; mso-char-indent-size: 10.5pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=4>type=”org.apache.struts.action.DynaActionForm”<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 84pt; mso-char-indent-count: 8.0; mso-char-indent-size: 10.5pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=4>//上面是指定DynaActionForm类,名字是loginForm<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 36.75pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FORM-PROPERTY name="”username”" type="”java.lang.String”/"><o:p><FONT size=4></FONT></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 36.75pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FORM-PROPERTY name="”password”" type="”java.lang.String”/"><o:p><FONT size=4></FONT></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 36.75pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"></FORM-BEAN><o:p><FONT size=4></FONT></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"></FORM-BEANS><o:p><FONT size=4></FONT></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FORM-BEAN><FONT size=4>元素的子元素<FORM-PROPERTY>来设置动态的ActionForm属性.name指定属性的名称,type指定属性的类型.ActionForm的类型表单的类型.如果要设置JAVA的基本类型,在配置的时候应该用相应的包装类型来替换,例如int的包装类型就是Integer.动态的Form类DynaActionForm提供了initialize()方法,它把调但所有的属性都恢复为默认值.表单属性默认值由<FORM-BEAN>元素的<FORM-PEOPRETY>子元素的initial属性来决定.如果没设置,则表单的默认属性由其JAVA类型来自动决定.例如对象类型的默认就是null.整型是0.Boolean是false.如果希望Struts每次把表单数据组装到动态的ActionForm之前,先把所有的属性恢复为默认值,可以定义一个DynaActionForm的子类,然后覆盖reset()方法,在其中调用initalize()方法就OK了.<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=4>Action类和JSP都可以访问动态的ActionForm类,使用方法与标准的Form大致相同.有一点区别就是如果使用标准的Form类,用get和set方法就可以,而DynaActionForm是把所有的属性保存在一个Map类对象中.访问的方法如下:<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=4>public Object get(String name)<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=4>public void set(Strig name,Object value)<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=4>DynaActionForm基类的validate()方法没有提供任何默认的验证行为,可以定义扩展它的子类,然后覆盖validate()方法,但是以编程的方法来验证动态的ActionForm违背了Struts框架提供的机制.幸运的是,可以采用另一种机制.Validator框架来完成验证,如果想了解Validator验证框架,不要急继续关注我的Blog,我还会漫漫道来.<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN style="FONT-FAMILY: 宋体"><FONT size=4>今天侧重研讨了构成<SPAN lang=EN-US>Struts视图组件的ActionForm,因为它非常重要,必须彻底的了解它算能真正的学会Struts,它可以存放在session和request范围内.下面说一些开发技巧希望能对关注我的Blog的朋友们,在如后的开发中有所帮助.<o:p></o:p></SPAN></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l3 level1 lfo4; tab-stops: list 39.0pt"><FONT size=4><SPAN lang=EN-US style="FONT-FAMILY: 宋体">1)<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体">在<SPAN lang=EN-US>HTML表单中定义<HTML;HIDDEN properyt="”page”/">隐藏字段来标示当前页面<o:p></o:p></SPAN></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l3 level1 lfo4; tab-stops: list 39.0pt"><FONT size=4><SPAN lang=EN-US style="FONT-FAMILY: 宋体">2)<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体">在<SPAN lang=EN-US>ActionForm中定义page属性,它和表单中的隐藏字段page对应<o:p></o:p></SPAN></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l3 level1 lfo4; tab-stops: list 39.0pt"><FONT size=4><SPAN lang=EN-US style="FONT-FAMILY: 宋体">3)<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体">在<SPAN lang=EN-US>ActionForm的reset()方法中,只能把当前表单相关的属性值恢复默认值.<o:p></o:p></SPAN></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l3 level1 lfo4; tab-stops: list 39.0pt"><FONT size=4><SPAN lang=EN-US style="FONT-FAMILY: 宋体">4)<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体">在<SPAN lang=EN-US>ActionFomr的validate()方法中,只能对当前表单的相关属性进行验证.<o:p></o:p></SPAN></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l3 level1 lfo4; tab-stops: list 39.0pt"><FONT size=4><SPAN lang=EN-US style="FONT-FAMILY: 宋体">5)<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体">在配置<SPAN lang=EN-US>ActionForm和Actin的映射的时候,应该把ActionForm的范围设为session<o:p></o:p></SPAN></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=4>Struts框架还引入了DynaActionForm类,是动态创建ActionForm的类,要注意的如下:<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: -10.5pt; mso-char-indent-count: -1.0; mso-char-indent-size: 10.5pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=4>1) </FONT>
<FORM><FONT size=4>的<FORM-PORPERTY>子元素是用来配置动态Form的.type属性指定ActionForm的属性的类型.如果是JAVA基本类型,则用JAVA包装类型.<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: -10.5pt; mso-char-indent-count: -1.0; mso-char-indent-size: 10.5pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=4>2)提倡使用Validator框架来验证动态的ActionForm.这样可以避免用编程的方法来实现validate()方法.<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: -10.5pt; mso-char-indent-count: -1.0; mso-char-indent-size: 10.5pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=4>3)通常不需要扩展DynaActionForm类,如果需要提供属性的复位功能,则扩展此类,然后重写reset方法中去调用initialize()方法进行复位,通常ActionForm在Session范围内使用此方法.<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=4>4)如果访问DynaActionForm的属性,应该调用以下方法:<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=4><SPAN style="mso-spacerun: yes">&nbsp; </SPAN>public Object(String name)<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=4><SPAN style="mso-spacerun: yes">&nbsp; </SPAN>public void set(String name,Object value)<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=4><SPAN style="mso-spacerun: yes">&nbsp; </SPAN>name参数代表属性的名称.<o:p></o:p></FONT></SPAN></P></FORM><img src ="http://www.blogjava.net/qq13367612/aggbug/17078.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qq13367612/" target="_blank">Sung</a> 2005-10-27 17:31 <a href="http://www.blogjava.net/qq13367612/articles/17078.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Struts模型组件</title><link>http://www.blogjava.net/qq13367612/articles/17077.html</link><dc:creator>Sung</dc:creator><author>Sung</author><pubDate>Thu, 27 Oct 2005 09:30:00 GMT</pubDate><guid>http://www.blogjava.net/qq13367612/articles/17077.html</guid><wfw:comment>http://www.blogjava.net/qq13367612/comments/17077.html</wfw:comment><comments>http://www.blogjava.net/qq13367612/articles/17077.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qq13367612/comments/commentRss/17077.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qq13367612/services/trackbacks/17077.html</trackback:ping><description><![CDATA[<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><FONT size=4><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">模型组件代表应用的业务数据</SPAN><SPAN style="FONT-FAMILY: 宋体">和逻辑<SPAN lang=EN-US>.坦率的说Struts框架并没有为设计和创建模型组件提供线程的框架.不过Strtus允许使用其他的模型组件来处理应用的业务领域.如EJB活JDO以及常规的JavaBean和ORM.<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p></o:p></SPAN></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><SPAN style="FONT-FAMILY: 宋体"><FONT size=4>模型是应用中重要的一部分<SPAN lang=EN-US>,它包含了业务实体和业务规则,负责访问和更新持久化数据.应该把所有的模型组件放在系统中的同一个位置,这样利于维护数据和完整性,提高可重用性.模型和视图以及控制器之间保持独立,在分层框架结构中.位于上层的视图和控制器依赖于下层的模型的实现,而下层的模型不应该依赖于上层的视图在控制器的实现.如果在模型组件中通过JAVA的import语句引入了视图和控制器组件,这样的程序就垃圾了.<o:p></o:p></SPAN></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><SPAN style="FONT-FAMILY: 宋体"><FONT size=4>在科学和工程技术领域<SPAN lang=EN-US>,模型是一个很有用途的概念,它可以用来模拟一个真是的系统.在软件开发领域,模型用来表示真是世界的实体.在软件开发的不同阶段,需要为目标系统创建不同的模型.可以采用面向对象的建模语言UML来描述.<o:p></o:p></SPAN></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><SPAN style="FONT-FAMILY: 宋体"><FONT size=4>在建模之前首先要对问题域进行详细的分析<SPAN lang=EN-US>,确定用例,接下来可以根据用例来创建概念模型.概念模型用来模拟问题域中的真实实体.概念模型描述了每个实体的概念和属性,以及实体之间的关系.这个阶段并不描述实体的行为.比如说商品和商品目录之间存在多对多的关系,这是因为一个商品目录包含多个商品,而一个商品也可以属于多个商品目录.<o:p></o:p></SPAN></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><SPAN style="FONT-FAMILY: 宋体"><FONT size=4>设计模型需要在概念模型的基础上设计<SPAN lang=EN-US>.可以用UML类框图,活动图以及状态图来描述设计模型.根据UML语言,类之间存在四种关系:<o:p></o:p></SPAN></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39.75pt; TEXT-INDENT: -18pt; mso-list: l0 level1 lfo1; tab-stops: list 39.75pt"><FONT size=4><SPAN lang=EN-US style="FONT-FAMILY: 宋体">1)<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体">关联<SPAN lang=EN-US>(Association):就是类之间的引用关系,<o:p></o:p></SPAN></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39.75pt; TEXT-INDENT: -18pt; mso-list: l0 level1 lfo1; tab-stops: list 39.75pt"><FONT size=4><SPAN lang=EN-US>2)<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体">依赖<SPAN lang=EN-US>(Dependency):是指类之间的访问关系.</SPAN></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39.75pt; TEXT-INDENT: -18pt; mso-list: l0 level1 lfo1; tab-stops: list 39.75pt"><FONT size=4><SPAN lang=EN-US>3)<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体">累积<SPAN lang=EN-US>(Aggregation)就是说整体与个体之间的关系,可以把累积看作一种强关联关系.</SPAN></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39.75pt; TEXT-INDENT: -18pt; mso-list: l0 level1 lfo1; tab-stops: list 39.75pt"><FONT size=4><SPAN lang=EN-US>4)<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体">一般化<SPAN lang=EN-US>(Generalization):是类之间的继承关系.</SPAN></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN style="FONT-FAMILY: 宋体"><FONT size=4>如果想了解如何为应用创建合理的面向对象的设计模型<SPAN lang=EN-US>,可以浏览<A href="http://www.uml.org/"><FONT color=#4371a6>www.uml.org</FONT></A>深入了解UML语言.<o:p></o:p></SPAN></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN style="FONT-FAMILY: 宋体"><FONT size=4>业务对象<SPAN lang=EN-US>BO(Business Object),是对真是世界的实体的软件抽象.它可以代表业务领域中的人,地点,事务或者概念.业务对象包括状态和行为.如果一个类可以作为业务对象它应该具有以下特征:<o:p></o:p></SPAN></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l2 level1 lfo2; tab-stops: list 39.0pt"><FONT size=4><SPAN lang=EN-US style="FONT-FAMILY: 宋体">1)<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体">包含状态和行为<SPAN lang=EN-US>.<o:p></o:p></SPAN></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l2 level1 lfo2; tab-stops: list 39.0pt"><FONT size=4><SPAN lang=EN-US>2)<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体">代表业务领域的人<SPAN lang=EN-US>,地点,事务或概念.</SPAN></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l2 level1 lfo2; tab-stops: list 39.0pt"><FONT size=4><SPAN lang=EN-US>3)<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体">可以重用<SPAN lang=EN-US>.</SPAN></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN style="FONT-FAMILY: 宋体"><FONT size=4>业务对象客分为三种类型<SPAN lang=EN-US>:<o:p></o:p></SPAN></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l1 level1 lfo3; tab-stops: list 39.0pt"><FONT size=4><SPAN lang=EN-US style="FONT-FAMILY: 宋体">1)<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体">实体业务对象<SPAN lang=EN-US>.<o:p></o:p></SPAN></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l1 level1 lfo3; tab-stops: list 39.0pt"><FONT size=4><SPAN lang=EN-US>2)<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体">过程业务对象<SPAN lang=EN-US>.</SPAN></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l1 level1 lfo3; tab-stops: list 39.0pt"><FONT size=4><SPAN lang=EN-US>3)<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体">事件业务对象<SPAN lang=EN-US>.</SPAN></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 21pt"><SPAN style="FONT-FAMILY: 宋体"><FONT size=4>实体对象就是具体的对象<SPAN lang=EN-US>,比如人,地点,商品,订单.过程对象就是业务过程或者流程,<o:p></o:p></SPAN></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN style="FONT-FAMILY: 宋体"><FONT size=4>他们通常依赖于实体对象<SPAN lang=EN-US>.可以把业务领域的动词,比如登陆,发货等作为过程对象.事件对象代表一些时间如比异常,警告,超时,错误.这些事件通常由系统中的行为触发器激活.在应用使用业务对象好处很多,最重要的一点就是业务对象提供了通用的技术术语和概念,不管技术人员还是非技术人员都可以共享理解它们.此外业务对象可以隐藏实现的细节,对外只暴露接口,提高了安全性.<o:p></o:p></SPAN></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN style="FONT-FAMILY: 宋体"><FONT size=4>通常<SPAN lang=EN-US>,持久化意味着通过手工或者其他方法输入到应用中的数据,能够在应用结束运行后依然存在.即使应用运行结束或者计算机关闭,这些信息依然存在.当应用中的业务对象在内存中创建后,他们不可能永远存在.最后,他们要么消失,要么就要被持久化到数据库中.内存无法永久保留数据,因此必须对业务对象进行持久化.关系型数据库被广泛用来存储数据.关系型数据库中存放的是关系型数据.它是非面向对象的.把业务对象映射到非面向对象的数据库中,因为对象由状态和行为组成,而关系数据库则由表组成.对象之间的各种关系和关系型数据库中表之间的关系并不一一对应.例如对象之间继承关系就不能直接映射到关系型数据库中了.而对于JAVA应用,可以直接通过JDBC编程来访问数据库.JDBC可以说是访问持久化数据层的最原始最直接的方法,如果数据模型非常复杂,这里我推荐用Hibernate架构来进行持久化层的处理.<o:p></o:p></SPAN></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN style="FONT-FAMILY: 宋体"><FONT size=4>因为<SPAN lang=EN-US>Struts中本身不包含处理模型的架构,所以在这里只是简单的对模型进行了介绍.至于具体的知识可以研究Ejb,JavaBean等技术.至于持久化层的hibernate架构,这里我推荐阅读孙卫琴的:&lt;&lt;精通Hibernate&gt;&gt;.</SPAN></FONT></SPAN></P><img src ="http://www.blogjava.net/qq13367612/aggbug/17077.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qq13367612/" target="_blank">Sung</a> 2005-10-27 17:30 <a href="http://www.blogjava.net/qq13367612/articles/17077.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Struts控制器组件</title><link>http://www.blogjava.net/qq13367612/articles/17076.html</link><dc:creator>Sung</dc:creator><author>Sung</author><pubDate>Thu, 27 Oct 2005 09:29:00 GMT</pubDate><guid>http://www.blogjava.net/qq13367612/articles/17076.html</guid><wfw:comment>http://www.blogjava.net/qq13367612/comments/17076.html</wfw:comment><comments>http://www.blogjava.net/qq13367612/articles/17076.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qq13367612/comments/commentRss/17076.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qq13367612/services/trackbacks/17076.html</trackback:ping><description><![CDATA[<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=4>Struts控制器组件负责接收用户的请求,更新模型.以及选择合适的视图组件返回给客户端.控制器组件有助于将模型和视图分离,有了这种分离可以在同一个模型的基础上得心应手的开发多种模型的视图.主要是ActionServlet框架中央控制器,RequestProcessor每个子应用的模块处理器,Action负责处理具体的业务的组件.Struts采用ActionServlet和RequestProcessor组件进行集中控制,并且采用Action组件来完成具体的业务单项处理.控制器组件的控制机制:主要认识是接受用户请求,根据用户的请求调用合适的模型来执行业务逻辑,获取业务逻辑的结果,根据当前状态以及业务逻辑执行结果选择合适的视图组件返回给客户端.<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=4>ActionServlet类:是Struts框架的核心控制器组件,所有的用户请求都先由它来处理,然后再由它把请求转发给其他组件.容器启动的时候或者用户首次请求ActionServlet的时候加载ActionServlet类在这两种情况下,容器都会在ActionServlet被加载后立即执行它的init()方法,这可以保证当ActionServlet处理用户请求的时候已经被初始化.至于具体的初始化方法我们不用去管,下面研究一下ActinServlet的process()方法.当主控制器实例接收到Http请求后,在doGet()或者doPost()方法中都会调用process()方法来处理请求.在这个方法中首先调用selectModule()方法,这个方法选择负责处理用于请求的子应用模块.然后把子应用模块相关的ModuleConfig和MessageResources对象存储到request范围内,这使得框架的其余组件可以方便地从request范围内读取这些对象.从而获取应用配置信息和消息资源.ActionServlet是可以派生子类的但是感觉没什么意义了,多数的功能都被移动到了RequestProcessor类中,以便减轻ActionServlet的负担.<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=4>RequestProcessor类:对于应用模块,每个子应用模块都由各自的RequestProcessor实例.在ActionServlet的process()方法中一旦选择了正确的子应用模块,就会调用子应用的模块的RequestProcessor类,每个子应用模块都可以拥有单纯的RequestProcessor类.开发人员可以很方便的创建客户化的RequestProcessor类.<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=4>Action类:是用户请求和业务逻辑之间的桥梁,每个Action充当客户的一项业务代理.在RequestProcessor类预处理请求的时候.在创建了Action的实例后,就调用自身的processActionPerForm()方法,该方法调用Action的execute()方法.为了确保线程安全thread-safe,在一个应用的生命周期中.Struts框架只会为每个Action类创建一个Action实例.所有的客户请求共享同一个Action实例.并且所有的请求线程可以执行它的execute方法.Action类的execute()方法返回一个ActionForward对象,代表了Web资源的逻辑对象,这里的Web资源可以是JSP页面,JAVA servlet或者Action.从execute()方法返回的对象有两种方法:创建一个动态的ActionForward实例和在配置文件的action元素里的子元素<FORWARD>元素.在execute()方法只需要调用mapping实例参数的findForward()方法,来获得特定的ActionForward对象.<ACTION>元素的roles属性是指定这个Action的用户必须具备的安全角色.多个角色之间以逗号隔开.<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN style="FONT-FAMILY: 宋体"><FONT size=4>利用<SPAN lang=EN-US>Token解决重复提交:在某些情况下,如果用户对同一个HTML表单多次提交,Web应用必须能够判断用户的重复提交的行为,以做出相应的处理.可以利用同步令牌Token机制来解决Web应用重复提交的问题.Struts给出了一个参考实例.Action类中提供了一系列和Token相关的方法判断存储在当前用户会话中的令牌值和请求参数中的令牌是否匹配,如果匹配返回true.否则返回false.方法是protected boolean isTokenValid(request).<o:p></o:p></SPAN></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN style="FONT-FAMILY: 宋体"><FONT size=4>实用类<SPAN lang=EN-US>:RequestUtils类:org.apache.struts.util.RequestUtlis为Struts框架提供了一些处理请求的通用的方法.ModuleUtils类:org.apache.strtus.taglib.ModuleUtils类提供了处理子应用应用模块的实用方法.Globals类:org.apache.struts.Globals类提供了一组公共类型的静态常量.<o:p></o:p></SPAN></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN style="FONT-FAMILY: 宋体"><FONT size=4>控制器组件的核心技术可以说就是<SPAN lang=EN-US>Servlet,控制器也是Struts的灵魂也是MVC模式的核心,所以如果想学好Struts就必须彻底的了解控制器的运行原理.</SPAN></FONT></SPAN></P><img src ="http://www.blogjava.net/qq13367612/aggbug/17076.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qq13367612/" target="_blank">Sung</a> 2005-10-27 17:29 <a href="http://www.blogjava.net/qq13367612/articles/17076.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Struts配置文件简介</title><link>http://www.blogjava.net/qq13367612/articles/17064.html</link><dc:creator>Sung</dc:creator><author>Sung</author><pubDate>Thu, 27 Oct 2005 08:26:00 GMT</pubDate><guid>http://www.blogjava.net/qq13367612/articles/17064.html</guid><wfw:comment>http://www.blogjava.net/qq13367612/comments/17064.html</wfw:comment><comments>http://www.blogjava.net/qq13367612/articles/17064.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qq13367612/comments/commentRss/17064.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qq13367612/services/trackbacks/17064.html</trackback:ping><description><![CDATA[<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Struts framework根据配置文件使得ServletAction，ActionMapping，Action，ActionForm这几个不同层次的组件相互交互，协调的工作。这些配置文件是在系统启动的时候，读入并保存于内存中，供控制器使用的。</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Struts framework主要包括三部分的配置描述，一个是指定有关Struts Controller及其相关的的配置描述（Initialization Parameters），一个是对struts tag lib的描述，一个是Struts组件（ActionMapping，Action，ActionForm）之间相互映射协调的关系</P>
<P>&nbsp;</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;因为Struts Controller的主要类ActionServlet是继承自HttpServlet，所以必须像配置一个Servlet那样在部署描述符（Web.xml ）中配置ActionServlet类及其访问映射。</P>
<P>&nbsp;&nbsp; 当第一次创建基于Struts的Web应用程序时，将为您创建一个部署描述符，这通常就足够了。该文件包括下列条目：</P>
<P>l、&lt;servlet&gt;条目定义用于Web应用程序的servlet (在本例中，这是唯一的servlet)：</P>
<P>— &lt;servlet-name&gt; 和&lt;servlet-class&gt;指示ActionServlet (标识为“操作”)接收HTTP请求并确定如何响应。</P>
<P>— &lt;init-param&gt;表示servlet初始化参数.</P>
<P>— “config”指示ActionServlet的行为由指定的配置文件来指导，该配置文件通常具有以下名称：</P>
<P>\WEB-INF\struts-config.xml</P>
<P>— “debug”具有整数值，它指示将有关处理的详细信息写至控制台的程度。“0”表示不生成任何Debug信息。</P>
<P>— “detail”具有整数值，它指示将“映射”详细信息(如后面所述)写至控制台的程度。</P>
<P>―&nbsp; &lt;load-on-startup&gt;导致在启动应用程序时装入servlet。</P>
<P>—&nbsp; &lt;servlet-mapping&gt;元素标识这样的命名模式：当命名模式由URL进行匹配时，Web服务器就将控制权移交给ActionServlet。考虑下面各种情况：</P>
<P>―&nbsp; 访问了ActionServlet，原因是“操作”(&lt;servlet-mapping&gt;中的&lt;servlet-name&gt;元素的内容)与“操作”(&lt;servlet&gt;中的&lt;servlet-name&gt;元素的内容)相匹配。</P>
<P>— &lt;servlet-mapping&gt;元素指定URL的结尾的命名模式。每个URL的开头都是应用程序上下文路径。按照惯例，ActionServlet调用对象以响应与命名模式“*.do”(其中“*”是通配符)一致的URL。</P>
<P>— &lt;welcome-file-list&gt;元素指示获得初始控制权的特定于应用程序的代码；在本例中，Web服务器直接从Web Content目录中调用index.jsp。</P>
<P>— &lt;error-page&gt;元素指示显示哪个JSP来响应错误;在本例中，错误为如下所示：</P>
<P>―&nbsp; 404&nbsp; (找不到资源)</P>
<P>―&nbsp; 500&nbsp; (Web服务器内部发生错误)</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;每个&lt;taglib&gt;元素都使相对URL(相对于Web.xml)与标记库描述符(相对于Web应用程序根目录)相关联。每个JSP都可以使用同一个URL来表示给定的标记库，而Web.xml确定引用了哪个文件。</P>
<P>有关struts tag lib的配置描述<BR>&nbsp;&nbsp;&nbsp; 如果你的web application打算使用Struts的taglib，那么你有必要在web.xml中对struts taglib进行配置描述。</P>
<P>有关Struts Action Mapping的配置描述<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;作为先前描述的web.xml设置的结果，Web应用程序服务器将请求的一个子集按路径发送至ActionServlet，它通常调用一系列操作和JSP。ActionServlet的响应是基于配置文件struts-config.xml的内容的。有关其DTD文档的描述，请参考<A href="http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd"><STRONG>这里</STRONG></A>。</P>
<P>&nbsp;&nbsp;&nbsp; 一般struts-config（version1.1）包含了如下几个部分：</P>
<P>&nbsp;&nbsp;&nbsp;（1）form-bean</P>
<P>&nbsp;&nbsp;&nbsp;（2）global-forwards</P>
<P>&nbsp;&nbsp;&nbsp;（3）action-mappings</P>
<P>&nbsp;&nbsp;&nbsp;（4）data-sources</P>
<P>&nbsp;</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;对于这样的一个请求（例如，表示为“/login.do”），Struts框架将会执行下列步骤：</P>
<P>1、&nbsp;&nbsp;&nbsp;&nbsp;寻找操作类对象（继承org.&nbsp;apache.struts.action.Action的类）<BR>2、&nbsp;&nbsp;&nbsp;&nbsp;ActionServlet调用操作类对象的执行方法<BR>操作类中的执行方法的特征符为如下所示：<BR>public&nbsp;ActionForward&nbsp;&nbsp;execute(<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ActionMapping&nbsp;mapping,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ActionForm&nbsp;form,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HttpServletRequest&nbsp;request,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HttpServletResponse&nbsp;response)<BR>&nbsp;&nbsp;&nbsp;&nbsp;映射对象（ActionMapping），它包含指示如何响应方法的每个可能结果的规则（“映射”）<BR>&nbsp;&nbsp;&nbsp;&nbsp;Struts表单bean（ActionForm），它保存发送至HTML表单或接收自HTML表单的数据<BR>&nbsp;&nbsp;&nbsp;&nbsp;请求和响应对象（HttpServletReques/&nbsp;HttpServletResponse）<BR><BR>3、&nbsp;&nbsp;&nbsp;&nbsp;从执行方法返回ActionForward对象，用于指导ActionServlet接着访问哪个操作类或JSP<BR>返回的ActionForward对象中的信息取决于两个值：<BR>&nbsp;&nbsp;&nbsp;&nbsp;方法的结果（如在“成功”或“故障”等字符串中所述）<BR>&nbsp;&nbsp;&nbsp;&nbsp;映射对象，它包含从Struts配置文件中读取的信息<BR><BR><BR>要弄明白某些运行时关系，要明白struts-config.xml该文件包括下面的一组条目：<BR>&nbsp;&nbsp;&nbsp;&nbsp;＜form-beans＞标记标识每个表单bean<BR>&nbsp;&nbsp;&nbsp;&nbsp;＜action-mappings＞标记包括用于指导应用程序流的信息，每个＜action＞子标记都使相对URL与操作类和潜在的后续操作相关。<BR>Form-bean元素<BR>Struts配置文件中的一个示例＜form-bean＞子元素为如下所示：<BR>　&lt;form-bean&nbsp;name=“registerForm”&nbsp;&nbsp;type=“strutscommon.RegisterForm”/&gt;<BR>每个&lt;form-bean&gt;子元素都包括下列属性：<BR>name<BR>表单bean的名称，稍后在配置文件中会用到。ActionServlet举例说明了该bean（如果需要的话）并在将对bean的引用存储在请求或会话对象中时将该名称用作键。<BR>type<BR>　　　　　类的全限定名称，它继承org.apache.struts.action.ActionForm该类必须在类路径中。接受“Struts贸易样本”中的注册的表单bean包括HTML注册表单中每个字段的getter&nbsp;和setter方法。该bean还包括验证方法，如下节“验证”中所述。<BR>Action元素<BR>&nbsp;&nbsp;&nbsp;Struts配置文件中的一个示例＜action＞元素为如下所示：<BR>　　&lt;action&nbsp;path=“/register”<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;type=“strutsEGL.RegisterAction”<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name=“registerForm”<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;input=“/register.jsp”<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;scope=“request”<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;forward&nbsp;name=“success”path=“/home.do”/&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;&nbsp;forward&nbsp;name=“failure”path=“/register.jsp”/&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/action&gt;<BR>每个＜action＞元素都包括下列属性中的某些属性或所有属性：<BR>&nbsp;path<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;将请求指定为非限定URL，不带文件扩展名（例如，“/register”）请求是根据＜action＞元素中的其它属性来处理的，并且是用户输入的结果或者是在different＜action＞元素中标识的转发的结果。<BR>type<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;指定在发出请求时调用其执行方法的操作类的全限定名。该类必须在类路径中。<BR>　　　注：不指定要实例化的类，可以通过使用forward属性来转发请求，该属性在“Struts贸易样本”中未使用，并且与后面描述的＜forward＞子元素不相同。<BR>name<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;用于保存发送至HTML表单或接收自HTML表单的数据表单bean的名称。<BR>　　&nbsp;input<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;指定相对URL（例如，“/register.do”或“/index.jsp”）必须包括后缀，<BR>如果表单bean的验证方法指示发生了输入错误，则会调用URL；有关详细信息，参见下节的“验证”。<BR>　　&nbsp;scope<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;指定将对表单&nbsp;bean的引用存储在哪个作用域中。其值为“会话”（缺省值）或“请求”。<BR>　　　　&nbsp;Struts配置文件中的每个＜action＞元素还包括子元素＜forward＞，它指定从方法结果至后续调用的映射。每个＜forward＞子元素都包括下列属性<BR>　　name&nbsp;<BR>指定导致在运行时使用当前映射的字符串（例如，“success”），但是<BR>只限于以下情况：在&nbsp;type&nbsp;中引用的操作类的执行方法使用完全相同<BR>的字符串来配置返回至ActionServlet的&nbsp;ActionForward对象。下面<BR>的执行方法不是很重要，但是会导致使用“success”映射：<BR>&nbsp;&nbsp;<BR>&nbsp;public&nbsp;ActionForward&nbsp;exectue(<BR>&nbsp;&nbsp;&nbsp;ActionMapping&nbsp;mapping,<BR>&nbsp;&nbsp;&nbsp;ActoinForm&nbsp;form,<BR>&nbsp;&nbsp;&nbsp;HttpServletRequest&nbsp;request,<BR>&nbsp;&nbsp;&nbsp;HttpServletResponse&nbsp;response)<BR>&nbsp;&nbsp;&nbsp;Throws&nbsp;IOException,ServletException<BR>｛<BR>&nbsp;&nbsp;&nbsp;ActionForward&nbsp;forward=new&nbsp;ActionForward();<BR>&nbsp;&nbsp;&nbsp;Forward=mapping,findForward(“success”);<BR>&nbsp;&nbsp;&nbsp;return(forward)；<BR>｝<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;path<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;指定非限定URL（例如，“/home.do”&nbsp;或“/index.jsp”）必须包括文件扩展名，仅当使用当前映射时才会调用该URL，转发操作类是根据different&lt;action&gt;元素中的属性来处理的，尤其是，在其path属性标识相同URL的&lt;action&gt;元素中。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;有必要提一下的是，在struts1.1中，提出了对Multiple&nbsp;Application&nbsp;Support。在struts的早先版本中，只有一个struts配置文件，一般叫struts-config.xml。但是，对于越来越复杂的应用系统的发展，只有一个地方存放这个一个文件，对大型项目来说，使用和修改这个配置文件，使其成为了一个应用的瓶颈问题。在struts1.1中，你可以定义多了配置文件协同工作。<BR></P><img src ="http://www.blogjava.net/qq13367612/aggbug/17064.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qq13367612/" target="_blank">Sung</a> 2005-10-27 16:26 <a href="http://www.blogjava.net/qq13367612/articles/17064.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Struts原理、开发及项目实施 </title><link>http://www.blogjava.net/qq13367612/articles/16894.html</link><dc:creator>Sung</dc:creator><author>Sung</author><pubDate>Wed, 26 Oct 2005 08:30:00 GMT</pubDate><guid>http://www.blogjava.net/qq13367612/articles/16894.html</guid><wfw:comment>http://www.blogjava.net/qq13367612/comments/16894.html</wfw:comment><comments>http://www.blogjava.net/qq13367612/articles/16894.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qq13367612/comments/commentRss/16894.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qq13367612/services/trackbacks/16894.html</trackback:ping><description><![CDATA[1、 摘要<BR>2、 关键词<BR>3、 Framework<BR>4、 Struts的起源<BR>5、 Struts工作原理<BR>6、 Struts安装<BR>7、 一个实例<BR>8、 Struts优缺点<BR>9、 Struts项目实施经验<BR>10、 总结<BR>11、 参考文献<BR><BR>1、 摘要<BR>　　本文主要讲述了Struts（以Struts1.0.2为例）的工作原理，安装以及配置方面的问题。然后结合一个实例，详细讨论了Struts在实际开发过程中的应用，最后提供一些在开发过程中积累的经验，供大家参考。<BR><BR>2、关键词<BR>Struts、MVC、J2EE、Tiles、Framework<BR><BR>3、Framework<BR>　　Framework即架构（框架），这里指软件的架构方式，为什么要提Framework呢？请允许我从J2EE讲起。<BR>　　J2EE体系包括JSP、Servlet、EJB、WEB SERVICE等多项技术。这些技术的出现给电子商务时代的WEB应用开发提供了一个非常有竞争力的选择。怎样把这些技术组合起来，形成一个适应项目需要的稳定架构是项目开发过程中一个非常重要的步骤。<BR>　　此步骤一般主要由架构设计师完成，设计师将根据项目需求，对J2EE体系中的各处技术进行筛选取舍，并考虑到开发过程中的角色分工、后期的运行维护，以及系统扩展性等诸多因素，建立系统的架构。<BR>　　一个成功的软件需要有一个成功的架构，但软件架构的建立是一个复杂而又持续改进的过程，软件开发者们不可能对每个不同的项目做不同的架构，而总是尽量重用以前的架构，或开发出尽量通用的架构方案，Struts就是其中之一，Struts是流行的基于J2EE的架构方案，其他常用的基于J2EE的架构方案还有Turbine、RealMothods等。<BR><BR>4、Struts的起源<BR>　　Struts最早是作为Apache Jakarta项目的组成部分问世运做。项目的创立者希望通过对该项目的研究，改进和提高Java Server Pages (JSPs)、Servlet、标签库以及面向对象的技术水准。当前最高发行版本为Struts1.0.2，可以到http://jakata.apache.org/Struts下载。<BR>　　Struts这个名字来源于在建筑和旧式飞机中使用的支持金属架。它的目的是为了帮助你减少在运用MVC设计模型来开发Web应用的时间。你仍然需要学习和应用该架构，不过它将可以完成其中一些繁重的工作。如果想混合使用Servlets和JSP的优点来建立可扩展的应用，Struts是一个不错的选择。<BR><BR>5、Struts工作原理<BR>　　MVC即Model-View-Controller的缩写，是一种常用的设计模式。MVC 减弱了业务逻辑接口和数据接口之间的耦合，以及让视图层更富于变化。MVC的工作原理,如下图1所示：<BR><BR><BR>　　Struts 是MVC的一种实现，它将 Servlet和 JSP 标记（属于 J2EE 规范）用作实现的一部分。Struts继承了MVC的各项特性，并根据J2EE的特点，做了相应的变化与扩展。Struts的工作原理，如下图2所示：<BR><BR><BR>控制：通过图2大家可以看到有一个XML文件Struts-config.xml，与之相关联的是Controller，在Struts中，承担MVC中Controller角色的是一个Servlet，叫ActionServlet。ActionServlet是一个通用的控制组件。这个控制组件提供了处理所有发送到Struts的HTTP请求的入口点。它截取和分发这些请求到相应的动作类（这些动作类都是Action类的子类）。另外控制组件也负责用相应的请求参数填充 Action From（通常称之为FromBean）,并传给动作类（通常称之为ActionBean）。动作类实现核心商业逻辑，它可以访问java bean 或调用EJB。最后动作类把控制权传给后续的JSP 文件，后者生成视图。所有这些控制逻辑利用Struts-config.xml文件来配置。<BR><BR>视图：主要由JSP生成页面完成视图，Struts提供丰富的JSP 标签库： Html，Bean，Logic，Template等，这有利于分开表现逻辑和程序逻辑。<BR><BR>模型：模型以一个或多个java bean的形式存在。这些bean分为三类：Action Form、Action、JavaBean or EJB。Action Form通常称之为FormBean，封装了来自于Client的用户请求信息，如表单信息。Action通常称之为ActionBean，获取从ActionSevlet传来的FormBean，取出FormBean中的相关信息，并做出相关的处理，一般是调用Java Bean或EJB等。<BR>流程：在Struts中，用户的请求一般以*.do作为请求服务名，所有的*.do请求均被指向ActionSevlet，ActionSevlet根据Struts-config.xml中的配置信息，将用户请求封装成一个指定名称的FormBean，并将此FormBean传至指定名称的ActionBean，由ActionBean完成相应的业务操作，如文件操作，数据库操作等。每一个*.do均有对应的FormBean名称和ActionBean名称，这些在Struts-config.xml中配置。<BR><BR>核心：Struts的核心是ActionSevlet，ActionSevlet的核心是Struts-config.xml。这在后面还会详细讨论。<BR><BR>6、Struts安装<BR>　　Struts的安装比较简单，下面的以Tomcat 4.0.4为例，讲述安装过程。<BR>　　首先请到http://jakarta.apache.org/Struts下载Struts，建议使用release版，现在最高版本为1.0.2，下载后得到的是一个ZIP文件。将ZIP包解开，可以看到这个目录：lib和webapps，webapps下有一些WAR文件。<BR>　　假设你的Tomcat装在c:\Tomcat下，则将那些WAR文件拷贝到C:\Tomcat\webapps，重新启动Tomcat即可。<BR>　　打开浏览器，在地址栏中输入：http://localhost:8080/Struts-example/index.jsp，若能见到“powered by Struts”的深蓝色图标，即说明成功了。这是Struts自带的一个例子，附有详细的说明文档，可以做为初学者的入门教程。<BR>　　另外，Struts还提供了一系统实用对象：XML处理、通过Java reflection APIs自动处理JavaBeans属性、国际化的提示和消息等。<BR><BR><BR>7、一个实例<BR>　　一个用户注册系统，用户通过网页输入相关信息：注册ID号，密码，EMAIL，若注册成功，则返回成功提示信息，反之出现注册失败提示信息。<BR>以下是相关文件的部分核心代码。<BR><BR>项目建立：<BR>　　正式开发前，需要在Tocmat（我的tomcat装在c:\tomcat）中建立此项目。<BR>比较快的一种建立方式为：<BR>　　在C:\tomcat\webapps下新建目录test，再将C:\tomcat\webapps\struts-example下的<BR>WEB-INF目录拷贝到test目录下，然后将test\WEB-INF下的src和classes目录清空，以及struts-config.xml文件中内容清空即可。这样，我们需要的Struts类包及相关的配置文件就都齐了。<BR>　　开发时，将JSP文件放在test目录下，Java原文件放在test\WEB-INF\src下，编译后的类文件放在test\WEB-INF\classes下。<BR><BR>注册页面：reguser.jsp<BR><BR>&lt;%@ page contentType="text/html;charset=UTF-8" language="java" %&gt;<BR>&lt;%@ taglib uri="/WEB-INF/Struts-bean.tld" prefix="bean" %&gt;<BR>&lt;%@ taglib uri="/WEB-INF/Struts-html.tld" prefix="html" %&gt;<BR>&lt;html:html locale="true"&gt;<BR>&lt;head&gt;<BR>&lt;title&gt;RegUser&lt;/title&gt;<BR>&lt;html:base/&gt;<BR>&lt;/head&gt;<BR>&lt;body bgcolor="white"&gt;<BR>&lt;html:errors/&gt;<BR>&lt;html:form action="/regUserAction" focus="logname"&gt;<BR>&lt;table border="0" width="100%"&gt;<BR>&lt;tr&gt;<BR>&lt;th align="right"&gt;<BR>Logname:<BR>&lt;/th&gt;<BR>&lt;td align="left"&gt;<BR>&lt;html:text property="logname" size="20" maxlength="20"/&gt;<BR>&lt;/td&gt;<BR>&lt;/tr&gt;<BR>&lt;tr&gt;<BR>&lt;th align="right"&gt;<BR>Password:<BR>&lt;/th&gt;<BR>&lt;td align="left"&gt;<BR>&lt;html:password property="password" size="20" maxlength="20"/&gt;<BR>&lt;/td&gt;<BR>&lt;/tr&gt; <BR>&lt;tr&gt;<BR>&lt;th align="right"&gt;<BR>E-mail:<BR>&lt;/th&gt;<BR>&lt;td align="left"&gt;<BR>&lt;html:password property="email" size="30" maxlength="50"/&gt;<BR>&lt;/td&gt;<BR>&lt;/tr&gt;<BR>&lt;tr&gt;<BR>&lt;td align="right"&gt;<BR>&lt;html:submit property="submit" value="Submit"/&gt;<BR>&lt;/td&gt;<BR>&lt;td align="left"&gt;<BR>&lt;html:reset/&gt;<BR>&lt;/td&gt;<BR>&lt;/tr&gt;<BR>&lt;/table&gt;<BR>&lt;/html:form&gt;<BR>&lt;/body&gt;<BR>&lt;/html:html&gt;<BR><BR>　　此JSP页面不同于普通的JSP页，因为它大量运用了taglib，这些taglib对初学者而言，可能难于掌握，可这却是Struts的精华之一。灵活运用，将大大提高开发效率。<BR><BR>Struts-config.xml：<BR><BR>&lt;Struts-config&gt; <BR>&lt;form-beans&gt;<BR>&lt;form-bean name="regUserForm"<BR>type="org.cjea.Struts.example. RegUserForm "/&gt; <BR>&lt;/form-beans&gt;<BR><BR>&lt;action-mappings&gt;<BR>&lt;action path="/regUserAction"<BR>type=" org.cjea.Struts.example.RegUserAction "<BR>attribute=" regUserForm "<BR>scope="request"<BR>validate="false"&gt;<BR>&lt;forward name="failure" path="/ messageFailure.jsp"/&gt;<BR>&lt;forward name="success" path="/ messageSuccess.jsp"/&gt;<BR>&lt;/action&gt;<BR>&lt;/action-mappings&gt;<BR>&lt;/Struts-config&gt;<BR><BR>　　Struts的核心是Controller，即ActionServlet，而ActionServlet的核心就是Struts-config.xml，Struts-config.xml集中了所有页面的导航定义。对于大型的WEB项目，通过此配置文件即可迅速把握其脉络，这不管是对于前期的开发，还是后期的维护或升级都是大有裨益的。掌握Struts-config.xml是掌握Struts的关键所在。<BR><BR>FormBean：RegUserForm<BR><BR>package org.cjea.Struts.example;<BR><BR>import javax.Servlet.http.HttpServletRequest;<BR>import org.apache.Struts.action.ActionForm;<BR>import org.apache.Struts.action.ActionMapping;<BR><BR>public final class RegUserForm extends ActionForm{<BR><BR>private String logname;<BR>private String password;<BR>private String email;<BR><BR>public RegUserForm(){<BR>logname = null;<BR>password = null;<BR>email = null;<BR>}<BR><BR>public String getLogName() {<BR>return this.logname;<BR>}<BR>public void setLogName(String logname) {<BR>this.logname = logname;<BR>}<BR>public void setPassWord(String password) {<BR>this.password = password;<BR>}<BR>public String getPassWord() {<BR>return this.password;<BR>}<BR>public void setEmail(String email) {<BR>this.email = email;<BR>}<BR>public String getEmail() {<BR>return this.email;<BR>}<BR><BR>public void reset(ActionMapping mapping, HttpServletRequest request)<BR>{<BR>logname = null;<BR>password = null;<BR>email = null;<BR>}<BR>}<BR><BR>　　每一个FormBean 都必须继承ActionForm类，FormBean是对页面请求的封装。即把HTTP request 封装在一个对象中，需要说明的一点就是多个HTTP request可以共用一个FormBean，便于维护和重用。<BR><BR>ActionBean：RegUserAction<BR><BR>package org.cjea.Struts.example;<BR><BR>import javax.Servlet.http.*;<BR>import org.apache.Struts.action.*;<BR><BR>public final class RegUserAction extends Action<BR>{<BR><BR>public ActionForward perform(ActionMapping mapping,<BR>ActionForm form, HttpServletRequest req,<BR>HttpServletResponse res)<BR>{ <BR>String title = req.getParameter("title");<BR>String password = req.getParameter("password");<BR>String email = req.getParameter("email");<BR>/*<BR>取得用户请求,做相应数据库操作，略<BR>*/ <BR>}<BR>}<BR><BR>　　FormBean的产生是为了提供数据给ActionBean，在ActionBean中可以取得FormBean中封装的数据，经相应的逻辑处理后，调用业务方法完成相应业务要求。<BR><BR>　　Servlet的演变：在常规的 JSP，Servlet，JavaBean三层结构中，JSP实现View的功能，Servlet实现Controller的功能，JavaBean实现Model的实现。<BR>　　在Struts中，将常规情况下的Servlet拆分与ActionServlet、FormBean、ActionBean三个部分。ActionServlet配合Struts-config.xml，专职完成页面导航，而不再负责具体的数据获取与相应逻辑，这两部分功能由FormBean和ActionBean来完成。<BR><BR>8、Struts优缺点<BR>优点：<BR>　　Struts跟Tomcat、Turbine等诸多Apache项目一样，是开源软件，这是它的一大优点。使开发者能更深入的了解其内部实现机制。<BR>　　除此之外，Struts的优点主要集中体现在两个方面：Taglib和页面导航。Taglib是Struts的标记库，灵活动用，能大大提高开发效率。另外，就目前国内的JSP开发者而言，除了使用JSP自带的常用标记外，很少开发自己的标记，或许Struts是一个很好的起点。<BR>　　关于页面导航，我认为那将是今后的一个发展方向，事实上，这样做，使系统的脉络更加清晰。通过一个配置文件，即可把握整个系统各部分之间的联系，这对于后期的维护有着莫大的好处。尤其是当另一批开发者接手这个项目时，这种优势体现得更加明显。<BR>缺点：<BR>　　Taglib是Struts的一大优势，但对于初学者而言，却需要一个持续学习的过程，甚至还会打乱你网页编写的习惯，但是，当你习惯了它时，你会觉得它真的很棒。<BR>　　Struts将MVC的Controller一分为三，在获得结构更加清晰的同时，也增加了系统的复杂度。<BR>Struts从产生到现在还不到半年，但已逐步越来越多运用于商业软件。虽然它现在还有不少缺点，但它是一种非常优秀的J2EE MVC实现方式，如果你的系统准备采用J2EE MVC架构，那么，不妨考虑一下Struts。<BR><BR><BR>9、Struts项目实施经验<BR>　　前段时间，我们基于Struts架构（结合Tiles），开发了一个WEB应用。以下是我们在项目过程中积累的一些经验和吸取的教训，望对各位有所帮助。<BR>1、 基于Struts架构的项目开发，首先需要有一个很好的整体规划，整个系统中包括哪几个模块，每个模块各需要多少FormBean和ActionBean等，而且最h有专人负责Struts-config.xml的管理。开发基于Struts的项目的难点在于配置管理，尤其是对Struts-config.xml的管理。<BR>2、 如果你的项目非常紧，并且项目组中又没有富有经验的Struts开发人员，建议不要冒然采用Struts。Struts的掌握需要一个过程，对于一个熟练的JSP程序员，自学大概需要半个月左右的时间。如果结合titls，则需要更长的时间。<BR>3、 如果你在网页中大量运用taglib，那么你的美工将做出部分牺牲。当你结合Tiles，功能增强的同时，这种牺牲尤为明显。当然，你对功能和美观的取舍由你自己决定。<BR>4、 Taglib是一个好东西，但灵活运用它却需要一个过程，如果你不想在Taglib上花太多的时间，那么只需理解与FORM有关的几个标记，其它的标记就放着吧，以后再看，先去研究ActionServlet和Struts-config.xml，你会觉得很有成就感。<BR>5、 Struts的诞生时间虽不长，但与之相关的工具却越来越多，如果你是用Jbuilder作为开发工具，那我可以为你推荐几款优秀的open tools，极大的提高开发效率。<BR>6、 Struts是否只适合于大型项目呢？No！Struts适合于各种大小的项目，当然，对于大型项目，它所体现出来的优势更加明显。<BR><BR>10、总结<BR>　　Struts是一种优秀的J2EE MVC架构方式。它利用taglib获得可重用代码和抽象 Java 代码，利用ActionServlet配合Struts-config.xml实现对整个系统导航。增强了开发人员对系统的整体把握，提高了系统的可维护性和可扩充性。<BR><BR>11、参考文献<BR>1、 《Struts-documentation》<BR>2、 《当前流行的J2EE WEB应用架构分析》 龚永生 IBM开发者网站<BR>3、 《Struts，MVC 的一种开放源码实现用这种Servlet和JSP框架管理复杂的大型网站》Malcolm G. Davis IBM开发者网站<BR>4、 《Jakarta Struts Book Review Project》 Chuck Cavaness Theserverside连载 <img src ="http://www.blogjava.net/qq13367612/aggbug/16894.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qq13367612/" target="_blank">Sung</a> 2005-10-26 16:30 <a href="http://www.blogjava.net/qq13367612/articles/16894.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Struts的体系结构 </title><link>http://www.blogjava.net/qq13367612/articles/16893.html</link><dc:creator>Sung</dc:creator><author>Sung</author><pubDate>Wed, 26 Oct 2005 08:28:00 GMT</pubDate><guid>http://www.blogjava.net/qq13367612/articles/16893.html</guid><wfw:comment>http://www.blogjava.net/qq13367612/comments/16893.html</wfw:comment><comments>http://www.blogjava.net/qq13367612/articles/16893.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qq13367612/comments/commentRss/16893.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qq13367612/services/trackbacks/16893.html</trackback:ping><description><![CDATA[<P>自学</P>
<P align=left>预备知识 <BR>在开始学习Struts以前，以下的知识点，需要有所了解： 模型-视图-控制的软件构架模式，JSP/Servlet的web层应用，J2EE体系结构。如果对客户标签类（Customer TagLib）有所了解也许更容易理解Struts本身的TagLib。 <BR><BR>概述 <BR>本文主要从概念上讲解什么是struts framework，它的框架结构，组件结构，以及简单的配置讲解。对于其应用请参考后面的“struts安装及应用”和“struts实用案例分析”。 <BR>文章的包括了如下四大部分： <BR>一、 Framework的概念和体系简介 （Framework Conception and Architecture） <BR>二、 Struts的概念和体系结构（Struts Conception and Architecture） <BR>三、 Struts的工作原理和组件（Struts Componennts） <BR>四、 Struts配置文件简介（Struts Deployment Description） <BR><BR>一、 Framework概念 <BR>一直以来我们都说struts是一个web framework。那么让我么先来看看什么是Framework。（我想用“框架”一词来翻译framework，可是后来越来越发现不太理想和完备，所以就直接用Framework一词） <BR>Framework概念并不是很新了，伴随着软件开发的发展，在多层的软件开发项目中，可重用、易扩展的，而且是经过良好测试的软件组件，越来越为人们所青睐。这意味着人们可以将充裕的时间用来分析、构建业务逻辑的应用上，而非繁杂的代码工程。于是人们将相同类型问题的解决途径进行抽象，抽取成一个应用框架。这也就是我们所说的Framework。 <BR>Framework的体系提供了一套明确机制，从而让开发人员很容易的扩展和控制整个framework开发上的结构。 通常，framework的结构中都有一个“命令和控制”组件（"command and control" component）??Framework Factory and Manager。 <BR><BR>图片（2）：Framework体系 <BR><BR><BR>通过基于请求响应（Request-Response）模式的应用framework，基本上有如下几个表现逻辑结构组成。 <BR>（1）控制器（Controller）??控制整个framework中各个组件的协调工作。 <BR>（2）业务逻辑层（Business Logic）??这是framework所希望解决问题的关键。当然对framwork本身来说，这里仅仅只是概念和几个提够服务的基础组件，真正的实现与客户的业务逻辑接轨，还需要开发人员在framework上再次扩展。 <BR>（3）数据逻辑层（Data Logic）??绝大应用系统都需要涉及到数据交互，这一层次主要包括了数据逻辑和数据访问接口。对于数据逻辑来说，如果你了解数据建模（Data Modeling）可能就很容易理解。 <BR><BR>下面就进入我们的正题??Struts的结构 <BR><BR>二、 Struts的概念和体系结构 <BR>Struts有一组相互协作的类（组件）、Serlvet以及jsp tag lib组成。基于struts构架的web应用程序基本上符合JSP Model2的设计标准，可以说是MVC设计模式的一种变化类型。根据上面对framework的描述，我们很容易理解为什么说Struts是一个web framwork，而不仅仅是一些标记库的组合。但 Struts 也包含了丰富的标记库和独立于该框架工作的实用程序类。 <BR>Struts有其自己的控制器（Controller），同时整合了其他的一些技术去实现模型层（Model）和视图层（View）。在模型层，Struts可以很容易的与数据访问技术相结合，包括EJB,JDBC和Object Relation Bridge。在视图层，Struts能够与JSP, Velocity Templates,XSL等等这些表示层组件想结合。 <BR><BR>2.1 Struts的与Web App的关系 <BR><BR>既然struts叫做web framework，那么其肯定主要基于web层的应用系统开发。按照J2EE Architecture的标准，struts应当和jsp/servlet一样，存在于web container一层。如图片(3)所显示 <BR>图片（3）： Struts与WebApp的关系 <BR><BR>2.2 Struts的体系结构 <BR>我们说struts framework是MVC 模式的体现，下面我们就从分别从模型、视图、控制来看看struts的体系结构（Architecture）。图片（4）显示了struts framework的体系结构响应客户请求时候，各个部分工作的原理。 <BR>图片（4）：Struts体系结构 <BR><BR>2.2.1从视图角度（View） <BR>主要由JSP建立，struts自身包含了一组可扩展的自定义标签库（TagLib），可以简化创建用户界面的过程。目前包括：Bean Tags，HTML Tags，Logic Tags，Nested Tags，Template Tags　这几个Taglib。有关它们的详细资料请参考struts用户手册 <BR>2.2.2从模型角度（Model） <BR>模型主要是表示一个系统的状态（有时候，改变系统状态的业务逻辑操作也也划分到模型中）。在Struts中，系统的状态主要有ActiomForm Bean体现，一般情况下，这些状态是非持久性的。如果需要将这些状态转化为持久性数据存储，Struts本身也提供了Utitle包，可以方便的与数据库操作 <BR>2.2.3 从控制器角度（Controller） <BR>在Struts framework中， Controller主要是ActionServlet，但是对于业务逻辑的操作则主要由Action、ActionMapping、ActionForward这几个组件协调完成（也许这几个组件，应该划分到模型中的业务逻辑一块）。其中，Action扮演了真正的业务逻辑的实现者，而ActionMapping和ActionForward则指定了不同业务逻辑或流程的运行方向。 <BR><BR>2.3 Struts的基本组件包 <BR>整个struts大约有15包，近200个类所组成，而且数量还在不断的扩展。在此我们不能一一介绍，只能列举几个主要的简要的介绍一下。下表说明了目前struts api中基本的几个组件包，包括action,actions,config,util,taglib,validator。图片（5）则显现了这几个组件包之间的关系。其中action是整个struts framework的核心 <BR>org.apache.struts.action <BR>基本上，控制整个struts framework的运行的核心类、组件都在这个包中，比如我们上面提到的控制器ActionServlet。已经Action,ActionForm,ActionMapping等等。struts1.1比1.0多了 DynaActionForm 类。增加了动态扩展生成FormBean功能 <BR>org.apache.struts.actions <BR>这个包是主要作用是提供客户的http请求和业务逻辑处理之间的特定适配器转换功能，而1.0版本中的部分动态增删FromBean的类，也在struts1.1中被Action包的DynaActionForm组件所取代 <BR>org.apache.struts.config <BR>提供对配置文件struts-config.xml元素的映射。这也是sturts1.1中新增的功能 <BR>org.apache.struts.util <BR>Strtuts为了更好支持web application的应用，体统了一个些常用服务的支持，比如Connection Pool和Message Source。详细信息请参考http://jakarta.apache.org/struts/api/org/apache/struts/util/package-summary.html <BR>org.apache.struts.taglib <BR>这不是一个包，而是是一个客户标签类的集合。下面包括Bean Tags，HTML Tags，Logic Tags，Nested Tags，Template Tags这几个用于构建用户界面的标签类。 <BR>org.apache.struts.validator <BR>Struts1.1 framework中增加了validator framework，用于动态的配置from表单的验证。详细信息请参阅<A href="http://home.earthlink.net/~dwinterfeldt/" target=_blank> http://home.earthlink.net/~dwinterfeldt/</A> <BR><BR><BR><BR><BR><BR><BR><BR><BR>三、 Struts framework的工作原理和组件 <BR>对于Struts 如何控制、处理客户请求，让我们通过对struts的四个核心组件介绍来具体说明。这几个组件就是：ActionServlet。Action Classes，Action Mapping（此处包括ActionForward），ActionFrom Bean。 <BR>3.1 Struts ActionServlet <BR>ActionServlet继承自javax.servlet.http.HttpServlet类，其在Struts framework中扮演的角色失控制器，参看上面的“Struts体系图”。控制器ActionServlet主要负责将HTTP的客户请求信息组装后，根据配置文件的指定描述，转发到适当的处理器。（在Struts1.1中新增了org.apache.struts.action.Action.RequestProcessor类，将处理请求的功能从控制器功能中分离。 <BR>按照Servelt的标准，所有得Servlet必须在web配置文件（web.xml）声明。同样，ActoinServlet必须在Web Application配置文件（web.xml）中描述，有关配置信息，后面将会介绍。 <BR><BR>当用户向服务器端提交请求的时候，实际上信息是首先发送到控制器ActionServlet，一旦控制器获得了请求，其就会将请求信息传交给一些辅助类（help classes）处理。这些辅助类知道如何去处理与请求信息所对应的业务操作。在Struts中，这个辅助类就是org.apache.struts.action.Action。通常开发者需要自己继承Aciton类，从而实现自己的Action实例。 <BR><BR>3.2 Struts Action Classes <BR>一个Action 类的角色，就像客户请求动作和业务逻辑处理之间的一个适配器（Adaptor），其功能就是将请求与业务逻辑分开。这样的分离，使得客户请求和Action类之间可以有多个点对点的映射。而且Action类通常还提供了其它的辅助功能，比如：认证（authorization）、日志（logging）和数据验证（validation）。 <BR>Action最为常用的是execute（）方法。（注意，以前的perform方法在struts1.1中已经不再支持），还有一个execute（）方法，请参考apidoc，在此不在说明。 <BR>当Controller收到客户的请求的时候，在将请求转移到一个Action实例时，如果这个实例不存在，控制器会首先创建，然后会调用这个Action实例的execute（）方法。Struts Framework为应用系统中的每一个Action类只创建一个实例。因为所有的用户都使用这一个实例，所以你必须确定你的Action 类运行在一个多线程的环境中。下图显示了一个execute（）方法如何被访问： <BR><BR>图片（6）： Action实例的execute()方法 <BR><BR>注意，客户自己继承的Action子类，必须重写execute（）方法，因为Action类在默认情况下是返回null的。 <BR><BR><BR>3.3 Struts Action Mapping <BR>上面讲到了一个客户请求是如何被控制器转发和处理的，但是，控制器如何知道什么样的信息转发到什么样的Action类呢？这就需要一些与动作和请求信息相对应的映射配置说明。在struts 中，这些配置映射信息是存储在特定的XML文件（比如struts-config.xml）。 <BR>这些配置信息在系统启动的时候被读入内存，供struts framework在运行期间使用。在内存中，每一个&lt;action&gt;元素都与org.apache.struts.action.ActionMapping类的一个实例对应。下表就显示了一个登陆的配置映射。 <BR><BR>上面的配置表示：当可以通过/logonAction.do（此处假设配置的控制器映射为*.do）提交请求信息的时候，控制器将信息委托com.test.LogonAction处理。调用LogonAction实例的execute()方法。同时将Mapping实例和所对应的LogonForm Bean信息传入。其中name=LogonForm，使用的form-bean元素所声明的ActionForm Bean。有关form-bean的申明如下显示。 <BR><BR>元素&lt;forward&gt;则表示了当Action实例的execute()方法运行完毕或，控制器根据Mapping可将响应信息转到适当的地方。如上面现实，如果客户登陆成功，则调用welcome forward，将成功信息返回到/welcome.jsp页面。在你的execute()方法的结尾可以使用下面的实例代码而返回welcome forward。当然你的welcome forward必须在action元素属性中定义，正如上面所声明的那样。 <BR><BR>在此稍稍说一下有关global-forwards的概念。其在配置文件中描述了整个应用系统可以使用的ActionForward，而不是仅仅是一个特定的Action。 <BR><BR><BR>3.4 Struts ActionForm Bean <BR>在上面讲解ActionServlet，Action Classes和Action Mapping的时候，我们都提到了ActionForm Bean的概念。一个应用系统的消息转移（或者说状态转移）的非持久性数据存储，是由ActionForm Bean的负责保持的。 <BR>ActionForm的主要功能就是为Action的操作提供与客户表单相映射的数据（如果在客户指定的情况下，还包括对数据进行校验）。Action负责对系统数据状态的保持，而Action则负责根据业务逻辑的需要，对数据状态进行修改，在改变系统状态后，ActionForm则自动的回写新的数据状态并保持。 <BR>注意：在struts1.1中，ActionForm的校验功能，逐渐被剥离出来（当然依然可以使用）。使用了validator framework对整个应用系统的表单数据验证进行统一管理。相信信息请参考：http://home.earthlink.net/~dwinterfeldt <BR>在ActionForm的使用中，Struts提倡使用到值对象（Value Object）。这样将客户或开发人员，对数据状态与对象状态能够更加清晰的理解和使用。 <BR>对于每一个客户请求，Struts framework在处理ActionForm的时候，一般需要经历如下几个步骤： <BR>（１）检查Action的映射，确定Action中已经配置了对ActionForm的映射 <BR>（２）根据name属性，查找form bean的配置信息 <BR>（３）检查Action的formbean的使用范围，确定在此范围下，是否已经有此form bean的实例。 <BR>（４）假如当前范围下，已经存在了此form bean的实例，而是对当前请求来说，是同一种类型的话，那么就重用。 <BR>（５）否则，就重新构建一个form bean的实例 <BR>（６）form bean的reset()方法备调用 <BR>（７）调用对应的setter方法，对状态属性赋值 <BR>（８）如果validatede的属性北设置为true，那么就调用form bean的validate()方法。 <BR>注意：直接从ActionFrom类继承的reset()和validate()方法，并不能实现什么处理功能，所以有必要自己重新覆盖。 <BR>如果validate（）方法没有返回任何错误，控制器将ActionForm作为参数，传给Action实例的execute（）方法并执行。 <BR><BR><BR>有必要提一下有关org.apache.struts.action.DynaActionForm。这是struts1.1新增的特性。其继承自ActionForm，在struts早先版本中，我们必须人为的构造特定的ActionFrom子类，但是利用DynaActionForm，可以依据属性集而动态的创建from bean。有关其详细资料，请参考??? <BR><BR><BR>四、Struts的其他组件 <BR>Struts framework本身提供了很多可扩展的组件或sub framework，方便的开发人员在其构架上构建web层的应用系统。比如upload,collections ,logging等等。让我们来看看两个比较重要的组件：validationg framework和struts taglib。有关其他组件请参考Struts用户手册（http://jakarta.apache.org/struts/userGuide）。 <BR>在stuts1.0中有些很不错的概念和组件，比如benaUtils,Collections等等，后来被Jakarta Commons项目组吸收而独立处struts framework。但是struts依然需要依赖这些组件才能正常的工作。 <BR>4.1 Validation Framework for Struts <BR>在struts1.1中，新增了validation framework。增加了对form数据提交的验证。将原本需要在ActionFrom Bean的validate（）进行的验证通过配置文件的描述进行验证。 <BR>有关其详细信息，请参考http://home.earthlink.net/~dwinterfeldt 。个人建议对于小型应用系统可以采用这种配置方式，但是对于应用系统中有大量web层表单应用的系统，并且业务需求变动比较大的，使用validation framework 可能会加重开发难度、系统维护难度。可以借鉴validation framework的Javascript Validator Tag。 <BR><BR>4.2 Struts TagLib <BR>struts提供了一组可扩展的自定义标签库（TagLib），可以简化创建用户界面的过程。目前包括：Bean Tags，HTML Tags，Logic Tags，Nested Tags，Template Tags　这几个Taglib。有关Struts Taglib的结构和使用，可以参考前面有关Cutomer Tag Lib的介绍，有关起详细资料，请参考 <BR><BR>4.3 BeanUtils <BR>这个组件的全称是Bean Introspection Utilites。是属于Jakarta Commons项目组的。主要是帮助构建javabean的属性操作的（getter,setter），已经提供一种动态定义和访问bean的属性。有关详细信息，请参考。 <BR>http://jakarta.apache.org/commons/beanutils.html <BR>如果各位对这方面有很兴趣，可以参考一些有关java反射（Reflectio）方面的资料。 <BR><BR>4．4 Collections <BR>这个组件主要是提供了一些集合或列表对象，在原有的java collections framework的基础上进行了扩展。详细资料请参考： <BR>http://jakarta.apache.org/commons/collections.html 以及 <BR>http://cvs.apache.org/viewcvs/~checkout~/jakarta-commons/collections/STATUS.html?rev=1.13 <BR><BR>4．5 Digester <BR>这个组件翻译成中文的意思是“汇编”。其主要功能是根据xml配置文件，初始化系统的一些java类对象。Digester帮助你指定XML与java对象之间映射模型，而且允许客户话定制映射规则（rules）。详细资料请参考 <BR>http://jakarta.apache.org/commons/digester.html <BR><BR>4．6 其他相关组件 <BR>由于篇幅问题，还有一些组件就不一一介绍了，包括Database Connection Pool，Upload，Logging，Pool，Services。基在struts用户手册都有详细介绍，请参考。 <BR><BR><BR><BR>五、 Struts配置文件简介（Deployment Description） <BR>struts framework根据配置文件指定（更确切的说，是控制器），才使得ServletAction，ＡctionMapping,Action　,　ActionForm这几个不同层次的组件相互交互，协调的工作。前面也提到了，这些配置文件是在系统启动的时候，读入导内存中，供控制器使用的。 <BR>Struts framework主要包括三部分的配置描述，一个是指定有关Struts Controller及其相关的的配置描述（Initialization Parameters），一个时对struts tag lib的描述，一个是struts组件（ＡctionMapping,Action，ActionForm）之间相互映射协调的关系 <BR><BR>5.1有关Struts Controller及其相关的的配置描述 <BR>因为Struts Controller的主要类ActionServlet是继承自HttpServlet，所以必须像配置一个Servlet那样配置ActionServlet类及其访问映射。详细信息请参考： <BR>http://jakarta.apache.org/struts/userGuide/building_controller.html#dd_config <BR><BR>5.2 有关struts tag lib的配置描述 <BR>如果你的web application打算使用Struts的taglib，那么你有必要在web.xml中对struts taglib进行配置描述。有关详细的描述和说明请参考 <BR>http://jakarta.apache.org/struts/userGuide/building_controller.html#dd_config_taglib <BR><BR>5.3 有关Struts Action Mapping的配置描述 <BR>Struts本身有一个配置文件，通常情况为struts-config.xml。有关其DTD文档的描述，请参考http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd <BR>（或struts-config_1_0.dtd） <BR>一般struts-config（version1.1）包含了如下几个部分： <BR>（1）form-bean <BR>（2）global-forwards <BR>（3）action-mappings <BR>（4）data-sources <BR>有关详细信息请参阅 <BR>http://jakarta.apache.org/struts/userGuide/building_controller.html#config <BR><BR>有必要提一下的是，在struts1.1中，提出了对Multiple Application Support。在struts的早先版本中，只有一个struts配置文件，一般叫struts-config.xml。但是，对于越来越复杂的应用系统的发展，只有一个地方存放这个一个文件，对大型项目来说，使用和修改这个配置文件，使其成为了一个应用的瓶颈问题。在struts1.1中，你可以定义多了配置文件协同工作。 <BR><BR>总结 <BR>希望通过以上的对Struts Framework的讲解，读者可以对Struts的整体结构有个比较清晰的认识，对其如何处理客户请求，如何进行业务逻辑的处理和自动流转能够有个概念上的认识。 <BR><BR>Resource <BR>① Struts的官方网站： <BR>http://jakarta.apache.org/struts/ <BR>② Struts用户手册（User Guide） <BR>http://jakarta.apache.org/struts/userGuide <BR>③ ARTICLE --- Framework save the day <BR>http://www.javaworld.com/jw-09-2000/jw-0929-ejbframe.html <BR>④ ARTICLE --- Building a Java servlet framework using reflection <BR>http://www.javaworld.com/javaworld/jw-11-1999/jw-11-servlet.html <BR>⑤ Validation Framework <BR>http://home.earthlink.net/~dwinterfeldt/ <BR>http://cvs.apache.org/viewcvs/jakarta-commons/validator/ <BR>⑥ ARTICLE --- Struts1.1,Should I upgrade? <BR>http://www.theserverside.com/resources/article.jsp?l=Struts1_1 　</P><img src ="http://www.blogjava.net/qq13367612/aggbug/16893.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qq13367612/" target="_blank">Sung</a> 2005-10-26 16:28 <a href="http://www.blogjava.net/qq13367612/articles/16893.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Struts 体系结构与工作原理(图)</title><link>http://www.blogjava.net/qq13367612/articles/16891.html</link><dc:creator>Sung</dc:creator><author>Sung</author><pubDate>Wed, 26 Oct 2005 08:20:00 GMT</pubDate><guid>http://www.blogjava.net/qq13367612/articles/16891.html</guid><wfw:comment>http://www.blogjava.net/qq13367612/comments/16891.html</wfw:comment><comments>http://www.blogjava.net/qq13367612/articles/16891.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qq13367612/comments/commentRss/16891.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qq13367612/services/trackbacks/16891.html</trackback:ping><description><![CDATA[Struts是Apache 基金会Jakarta 项目组的一个Open Source 项目，它采用MVC模式，能够很好地帮助java 开发者利用J2EE开发Web应用。和其他的java架构一样，Struts 也是面向对象设计，将MVC模式"分离显示逻辑和业务逻辑"的能力发挥得淋漓尽致。Structs 框架的核心是一个弹性的控制层，基于如 Java Servlets，JavaBeans，ResourceBundles与XML等标准技术，以及 Jakarta Commons 的一些类库。Struts有一组相互协作的类（组件）、Serlvet以及jsp tag lib组成。基于struts构架的web应用程序基本上符合JSP Model2的设计标准，可以说是一个传统 MVC设计模式的一种变化类型。<BR>　　<BR>　　Struts有其自己的控制器（Controller），同时整合了其他的一些技术去实现模型层（Model）和视图层（View）。在模型层，Struts可以很容易的与数据访问技术相结合，如 JDBC / EJB ，以及其它第三方类库，如 Hibernate / iBATIS ，或者 Object Relational Bridge(对象关系桥)。在视图层，Struts能够与JSP，包括 JSTL 与 JSF，以及 Velocity 模板，XSLT 与其它表示层技术。<BR>　　<BR>　　Struts 为每个专业的 Web 应用程序做背后的支撑，帮助为你的应用创建一个扩展的开发环境。<BR>　　<BR>　　<B>Struts的体系结构与工作原理</B><BR>　　<BR>　　MVC即Model-View-Controller的缩写，是一种常用的设计模式。MVC 减弱了业务逻辑接口和数据接口之间的耦合，以及让视图层更富于变化。MVC的工作原理,如下图1所示：<BR>　　 <BR>
<CENTER>　<IMG onmousewheel="return bbimg(this)" style="CURSOR: pointer" onclick=javascript:window.open(this.src); src="http://www.blogjava.net/images/blogjava_net/qq13367612/4168/o_2005.9.27.10.13.59.3.1.jpg" onload="javascript:if(this.width>screen.width-500)this.style.width=screen.width-500;"></CENTER><BR>　　 <BR>
<CENTER>图1</CENTER><BR>　　<BR>　　Struts 是MVC的一种实现，它将 Servlet和 JSP 标记（属于 J2EE 规范）用作实现的一部分。Struts继承了MVC的各项特性，并根据J2EE的特点，做了相应的变化与扩展。Struts的体系结构与工作原理如下图2所示：<BR>　　 <BR>
<CENTER>　<IMG onmousewheel="return bbimg(this)" style="WIDTH: 415px; CURSOR: pointer; HEIGHT: 254px" onclick=javascript:window.open(this.src); height=139 src="http://www.blogjava.net/images/blogjava_net/qq13367612/4168/o_2005.9.27.10.14.11.3.2.jpg" onload="javascript:if(this.width>screen.width-500)this.style.width=screen.width-500;"></CENTER><BR>　　 <BR>
<CENTER>图2</CENTER><BR>　　<BR>　　从图2中我们可以知道，Struts的体系结构包括模型（Model），视图（View）和控制器（Controller）三部分。<BR>　　<BR>　　下面让我们从MVC角度来看看struts的体系结构（Model 2）与工作原理：<BR>　　<BR>　　1）模型（Model）<BR>　　<BR>　　在Struts的体系结构中，模型分为两个部分：系统的内部状态和可以改变状态的操作（事务逻辑）。内部状态通常由一组Actinform Bean表示。根据设计或应用程序复杂度的不同，这些Bean可以是自包含的并具有持续的状态，或只在需要时才获得数据（从某个数据库）。大型应用程序通常在方法内部封装事务逻辑（操作），这些方法可以被拥有状态信息的bean调用。比如购物车bean，它拥有用户购买商品的信息，可能还有checkOut()方法用来检查用户的信用卡，并向仓库发定货信息。 小型程序中，操作可能会被内嵌在Action类，它是struts框架中控制器角色的一部分。当逻辑简单时这个方法很适合。 建议用户将事务逻辑（要做什么）与Action类所扮演的角色（决定做什么）分开。<BR>　　<BR>　　2）视图（View）<BR>　　<BR>　　视图主要由JSP建立，struts包含扩展自定义标签库（TagLib），可以简化创建完全国际化用户界面的过程。目前的标签库包括：Bean Tags、HTML tags、Logic Tags、Nested Tags 以及Template Tags等。<BR>　　<BR>　　3）控制器（Controller）<BR>　　<BR>　　在struts中，基本的控制器组件是ActionServlet类中的实例servelt，实际使用的servlet在配置文件中由一组映射（由ActionMapping类进行描述）进行定义。对于业务逻辑的操作则主要由Action、ActionMapping、ActionForward这几个组件协调完成的，其中Action扮演了真正的业务逻辑的实现者，ActionMapping与ActionForward则指定了不同业务逻辑或流程的运行方向。struts-config.xml 文件配置控制器。<BR>　　<BR>　　Struts体系结构中的组件<BR>　　 <BR>
<CENTER><IMG onmousewheel="return bbimg(this)" style="WIDTH: 334px; CURSOR: pointer; ZOOM: 160%; HEIGHT: 209px" onclick=javascript:window.open(this.src); height=153 src="http://www.blogjava.net/images/blogjava_net/qq13367612/4168/o_2005.9.27.10.14.21.3.3.jpg" onload="javascript:if(this.width>screen.width-500)this.style.width=screen.width-500;"></CENTER><BR>　　 <BR>
<CENTER>图3</CENTER><BR>　　<BR>　　上图3显示了 ActionServlet (Controller)、Actionform (form State) 和 Action (Model Wrapper) 之间的最简关系。<BR>　　体系结构中所使用的组件如下表：<BR>　　ActionServlet　 控制器<BR>　　ActionClass　　 包含事务逻辑<BR>　　Actionform　　　显示模块数据<BR>　　ActionMapping　 帮助控制器将请求映射到操作<BR>　　ActionForward　 用来指示操作转移的对象<BR>　　ActionError　　 用来存储和回收错误<BR>　　Struts标记库　　可以减轻开发显示层次的工作<BR>　　<BR>　　<B>Struts配置文件：struts-config.xml</B><BR>　　<BR>　　Struts配置文件struts-config.xml，我们默认可以在目录WEB-INFstruts-config.xml找到这个文件。文件的配置包括全局转发、ActionMapping类、Actionform bean 和JDBC数据源四个部分。<BR>　　<BR>　　1）配置全局转发<BR>　　<BR>　　全局转发用来在JSP页之间创建逻辑名称映射。转发都可以通过对调用操作映射的实例来获得，例如：NuW=mactionMappingInstace.findForward("logicalName");<BR>　　<BR>　　全局转发的例子：<BR>　　＜global-forwards＞<BR>　　＜forward name="bookCreated" path="/BookView.jsp"/＞<BR>　　＜/global-forwards＞<BR>　　<BR>　　属性　　 描述<BR>　　Name　　 全局转发的名字<BR>　　Path　　 与目标URL的相对路径<BR>　　<BR>　　2）配置ActionMapping<BR>　　ActionMapping对象帮助进行框架内部的流程控制，它们可将请求URI映射到Action类,并且将Action类与Actionform bean相关联。ActionServlet在内部使用这些映射，并将控制转移到特定Action类的实例。所有Action类使用perform()方法实现特定应用程序代码，返回一个ActionForward对象，其中包括响应转发的目标资源名称。例如：<BR>　　<BR>　　＜action-mappings＞<BR>　　＜action path="/createBook" type="BookAction" name="bookform" scope="request" input="/CreateBook.jsp"＞<BR>　　＜/action＞<BR>　　＜forward name="failure" path="/CreateBook.jsp"/＞<BR>　　＜forward name="cancel" path="/index.jsp"/＞<BR>　　＜/action-mappings＞<BR>　　<BR>　　属性　　　　　　　　　　 描述<BR>　　Path　　　　　　　　Action类的相对路径<BR>　　Name　　　　　　　　与本操作关联的Action bean的名称<BR>　　Type　　　　　　　　连接到本映射的Action类的全称（可有包名）<BR>　　Scope　　　　　　　 Actionform bean的作用域（请求或会话）<BR>　　Prefix　　　　　　　用来匹配请求参数与bean属性的前缀<BR>　　Suffix　　　　　　　用来匹配请求参数与bean属性的后缀<BR>　　attribute　　　　　 作用域名称。<BR>　　className　　　　　 ActionMapping对象的类的完全限定名默认的是<BR>　　org.apache.struts.action.ActionMapping<BR>　　input　　　　　　　 输入表单的路径，指向bean发生输入错误必须返回的控制<BR>　　unknown　　　　　　 设为true，操作将被作为所有没有定义的ActionMapping的URI的默认操作<BR>　　validate　　　　　　设置为true，则在调用Action对象上的perform()方法前， ActionServlet将调用Actionform bean的validate()方法来进行输入检查<BR>　　通过＜forward＞元素，可以定义资源的逻辑名称，该资源是Action类的响应要转发的目标。<BR>　　属性　　　　　　　　　　　　　　 描述<BR>　　Id ID<BR>　　ClassName　　　　　　　　　　 ActionForward类的完全限定名，默认是<BR>　　org.apache.struts.action.ActionForward<BR>　　Name　　　　　　　　　　　　　操作类访问ActionForward时所用的逻辑名<BR>　　Path　　　　　　　　　　　　　响应转发的目标资源的路径<BR>　　redirect　　　　　　　　　　　若设置为true，则ActionServlet使用sendRedirec方法来转发资源<BR>　　3）配置Actionform Bean<BR>　　ActionServlet使用Actionform来保存请求的参数，这些bean的属性名称与HTTP请求参数中的名称相对应，控制器将请求参数传递到Actionform bean的实例，然后将这个实例传送到Action类。例子：<BR>　　＜form-beans＞<BR>　　＜form-bean name="bookform" type="Bookform"/＞<BR>　　＜/form-beans＞<BR>　　属性　　　　　　　　　　　　　　　描述<BR>　　Id　ID<BR>　　className　　　　　　 Actionform bean的完全限定名，默认值是org.apache.struts.action.ActionformBean<BR>　　Name　　　　　　　　　　　　　　　表单bean在相关作用域的名称，这个属性用来将bean与ActionMapping进行关联<BR>　　Type　　　　　　　　　 类的完全限定名<BR>　　4）配置JDBC数据源<BR>　　用＜data-sources＞元素可以定义多个数据源：<BR>　　属性　　　　　　　　描述<BR>　　Id　　　　　　　　　ID<BR>　　Key　　　　　　　　 Action类使用这个名称来寻找连接<BR>　　Type　　　　　　　　实现JDBC接口的类的名称<BR>　　<BR>　　下面属性需要＜set-property＞元素定义，在Struts 1.1版本中已不在使用，但你可用＜data-source＞元素。例如：|<BR>　　＜data-sources＞<BR>　　＜data-source id="DS1" key="conPool" type="org.apache.struts.util.GenericDataSource"<BR>　　＜set-property id="SP1" autoCommit="true" description="Example Data Source Configuration"<BR>　　driverClass="org.test.mm.mysql.Driver" maxCount="4"<BR>　　minCount="2" url="jdbc:mysql://localhost/test" user="struts" password="ghq123" /＞<BR>　　＜data-source/＞<BR>　　＜/data-sources＞<BR>　　<BR>　　属性　　　　 描述<BR>　　desciption 数据源的描述<BR>　　autoCommit 数据源创建的连接所使用的默认自动更新数据库模式<BR>　　driverClass　数据源所使用的类，用来显示JDBC驱动程序接口<BR>　　loginTimeout 数据库登陆时间的限制，以秒为单位<BR>　　maxCount　　 最多能建立的连接数目<BR>　　minCount　　 要创建的最少连接数目<BR>　　password　　 数据库访问的密码<BR>　　eadOnly　　 创建只读的连接<BR>　　User　　　　 访问数据库的用户名<BR>　　url　　　　　JDBC的URL<BR>　　<BR>　　通过指定关键字名称，Action类可以访问数据源，例如：<BR>　　javax.sql.DataSource ds = servlet.findDataSource("conPool");<BR>　　javax.sql.Connection con = ds.getConnection();<BR>　　<BR>　　<B>从struts的组件来看Struts 的工作原理</B><BR>　　<BR>　　对于Struts 如何控制、处理客户请求，让我们通过对struts的四个核心组件介绍来具体说明。这四个组件就是：ActionServlet、Action Classes，Action Mapping以及ActionFrom Bean。<BR>　　<BR>　　1） Struts ActionServlet<BR>　　<BR>　　ActionServlet继承自javax.servlet.http.HttpServlet类，其在Struts 体系结构中扮演的角色失控制器，控制器ActionServlet主要负责将HTTP的客户请求信息组装后，根据配置文件的指定描述，转发到适当的处理器。<BR>　　<BR>　　按照Servelt的标准，所有得Servlet必须在web配置文件（web.xml）声明。同样，ActoinServlet必须在Web Application配置文件（web.xml）中描述。<BR>　　<BR>　　当用户向服务器端提交请求的时候，实际上信息是首先发送到控制器ActionServlet，一旦控制器获得了请求，其就会将请求信息传交给一些辅助类（help classes）处理。这些辅助类知道如何去处理与请求信息所对应的业务操作。在Struts中，这个辅助类就是org.apache.struts.action.Action。通常开发者需要自己继承Aciton类，从而实现自己的Action实例。<BR>　　<BR>　　2） Struts Action Classes<BR>　　<BR>　　一个Action 类的角色，就像客户请求动作和业务逻辑处理之间的一个适配器（Adaptor），其功能就是将请求与业务逻辑分开。这样的分离，使得客户请求和Action类之间可以有多个点对点的映射。而且Action类通常还提供了其它的辅助功能，比如：认证（authorization）、日志（logging）和数据验证（validation）。<BR>　　<BR>　　3） Struts ActionMapping<BR>　　<BR>　　将特定请求映射到特定Action的相关信息存储在ActionMapping中，ActionServelt将ActionMapping传送到Action类的perform()方法，Action将使用ActionMapping的findForward()方法，此方法返回一个指定名称的ActionForward，这样Action就完成了本地转发。若没有找到具体的ActionForward，就返回一个null。<BR>　　<BR>　　4） Struts Actionform Bean<BR>　　<BR>　　一个应用系统的消息转移（或者说状态转移）的非持久性数据存储，是由Actionform Bean的负责保持的。<BR>　　<BR>　　Actionform的主要功能就是为Action的操作提供与客户表单相映射的数据（如果在客户指定的情况下，还包括对数据进行校验）。Action负责对系统数据状态的保持，而Action则负责根据业务逻辑的需要，对数据状态进行修改，在改变系统状态后，Actionform则自动的回写新的数据状态并保持。<BR>　　<BR>　　在Actionform的使用中，Struts提倡使用到值对象。这样将客户或开发人员，对数据状态与对象状态能够更加清晰的理解和使用。<BR>　　<BR>　　对于每一个客户请求，Struts 体系结构在处理Actionform的时候，一般需要经历如下几个步骤：<BR>　　<BR>　　① 检查Action的映射，确定Action中已经配置了对Actionform的映射；<BR>　　<BR>　　② 根据name属性，查找form bean的配置信息；<BR>　　<BR>　　③ 检查Action的formbean的使用范围，确定在此范围下，是否已经有此form bean的实例；<BR>　　<BR>　　④假如当前范围下，已经存在了此form bean的实例，而是对当前请求来说，是同一种类型的话，那么就重用；<BR>　　<BR>　　⑤ 否则，就重新构建一个form bean的实例；<BR>　　<BR>　　⑥form bean的reset()方法备调用；<BR>　　<BR>　　⑦ 调用对应的setter方法，对状态属性赋值；<BR>　　<BR>　　⑧ 如果validatede的属性北设置为true，那么就调用form bean的validate()方法。<BR>　　<BR>　　如果validate（）方法没有返回任何错误，控制器将Actionform作为参数，传给Action实例的execute（）方法并执行。 <BR><img src ="http://www.blogjava.net/qq13367612/aggbug/16891.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qq13367612/" target="_blank">Sung</a> 2005-10-26 16:20 <a href="http://www.blogjava.net/qq13367612/articles/16891.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Struts Tiles的使用</title><link>http://www.blogjava.net/qq13367612/articles/16879.html</link><dc:creator>Sung</dc:creator><author>Sung</author><pubDate>Wed, 26 Oct 2005 07:50:00 GMT</pubDate><guid>http://www.blogjava.net/qq13367612/articles/16879.html</guid><wfw:comment>http://www.blogjava.net/qq13367612/comments/16879.html</wfw:comment><comments>http://www.blogjava.net/qq13367612/articles/16879.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qq13367612/comments/commentRss/16879.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qq13367612/services/trackbacks/16879.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;Struts Tiles 的使用l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 配置准备从Struts1.1开始，Tiles的使用发生了一些改变，主要是配置方面的，tiles的安装必备的元素有：&nbsp;struts.jar – in WEB-INF/lib/. Tiles are now in the main S...&nbsp;&nbsp;<a href='http://www.blogjava.net/qq13367612/articles/16879.html'>阅读全文</a><img src ="http://www.blogjava.net/qq13367612/aggbug/16879.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qq13367612/" target="_blank">Sung</a> 2005-10-26 15:50 <a href="http://www.blogjava.net/qq13367612/articles/16879.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Struts标签库 </title><link>http://www.blogjava.net/qq13367612/articles/16661.html</link><dc:creator>Sung</dc:creator><author>Sung</author><pubDate>Mon, 24 Oct 2005 14:18:00 GMT</pubDate><guid>http://www.blogjava.net/qq13367612/articles/16661.html</guid><wfw:comment>http://www.blogjava.net/qq13367612/comments/16661.html</wfw:comment><comments>http://www.blogjava.net/qq13367612/articles/16661.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qq13367612/comments/commentRss/16661.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qq13367612/services/trackbacks/16661.html</trackback:ping><description><![CDATA[JSP视窗组件所使用的struts标记库由四类标记组成：&nbsp; <BR>2.&nbsp;Bean标记：用来在JSP页中管理bean&nbsp; <BR>3.&nbsp;逻辑标记：用来在JSP页中控制流程&nbsp; <BR>4.&nbsp;HTML标记：用来生成HTML标记，在表单中显示数据，使用会话ID对URL进行编程&nbsp; <BR>5.&nbsp;模板标记：使用动态模板构造普通格式的页&nbsp; <BR>2.1&nbsp;Bean标记&nbsp; <BR>这个标记库中包含用于定义新bean、访问bean及其属性的标记。Struts框架提供了多种自定义标记用来在JSP页中处理JavaBean。这些标记被封装在一个普通的标记库中，在文件struts-bean.tld中定义了它的标记库描述器。Bean标记库将标记定义在四个子类别中：&nbsp; <BR>创建和复制bean的标记&nbsp; <BR>脚本变量定义标记&nbsp; <BR>bean翻译标记&nbsp; <BR>消息国际化标记&nbsp; <BR>2.1.1&nbsp;Bean复制标记&nbsp; <BR>可定义新bean，可复制现有bean，还可从现有bean复制属性。&nbsp; <BR>&lt;bean:define&gt;标记用来：&nbsp; <BR>定义新字符串常数&nbsp; <BR>将现有的bean复制到新定义的bean对象&nbsp; <BR>复制现有bean的属性来创建新的bean&nbsp; <BR>&lt;bean:define&gt;标记属性：&nbsp; <BR>属性描述Id&nbsp;新定义的bean脚本变量名称，必须设置Type&nbsp;定义引入脚本变量的类value&nbsp;为id属性定义的脚本变量分配一个新的对象Name&nbsp;目标bean的名称。若value属性没有设置，这个属性就必须设置property&nbsp;Name属性定义的bean的属性名称，用来定义新的bean&nbsp; <BR>13&nbsp; <BR>Scope&nbsp;源bean的作用域。若没有设置，搜索范围是从页作用域到应用程序作用域toScope&nbsp;目标bean的作用域。若没有设置，默认值是页作用域&nbsp; <BR>例如：定义一个bean:&nbsp; <BR>&lt;bean:define&nbsp;id=”test”&nbsp;value=”this&nbsp;is&nbsp;a&nbsp;test”/&gt;&nbsp; <BR>源bean在页作用域中被拷贝大哦请求作用域中的另一个bean:&nbsp; <BR>&lt;bean:define&nbsp;id=”targetBean”&nbsp;name=”sourceBean”&nbsp; <BR>scope=”page”&nbsp;toScope=”request”/&gt;&nbsp; <BR>2.1.2&nbsp;定义脚本变量的标记&nbsp; <BR>从多种资源中定义和生成脚本变量，这些资源包括cookie,请求参数，HTTP标头等等。属性如下：&nbsp; <BR>属性描述Id&nbsp;脚本变量和要定义的页作用域属性的名称Name&nbsp;cookie/标头/参数的名称multiple&nbsp;如果这个属性设置了任意一个数值，所有匹配的cookie都会被积累并存储到一个Cookie[](一个数组)类型的bean里。若无设置，指定cookie的第一个值将作为Cookie类型的值value&nbsp;如果没有匹配的cookie或数值，就返回这个属性指定的默认值&nbsp; <BR>例如：&nbsp; <BR>&lt;bean:cookie&nbsp;id=”myCookie”&nbsp;name=”userName”/&gt;&nbsp; <BR>脚本变量名称是myCookie，用来创建这个属性的cookie的名称是userName。&nbsp; <BR>&lt;bean:header&nbsp;id=”myHeader”&nbsp;name=”Accept-Language”/&gt;&nbsp; <BR>脚本变量名称是myHeader,请求标头的名称是Accept-Language.&nbsp; <BR>&lt;bean:parameter&nbsp;id=”myParameter”&nbsp;name=”myParameter”&gt;&nbsp; <BR>脚本变量名称是myPatameter,它保存的请求参数的名称也是myParameter.&nbsp; <BR>&lt;bean:include&gt;标记将对一个资源的响应进行检索，并引入一个脚本变量和字符串类型的页作用域属性。这个资源可以是一个页，一个ActionForward或一个外部URL。与&lt;jsp:include&gt;的不同是资源的响应被存储到一个页作用域的bean中，而不是写入到输出流。属性如下：&nbsp; <BR>属性描述Id&nbsp;脚本变量和要定义的页作用域属性的名称Page&nbsp;一个内部资源forward&nbsp;一个ActionForward&nbsp;Href&nbsp;要包含的资源的完整URL&nbsp; <BR>例如：&nbsp; <BR>&lt;bean:include&nbsp;id=”myInclude”&nbsp;page=”MyJsp?x=1”/&gt;&nbsp; <BR>脚本变量的名称是myInclude，要检索的响应来自资源MyJsp?x=1。&nbsp; <BR>&lt;bean:resource&gt;标记将检索web应用中的资源，并引入一个脚本变量和InputStream或字符串类型的页作用域属性。如果在检索资源时发生问题，就会产生一个请求时间异常。属性如下：&nbsp; <BR>属性描述&nbsp; <BR>14&nbsp; <BR>Id&nbsp;脚本变量和要定义的页作用域属性的名称Name&nbsp;资源的相对路径Input&nbsp;如果这个属性不存在，资源的类型就是字符串&nbsp; <BR>例如：&nbsp; <BR>&lt;bean:resource&nbsp;id=”myResource”&nbsp;name=”/WEB-INF/images/myResource.xml”/&gt;&nbsp; <BR>脚本变量的名称是myResource，要检索的资源的名称是myResource.xml。&nbsp; <BR>2.1.3&nbsp;显示Bean属性&nbsp; <BR>标记库中定义了&lt;bean:write&gt;标记，用来将bean的属性输送到封装的JSP页写入器。这个标记与&lt;jsp:getProperty&gt;类似，属性如下：&nbsp; <BR>属性描述Name&nbsp;要进行属性显示的bean的名称property&nbsp;要显示的属性的名称。如果这个属性类有java.beans.PropertyEditor,getAsText()或toString&nbsp;方法会被调用Scope&nbsp;Bean的作用域，若没有设置，搜索范围是从页到应用程序作用域Filter&nbsp;如果设置true,属性中的所有特殊HTML字符都将被转化为相应的实体引用Ignore&nbsp;如果设置false，当发现属性时会产生一个请求时间异常，否则返回null&nbsp; <BR>例如：&nbsp; <BR>&lt;bean:write&nbsp;name=”myBean”&nbsp;property=”myProperty”&nbsp;scope=”request”&nbsp; <BR>filter=”true”/&gt;&nbsp; <BR>myBean的属性myProperty将会被显示，作用域为请求，如果发现任何HTML特殊字符都将被转化为相应的实体引用。&nbsp; <BR>2.1.4&nbsp;消息标记和国际化&nbsp; <BR>strtus框架支持国际化和本地化。用户在他们的计算机中定义自己所在的区域，当web应用程序需要输出一条消息时，它将引用一个资源文件，在这个文件中所有的消息都使用了适当的语言。一个应用程序可能提供了很多资源文件，每个文件提供了用不同语言编写的消息。如果没有找到所选语言的资源文件，就将使用默认的资源文件。&nbsp; <BR>struts框架对国际化的支持是使用&lt;bean:message&gt;标记，以及使用java.util数据包中定义的Locale和ResourceBundle类来实现Java2平台对这些任务的支持。Java.text.MessageFormat类定义的技术可以支持消息的格式。利用此功能，开发人员不需了解这些类的细节就可进行国际化和设置消息的格式。&nbsp; <BR>用strtus实现国际化和本地化：&nbsp; <BR>第一步要定义资源文件的名称，这个文件会包含用默认语言编写的在程序中会出现的所有消息。这些消息以“关键字-值”的形式存储，如下：&nbsp; <BR>error.validation.location&nbsp;=&nbsp;The&nbsp;entered&nbsp;location&nbsp;is&nbsp;invalid&nbsp; <BR>这个文件需要存储在类的路径下，而且它的路径要作为初始化参数传送给ActionServlet作为参数进行传递时，路径的格式要符合完整Java类的标准命名规范。比如，如果资源文件存储在WEB-INF\classes目录中，文件名是&nbsp; <BR>15&nbsp; <BR>ApplicationResources.properties，那么需要传递的参数值是ApplicationResources。如果文件在WEB-INF\classes\com\test中，那么参数值就应该是com.test.&nbsp;ApplicationResources.&nbsp; <BR>为了实现国际化，所有的资源文件必须都存储在基本资源文件所在的目录中。基本资源文件包含的是用默认地区语言-本地语言编写的消息。如果基本资源文件的名称是ApplicationResources.properties，那么用其他特定语言编写的资源文件的名称就应该是ApplicationResources_xx.properties(xx为ISO编码，如英语是en)。因此这些文件应包含相同的关键字，但关键字的值是用特定语言编写的。&nbsp; <BR>ActionServlet的区域初始化参数必须与一个true值一起传送，这样ActionServlet就会在用户会话中的Action.LOCALE_KEY关键字下存储一个特定用户计算机的区域对象。现在可以运行一个国际化的web站点，它可以根据用户计算机上的设置的区域自动以相应的语言显示。&nbsp; <BR>我们还可以使用特定的字符串来替换部分消息，就象用java.text.MessageFormat的方法一样：&nbsp; <BR>error.invalid.number&nbsp;=&nbsp;The&nbsp;number&nbsp;{0}&nbsp;is&nbsp;valid&nbsp; <BR>我们可以把字符串{0}替换成任何我们需要的数字。&lt;bean:message&gt;标签属性如下：&nbsp; <BR>属性描述Key&nbsp;资源文件中定义消息关键字Locale&nbsp;用户会话中存储的区域对象的属性名称。若没有设置，默认值是Action.LOCALE_KEY&nbsp;Bundle&nbsp;在应用程序上下文中，存储资源对象的属性的名称。如果没有设置这个属性，默认值是Action.MESSAGE_KEY&nbsp;arg0&nbsp;第一个替换参数值arg1&nbsp;第二个替换参数值arg2&nbsp;第三个替换参数值arg3&nbsp;第四个替换参数值&nbsp; <BR>例如：资源文件中定义了一个消息：&nbsp; <BR>info.myKey&nbsp;=&nbsp;The&nbsp;numbers&nbsp;entered&nbsp;are&nbsp;{0},{1},{2},{3}&nbsp; <BR>我们可使用下面的消息标记：&nbsp; <BR>&lt;bean:message&nbsp;key=”info.myKey”&nbsp;arg0=”5”&nbsp;arg1=”6”&nbsp;arg2=”7”&nbsp;arg3=”8”/&gt;&nbsp; <BR>这个信息标记输出到JSP页会显示为：The&nbsp;numbers&nbsp;entered&nbsp;are&nbsp;5,6,7,8&nbsp; <BR>2.2&nbsp;逻辑标记&nbsp; <BR>逻辑库的标记能够用来处理外观逻辑而不需要使用scriptlet。Struts逻辑标签库包含的标记能够有条件地产生输出文本，在对象集合中循环从而重复地产生输出文本，以及应用程序流程控制。它也提供了一组在JSP页中处理流程控制的标记。这些标记封装在文件名为struts-logic.tld的标记包中。逻辑标记库定义的标记能够执行下列三个功能：&nbsp; <BR>条件逻辑&nbsp; <BR>重复&nbsp; <BR>转发/重定向响应&nbsp; <BR>16&nbsp; <BR>2.2.1&nbsp;条件逻辑&nbsp; <BR>struts有三类条件逻辑。第一类可以比较下列实体与一个常数的大小：&nbsp; <BR>cookie&nbsp; <BR>请求参数&nbsp; <BR>bean或bean的参数&nbsp; <BR>请求标头&nbsp; <BR>以下列出了这一类标记：&nbsp; <BR>标记功能&lt;equal&gt;&nbsp;如果常数与被定义的实体相等，返回true&nbsp;&lt;notEqual&gt;&nbsp;如果常数与被定义的实体不相等，返回true&nbsp;&lt;greaterEqual&gt;&nbsp;如果常数大于等于被定义的实体，返回true&nbsp;&lt;lessEqual&gt;&nbsp;如果常数小于等于被定义的实体，返回true&nbsp;&lt;lessThan&gt;&nbsp;如果常数小于被定义的实体，返回true&nbsp;&lt;greaterThan&gt;&nbsp;如果常数大于被定义的实体，返回true&nbsp; <BR>这一类的所有标记有相同的属性&nbsp; <BR>属性描述value&nbsp;要进行比较的常数值Cookie&nbsp;要进行比较的HTTP&nbsp;cookie的名称Header&nbsp;要进行比较的HTTP请求标头的名称parameter&nbsp;要进行比较的HTTP请求参数的名称Name&nbsp;如果要进行比较的是bean或bean的属性，则这个属性代表bean的名称property&nbsp;要进行比较的bean属性的名称Scope&nbsp;Bean的作用域，如果没有指定作用域，则它的搜索范围是从页到应用程序&nbsp; <BR>例如：&nbsp; <BR>&lt;logic:equal&nbsp;parameter=”name”&nbsp;value=”SomeName”&gt;&nbsp; <BR>The&nbsp;entered&nbsp;name&nbsp;is&nbsp;SomeName&nbsp; <BR>&lt;/logic:equal&gt;&nbsp; <BR>判断名为”name”的请求参数的值是否是”SomeName”。&nbsp; <BR>&lt;logic:greaterThan&nbsp;name=”bean”&nbsp;property=”prop”&nbsp;scope=”page”&nbsp;value=”7”&gt;&nbsp; <BR>The&nbsp;value&nbsp;of&nbsp;bean.Prop&nbsp;is&nbsp;greater&nbsp;than&nbsp;7&nbsp; <BR>&lt;/logic:greaterThan&gt;&nbsp; <BR>判断在页的作用域中是否有一个名为”bean”的bean，它有一个prop属性，这个属性的值是否大于7。如果这个属性能够转化为数值，就进行数值比较，否则就进行字符串比较。&nbsp; <BR>第二类条件标记定义了两个标记：&nbsp; <BR>&lt;logic:present&gt;&nbsp; <BR>&lt;logic:notPresent&gt;&nbsp; <BR>它们的功能是在计算标记体之前判断特定的项目是否存在。标记的属性和属性值决定了要进行检查的项目。&nbsp; <BR>属性描述&nbsp; <BR>17&nbsp; <BR>Cookie&nbsp;由这个属性指定的cookie将被检查是否存在Header&nbsp;由这个属性指定的请求标头将被检查是否存在parameter&nbsp;由这个属性指定的请求参数将被检查是否存在Name&nbsp;如果没有设置property属性，那么有这个属性指定的bean将被检查是否存在。如果设置了，那么bean和bean属性都将被检查是否存在。property&nbsp;检查有name属性指定的bean中是否存在指定的属性Scope&nbsp;如果指定了bean的名称，这就是bean的作用域。如果没有指定作用域，搜索的范围从页到应用程序作用域。Role&nbsp;检查当前已经确认的用户是否属于特殊的角色User&nbsp;检查当前已经确认的用户是否有特定的名称&nbsp; <BR>例如：&nbsp; <BR>&lt;logic:notPresent&nbsp;name=”bean”&nbsp;property=”prop”&nbsp;scope=”page”&gt;&nbsp; <BR>The&nbsp;bean&nbsp;property&nbsp;bean.prop&nbsp;is&nbsp;present&nbsp; <BR>&lt;/logic:notPresent&gt;&nbsp; <BR>标记判断在页作用域中是否存在一个名为”bean”的bean，这个bean有一个prop属性。&nbsp; <BR>第三类条件标记比较复杂，这些标记根据模板匹配的结果检查标记体的内容。换句话说，这些标记判断一个指定项目的值是否是一个特定常数的子字符串：&nbsp; <BR>&lt;logic:match&gt;&nbsp; <BR>&lt;logic:notMatch&gt;&nbsp; <BR>这些标记允许JSP引擎在发现了匹配或是没有发现时计算标记主体。属性如下：&nbsp; <BR>属性描述Cookie&nbsp;要进行比较的HTTP&nbsp;cookie的名称Header&nbsp;要进行比较的的HTTP标头的名称parameter&nbsp;要进行比较的的HTTP请求参数的名称Name&nbsp;若要对bean或bean的属性进行比较，这个属性是用户指定bean的名称location&nbsp;如果设置了这个属性的值，将会在这个指定的位置(索引值)进行匹配scope&nbsp;如果对bean进行比较，这个属性指定了bean的作用域。如果没有设置这个参数，搜索范围是从页到应用程序作用域property&nbsp;要进行比较的bean的属性名称value&nbsp;要进行比较的常数值&nbsp; <BR>例如：&nbsp; <BR>&lt;logic:match&nbsp;parameter=”name”&nbsp;value=”xyz”&nbsp;location=”1”&gt;&nbsp; <BR>The&nbsp;parameter&nbsp;name&nbsp;is&nbsp;a&nbsp;sub-string&nbsp;of&nbsp;the&nbsp;string&nbsp;xyz&nbsp;from&nbsp;index&nbsp;1&nbsp; <BR>&lt;/logic:match&gt;&nbsp; <BR>标记检查名为”name”的请求参数是否是”xyz”的子字符串，但是子字符串必须从”xyz”的索引位置1开始（也就是说子字符串必须是”y”或”yz”）。&nbsp; <BR>2.2.2&nbsp;重复标记&nbsp; <BR>在逻辑标记库中定义了&lt;logic:iterate&gt;标记，它能够根据特定集合中元素的数目对标记体的内容进行重复的检查。集合的类型可以是java.util.Iterator,java.util.Collection&nbsp; <BR>18&nbsp; <BR>,java.util.Map或是一个数组。有三种方法可以定义这个集合：&nbsp; <BR>使用运行时间表达式来返回一个属性集合的集合&nbsp; <BR>将集合定义为bean，并且使用name属性指定存储属性的名称。&nbsp; <BR>使用name属性定义一个bean，并且使用property属性定义一个返回集合的bean属性。&nbsp; <BR>当前元素的集合会被定义为一个页作用域的bean。属性如下，所有这些属性都能使用运行时表达式。&nbsp; <BR>属性描述collection&nbsp;如果没有设置name属性，它就指定了要进行重复的集合Id&nbsp;页作用域bean和脚本变量的名称，它保存着集合中当前元素的句柄indexed&nbsp;页作用域JSP&nbsp;bean的名称，它包含着每次重复完成后集合的当前索引Length&nbsp;重复的最大次数Name&nbsp;作为集合的bean的名称，或是一个bean名称，它由property属性定义的属性，是个集合Offset&nbsp;重复开始位置的索引property&nbsp;作为集合的Bean属性的名称Scope&nbsp;如果指定了bean名称，这个属性设置bean的作用域。若没有设置，搜索范围从页到应用程序作用域Type&nbsp;为当前定义的页作用域bean的类型&nbsp; <BR>例如：&nbsp; <BR>&lt;logic:iterate&nbsp;id=”currentInt”&nbsp; <BR>collection=”&lt;%&nbsp;=myList&nbsp;%&gt;”&nbsp; <BR>type=”java.lang.Integer”&nbsp; <BR>offset=”1”&nbsp; <BR>length=”2”&gt;&nbsp; <BR>&lt;%&nbsp;=currentint&nbsp;%&gt;&nbsp; <BR>&lt;/logic:iterate&gt;&nbsp; <BR>代码将从列表中的第一个元素开始重复两个元素并且能够让当前元素作为页作用域和java.lang.Integer类型的脚本变量来使用。也就是说，如果myList包含元素1，2，3，4等，代码将会打印1和2。&nbsp; <BR>2.2.3&nbsp;转发和重定向标记&nbsp; <BR>转发标记&nbsp; <BR>&lt;logic:forward&gt;标记能够将响应转发给重定向到特定的全局ActionForward上。ActionForward的类型决定了是使用PageContext转发响应，还是使用sendRedirect将响应进行重定向。此标记只有一个”name”属性，用来指定全局ActionForward的名称，例如：&nbsp; <BR>&lt;logic:forward&nbsp;name=”myGlobalForward”/&gt;&nbsp; <BR>重定向标记&nbsp; <BR>&lt;logic:redirect&gt;标记是一个能够执行HTTP重定向的强大工具。根据指定的不同属性，它能够通过不同的方式实现重定向。它还允许开发人员指定重定向URL的查询参数。属性如下：&nbsp; <BR>19&nbsp; <BR>属性描述Forward&nbsp;映射了资源相对路径的ActionForward&nbsp;Href&nbsp;资源的完整URL&nbsp;Page&nbsp;资源的相对路径Name&nbsp;Map类型的页名称，请求，会话或程序属性的名称，其中包含要附加大哦重定向URL（如果没有设置property属性）上的“名称-值”参数。或是具有Map类型属性的bean名称，其中包含相同的信息（没有设置property属性）&nbsp;Property&nbsp;Map类型的bean属性的名称。Bean的名称由name属性指定。Scope&nbsp;如果指定了bean的名称，这个属性指定搜索bean的范围。如果没有设置，搜索范围从页到应用程序作用域ParamID&nbsp;定义特定查询参数的名称ParamName&nbsp;字符串类型的bean的名称，其中包含查询参数的值(如果没有设置paramProperty属性)；或是一个bean的名称，它的属性(在paramProperty属性中指定)包含了查询参数值paramProperty&nbsp;字符串bean属性的名称，其中包含着查询参数的值ParamScope&nbsp;ParamName定义的bean的搜索范围&nbsp; <BR>使用这个标记时至少要指定forward,href或page中的一个属性，以便标明将响应重定向到哪个资源。&nbsp; <BR>2.3&nbsp;HTML标记&nbsp; <BR>Struts&nbsp;HTML标记可以大致地分为以下几个功能：&nbsp; <BR>显示表单元素和输入控件&nbsp; <BR>显示错误信息&nbsp; <BR>显示其他HTML元素&nbsp; <BR>2.3.1&nbsp;显示表单元素和输入控件&nbsp; <BR>struts将HTML表单与为表单操作而定义的ActionForm&nbsp;bean紧密联系在一起。表单输入字段的名称与ActionForm&nbsp;bean里定义的属性名称是对应的。当第一次显示表单时，表单的输入字段是从ActionForm&nbsp;bean中移植过来的，当表单被提交时，请求参数将移植到ActionForm&nbsp;bean实例。&nbsp; <BR>所有可以在&lt;form&gt;标记中使用的用来显示HTML输入控件的内嵌标记都使用下列属性来定义javascript事件处理器。&nbsp; <BR>属性描述Onblur&nbsp;字段失去了焦点Onchange&nbsp;字段失去了焦点并且数值被更改了onclick&nbsp;字段被鼠标点击Ondblclick&nbsp;字段被鼠标双击Onfocus&nbsp;字段接收到输入焦点onkeydown&nbsp;字段拥有焦点并且有键按下&nbsp; <BR>20&nbsp; <BR>onkeypress&nbsp;字段拥有焦点并且有键按下并释放onkeyup&nbsp;字段拥有焦点并且有键被释放onmousedown&nbsp;鼠标指针指向字段并且点击onmousemove&nbsp;鼠标指针指向字段并且在字段内移动onmouseout&nbsp;鼠标指针指向控件，但是指针在元素外围移动onmouseover&nbsp;鼠标指针没有指向字段，但是指针在元素内部移动onmouseup&nbsp;鼠标指针指向字段，并且释放了鼠标按键&nbsp; <BR>&lt;form&gt;元素中能够被定义的其他一般属性有：&nbsp; <BR>属性描述Accesskey&nbsp;定义访问输入字段的快捷键Style&nbsp;定义输入字段的样式styleClass&nbsp;定义输入字段的样式表类Tabindex&nbsp;输入字段的tab顺序&nbsp; <BR>a)&nbsp;表单标记&nbsp; <BR>&lt;html:form&gt;标记用来显示HTML标记，可以指定AcitonForm&nbsp;bean的名称和它的类名。如果没有设置这些属性，就需要有配置文件来指定ActionMapping以表明当前输入的是哪个JSP页，以及从映射中检索的bean名和类。如果在ActionMapping指定的作用域中没有找到指定的名称，就会创建并存储一个新的bean，否则将使用找到的bean。&nbsp; <BR>&lt;form&gt;标记能够包含与各种HTML输入字段相对应的子标记。&nbsp; <BR>&lt;html:form&gt;标记属性如下：&nbsp; <BR>属性描述Action&nbsp;与表单相关的操作。在配置中，这个操作也用来标识与表单相关的ActionForm&nbsp;bean&nbsp;Enctype&nbsp;表单HTTP方法的编码类型Focus&nbsp;表单中需要初始化焦点的字段Method&nbsp;表单使用的HTTP方法Name&nbsp;与表单相关的ActionForm&nbsp;bean的名称。如果没有设置这个属性，bean的名称将会从配置信息中获得Onreset&nbsp;表单复位时的javascript事件句柄Onsubmit&nbsp;表单提交时的javascript事件句柄Scope&nbsp;搜索ActionForm&nbsp;bean的范围。如果没有设置，将从配置文件中获取Style&nbsp;使用的格式styleClass&nbsp;这个元素的格式表类Type&nbsp;ActionForm&nbsp;bean的完整名称。如果没有设置，将从配置文件获得&nbsp; <BR>例如：&nbsp; <BR>&lt;html:form&nbsp;action=”validateEmploee.do”&nbsp;method=”post”&gt;&nbsp; <BR>&lt;/html:form&gt;&nbsp; <BR>与表单相关的操作路径是validateEmployee,而表单数据是通过POST传递的。对于这个表单来说，ActionForm&nbsp;bean的其他信息，如bean名称类型，作用域，都是从表单指定操作的ActionMapping中检索得到的：&nbsp; <BR>21&nbsp; <BR>&lt;form-beans&gt;&nbsp; <BR>&lt;form-bean&nbsp;name=”empForm”&nbsp;type=”com.example.EmployeeForm”/&gt;&nbsp; <BR>&lt;/form-beans&gt;&nbsp; <BR>&lt;action-mappings&gt;&nbsp; <BR>&lt;action&nbsp;path=”/validateEmployee”&nbsp; <BR>type=”com.example.ValidateExampleAction”&nbsp; <BR>name=”empForm”&nbsp; <BR>scope=”request”&nbsp; <BR>input=”/employeeInput.jsp”&gt;&nbsp; <BR>&lt;forward&nbsp;name=”success”&nbsp;path=”/employeeOutput.jsp”&gt;&nbsp; <BR>&lt;/action&gt;&nbsp; <BR>&lt;/action-mapping&gt;&nbsp; <BR>如果配置文件中包含上述信息，并且请求URI的*.do被映射到ActionServlet，与表单相关的ActionForm&nbsp;bean的名称，类型和作用域分别是empForm,com.example.EmployeeForm和request.这些属性也可以使用&lt;html:form&gt;标记属性进行显示的定义。&nbsp; <BR>以下标记必须嵌套在&lt;html:form&gt;标记里&nbsp; <BR>b)&nbsp;按钮和取消标记&nbsp; <BR>&lt;html:button&gt;标记显示一个按钮控件；&lt;html:cancel&gt;标记显示一个取消按钮。属性如下：&nbsp; <BR>属性描述Property&nbsp;定义在表单被提交时返回到服务器的请求参数的名称value&nbsp;按钮上的标记&nbsp; <BR>c)&nbsp;复位和提交标记&nbsp; <BR>&lt;html:reset&gt;和&lt;html:submit&gt;标记分别能够显示HTML复位按钮和提交按钮。&nbsp; <BR>d)&nbsp;文本和文本区标记&nbsp; <BR>&lt;html:text&gt;和&lt;html:textarea&gt;标记分别HTML文本框和文本区，属性如下：&nbsp; <BR>属性描述Property&nbsp;定义当表单被提交时送回到服务器的请求参数的名称，或用来确定文本元素当前值的bean的属性名称Name&nbsp;属性被查询的bean的名称，它决定了文本框和文本区的值。如果没有设置，将使用与这个内嵌表单相关的ActionForm的名称&nbsp; <BR>&lt;html:text&gt;标记还有以下属性：&nbsp; <BR>属性描述Maxlength&nbsp;能够输入的最大字符数&nbsp; <BR>22&nbsp; <BR>Size&nbsp;文本框的大小（字符数）&nbsp; <BR>&lt;html:textarea&gt;标记特有的属性如下：&nbsp; <BR>属性描述Rows&nbsp;文本区的行数Cols&nbsp;文本区的列数&nbsp; <BR>e)&nbsp;检查框和复选框标记&nbsp; <BR>&lt;html:checkbox&gt;标记能够显示检查框控件。&lt;html:multibox&gt;标记能够显示HTML复选框控件，请求对象在传递检查框名称时使用的getParametervalues()调用将返回一个字符串数组。属性如下：&nbsp; <BR>属性描述Name&nbsp;Bean的名称，其属性会被用来确定检查是否以选中的状态显示。如果没有设置，将使用与这个内嵌表单相关的ActionFrom&nbsp;bean的名称。Property&nbsp;检查框的名称，也是决定检查框是否以选中的状态显示的bean属性名称。在复选框的情况下，这个属性必须是一个数组。value&nbsp;当检查框被选中时返回到服务器的请求参数的值&nbsp; <BR>例如：&nbsp; <BR>&lt;html:checkbox&nbsp;property=”married”&nbsp;value=”Y”/&gt;&nbsp; <BR>一个名为married的检查框，在表单提交时会返回一个”Y”.&nbsp; <BR>f)&nbsp;文件标记&nbsp; <BR>&lt;html:file&gt;标记可以显示HTML文件控件。属性如下：&nbsp; <BR>属性描述Name&nbsp;Bean的名称，它的属性将确定文件控件中显示的内容。如果没设置，将使用与内嵌表单相关的ActionForm&nbsp;bean的名称property&nbsp;这个属性定义了当表单被提交时送回到服务器的请求参数的名称，以及用来确定文件控件中显示内容的bean属性名称Accept&nbsp;服务器能够处理的内容类型集。它也将对客户浏览器对话框中的可选文件类型进行过滤value&nbsp;按钮上的标记，这个按钮能够在本地文件系统中浏览文件&nbsp; <BR>g)&nbsp;单选钮标记&nbsp; <BR>&lt;html:radio&gt;标记用来显示HTML单选钮控件，属性如下：&nbsp; <BR>属性描述Name&nbsp;Bean的名称，其属性会被用来确定单选钮是否以选中的状态显示。如果没有设置，将使用与这个内嵌表单相关的ActionFrom&nbsp;bean的名称。property&nbsp;当表单被提交时送回到服务器的请求参数的名称，以及用来确定单选钮是否以被选中状态进行显示的bean属性的名称&nbsp; <BR>23&nbsp; <BR>value&nbsp;当单选钮被选中时返回到服务器的值&nbsp; <BR>h)&nbsp;隐藏标记&nbsp; <BR>&lt;html:hidden&gt;标记能够显示HTML隐藏输入元素，属性如下：&nbsp; <BR>属性描述Name&nbsp;Bean的名称，其属性会被用来确定隐藏元素的当前值。如果没有设置，将使用与这个内嵌表单相关的ActionFrom&nbsp;bean的名称。property&nbsp;定义了当表单被提交时送回到服务器的请求参数的名称，以及用来确定隐藏元素当前值的bean属性的名称value&nbsp;用来初始化隐藏输入元素的值&nbsp; <BR>i)&nbsp;密码标记&nbsp; <BR>&lt;html:password&gt;标记能够显示HTML密码控件，属性如下：&nbsp; <BR>属性描述maxlength&nbsp;能够输入的最大字符数Name&nbsp;Bean的名称，它的属性将用来确定密码元素的当前值。如果没有设置，将使用与这个内嵌表单相关的ActionFrom&nbsp;bean的名称。property&nbsp;定义了当表单被提交时送回到服务器的请求参数的名称，以及用来确定密码元素当前值的bean属性的名称redisplay&nbsp;在显示这个字段时，如果相应的bean属性已经被设置了数据，这个属性决定了是否显示密码的内容Size&nbsp;字段的大小&nbsp; <BR>j)&nbsp;选择标记&nbsp; <BR>&lt;html:select&gt;标记能够显示HTML选择控件，属性如下：&nbsp; <BR>属性描述multiple&nbsp;表明这个选择控件是否允许进行多选Name&nbsp;Bean的名称，它的属性确定了哪个。如果没有设置，将使用与这个内嵌表单相关的ActionFrom&nbsp;bean的名称。property&nbsp;定义了当表单被提交时送回到服务器的请求参数的名称，以及用来确定哪个选项需要被选中的bean属性的名称Size&nbsp;能够同时显示的选项数目value&nbsp;用来表明需要被选中的选项&nbsp; <BR>k)&nbsp;选项标记(这个元素需要嵌套在&lt;html:select&gt;标记里)&nbsp; <BR>&lt;html:option&gt;标记用来显示HTML选项元素集合，属性如下：&nbsp; <BR>24&nbsp; <BR>属性描述collection&nbsp;Bean集合的名称，这个集合存储在某个作用域的属性中。选项的数目与集合中元素的数目相同。Property属性能够定义选项值所使用的bean属性，而labelProperty属性定义选项标记所使用的bean的属性labelName&nbsp;用来指定存储于某个作用域的bean，这个bean是一个字符串的集合，能够定义&lt;html:option&gt;元素的标记(如果标志与值不相同)&nbsp;labelProperty&nbsp;与collection属性共同使用时，用来定义了存储于某个作用域的bean，这个bean将返回一个字符串集合，能够用来写入&lt;html:option&gt;元素的value属性Name&nbsp;如果这是唯一被指定的属性，它就定义了存储于某个作用域的bean，这个bean将返回一个字符串集合，能够用来写入&lt;html:option&gt;元素的value属性property&nbsp;这个属性在与collection属性共同使用时，定义了每个要显示选项值的独立bean的name属性。如果不是与collection属性共同使用，这个属性定义了由name属性指定的bean的属性名称(如果有name属性)，或是定义了一个ActionForm&nbsp;bean，这个bean将返回一个集合来写入选项的值&nbsp; <BR>我们看一下这个标记的一些例子：&nbsp; <BR>&lt;html:option&nbsp;collection=”optionCollection”&nbsp;property=”optionvalue”&nbsp; <BR>labelProperty=”optionLabel”/&gt;&nbsp; <BR>标记假设在某个作用域中有一个名为optionCollection的集合，它包含了一些具有optionvalue属性的独立的bean，每个属性将作为一个选项的值。每个选项的标志由bean的optionLabel属性属性进行定义。&nbsp; <BR>&lt;html:option&nbsp;name=”optionvalues”&nbsp;labelName=”optionLabels”/&gt;&nbsp; <BR>标记中optionvalues代表一个存储在某个作用域中的bean，它是一个字符串集合，能够用来写入选项的值，而optionLabels代表一个存储在某个作用域中的bean，它也是一个字符串集合，能够用来写入选项的标志。&nbsp; <BR>2.3.2.显示错误信息的标记&nbsp; <BR>&lt;html:errors&gt;标记能够与ActionErrors结合在一起来显示错误信息。这个标记首先要从当前区域的资源文件中读取消息关键字errors.header，然后显示消息的文本。接下去它会在ActionErrors对象(通常作为请求参数而存储在Action.ERROR_KEY关键字下)中循环，读取单个ActionError对象的消息关键字，从当前区域的资源文件中读取并格式化相应的消息，并且显示它们。然后它读取与errors.footer关键字相对应的消息并且显示出来。&nbsp; <BR>通过定义property属性能够过滤要显示的消息，这个属性的值应该与ActionErrors对象中存储ActionError对象的关键字对应。属性如下：&nbsp; <BR>属性描述Bundle&nbsp;表示应用程序作用域属性的名称，它包含着消息资源，其默认值Acion.MESSAGE_KEY&nbsp;Locale&nbsp;表示会话作用域属性的名称，它存储着用户当前登录的区域信息。其默认值是Action.ERROR_KEY&nbsp; <BR>25&nbsp; <BR>Name&nbsp;表示请求属性的名称，它存储着ActionErrors对象。其默认值是Action.ERROR_KEY&nbsp;property&nbsp;这个属性指定了ActionErrors对象中存储每个独立ActionError对象的关键字，它可以过滤消息&nbsp; <BR>例子：&nbsp; <BR>&lt;html:errors/&gt;&nbsp; <BR>显示集合中所有的错误。&nbsp; <BR>&lt;html:errors&nbsp;property=”missing.name”/&gt;&nbsp; <BR>显示存储在missing.name关键字的错误。&nbsp; <BR>2.3.3.其他HTML标记&nbsp; <BR>struts&nbsp;HTML标记还定义了下列标记来显示其他HTML元素：&nbsp; <BR>&lt;html:html&gt;&nbsp;:&nbsp;显示HTML元素&nbsp; <BR>&lt;html:img&gt;&nbsp;:&nbsp;显示图象标记&nbsp; <BR>&lt;html:link&gt;&nbsp;:&nbsp;显示HTML链接或锚点&nbsp; <BR>&lt;html:rewrite&gt;&nbsp;:&nbsp;创建没有锚点标记的URI&nbsp; <BR>这些标记的详细内容请参照struts文档。&nbsp; <BR>2.4.&nbsp;模板标记&nbsp; <BR>动态模板是模块化WEB页布局设计的强大手段。Struts模板标记库定义了自定义标记来实现动态模板。&nbsp; <BR>2.4.1.插入标记&nbsp; <BR>&lt;template:insert&gt;标记能够在应用程序的JSP页中插入动态模板。这个标记只有一个template属性，用来定义模板JSP页。要插入到模板的页是有多个&lt;template:put&gt;标记来指定的，而这些标记被定义为&lt;template:insert&gt;标记的主体内容。&nbsp; <BR>2.4.2.放置标记&nbsp; <BR>&lt;template:put&gt;标记是&lt;template:insert&gt;标记内部使用的，用来指定插入到模板的资源。属性如下：&nbsp; <BR>属性描述content&nbsp;定义要插入的内容，比如一个JSP文件或一个HTML文件direct&nbsp;如果这个设置为true，由content属性指定的内容将直接显示在JSP上而不是作为包含文件Name&nbsp;要插入的内容的名称Role&nbsp;如果设置了这个属性，只有在当前合法用户具有特定角色时才能进行内容的插入。&nbsp; <BR>26&nbsp; <BR>2.4.3.获得标记&nbsp; <BR>在模板JSP页中使用&lt;template:get&gt;标记能够检索由&lt;template:put&gt;标记插入到JSP页的资源。属性如下：&nbsp; <BR>属性描述Name&nbsp;由&lt;template:put&gt;标记插入的内容的名称Role&nbsp;如果设置了这个属性，只有在当前合法用户具有特定角色时才能进行内容的检索&nbsp; <BR>2.4.4.使用模板标记&nbsp; <BR>首先编写一个模板JSP页，它将被所有的web页使用：&nbsp; <BR>&lt;html&gt;&nbsp; <BR>&lt;%@&nbsp;taglib&nbsp;uri=”/template”&nbsp;prefix=”template”&nbsp;%&gt;&nbsp; <BR>&lt;head&gt;&nbsp; <BR>&lt;title&gt;&lt;/title&gt;&nbsp; <BR>&lt;/head&gt;&nbsp; <BR>&lt;body&gt;&nbsp; <BR>&lt;table&nbsp;width=”100%”&nbsp;height=”100%”&nbsp;&gt;&nbsp; <BR>&lt;tr&nbsp;height=”10%”&gt;&nbsp; <BR>&lt;td&gt;&nbsp; <BR>&lt;template:get&nbsp;name=”header”/&gt;&nbsp; <BR>&lt;/td&gt;&nbsp; <BR>&lt;/tr&gt;&nbsp; <BR>&lt;tr&nbsp;height=”80%”&gt;&nbsp; <BR>&lt;td&gt;&nbsp; <BR>&lt;template:get&nbsp;name=”content”/&gt;&nbsp; <BR>&lt;/td&gt;&nbsp; <BR>&lt;/tr&gt;&nbsp; <BR>&lt;tr&nbsp;height=”10%”&gt;&nbsp; <BR>&lt;td&gt;&nbsp; <BR>&lt;template:get&nbsp;name=”footer”/&gt;&nbsp; <BR>&lt;/td&gt;&nbsp; <BR>&lt;/tr&gt;&nbsp; <BR>&lt;/table&gt;&nbsp; <BR>&lt;/body&gt;&nbsp; <BR>&lt;/html&gt;&nbsp; <BR>我们将这个文件命名为template.jsp。这个文件使用&lt;template:get&gt;标记来获得由JSP页使用&lt;template:put&gt;标记提供的内容，并且将内容在一个HTML表格中显示出来。这三个内容是标题，内容和页脚。典型的内容JSP会是这样：&nbsp; <BR>&lt;%@&nbsp;taglib&nbsp;uri=”/template”&nbsp;prefix=”/template”&nbsp;%&gt;&nbsp; <BR>&lt;template:insert&nbsp;template=”template.jsp”&gt;&nbsp; <BR>&lt;template:put&nbsp;name=”header”&nbsp;content=”header.html”/&gt;&nbsp; <BR>27&nbsp; <BR>&lt;template:put&nbsp;name=”content”&nbsp;content=”employeeList.jsp”/&gt;&nbsp; <BR>&lt;template:put&nbsp;name=”footer”&nbsp;content=”footer.html”/&gt;&nbsp; <BR>&lt;/template:insert&gt;&nbsp; <BR>这个应用程序JSP页使用&lt;template:insert标记来定义模板，然后使用&lt;template:put&gt;标记将特定内容名称指定的资源放到模板JSP页中。如果我们有上百个布局相同的页，但突然想改变这个模板，我们只需要改变template.jsp文件。<img src ="http://www.blogjava.net/qq13367612/aggbug/16661.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qq13367612/" target="_blank">Sung</a> 2005-10-24 22:18 <a href="http://www.blogjava.net/qq13367612/articles/16661.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Struts Action Mapping(含译文)</title><link>http://www.blogjava.net/qq13367612/articles/16660.html</link><dc:creator>Sung</dc:creator><author>Sung</author><pubDate>Mon, 24 Oct 2005 14:17:00 GMT</pubDate><guid>http://www.blogjava.net/qq13367612/articles/16660.html</guid><wfw:comment>http://www.blogjava.net/qq13367612/comments/16660.html</wfw:comment><comments>http://www.blogjava.net/qq13367612/articles/16660.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qq13367612/comments/commentRss/16660.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qq13367612/services/trackbacks/16660.html</trackback:ping><description><![CDATA[<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan"><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">This article discusses different combinations of a Struts action class and a form bean and how these combinations can be used. <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">本文讨论了</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Struts</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">框架中</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Action</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">以及</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Form Bean</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">之间的不同组合方式以及这些组合的使用。</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt"><o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan; mso-outline-level: 2"><B><SPAN lang=EN-US style="FONT-SIZE: 18pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt"><BR><BR>Full action（</SPAN></B><B><SPAN style="FONT-SIZE: 18pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">一个完整的</SPAN></B><B><SPAN lang=EN-US style="FONT-SIZE: 18pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Action） <o:p></o:p></SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan"><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">This is arguably the most popular form of Struts action. It contains an action class and a form bean. The action mapping for this operation looks like this: <o:p></o:p></SPAN></P>
<P><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">首先这里要讨论的是</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">Struts</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">框架中最常用的组合，即一个</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">Action</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">对应一个</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">Form Bean</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">。这样的对应关系可以用下图来解释：</SPAN>&nbsp;&nbsp;&nbsp;&nbsp;<ACTION path="/fullAction" type="com.acme.struts.MyAction" name="myForm" input="/WEB-INF/jsp/dataError.jsp">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<FORWARD path="/WEB-INF/jsp/viewResult.jsp" name="OK" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<FORWARD path="/WEB-INF/jsp/busError.jsp" name="ERROR" />&nbsp;&nbsp; </ACTION></P>
<P><IMG src="http://www.blogjava.net/images/blogjava_net/qq13367612/4168/o_IMG01.gif"></P>
<H2>Full action call sequence</H2>
<UL>
<LI>Struts controller component receives a request. 
<LI>Struts identifies the action mapping which is responsible for request processing. 
<LI>Struts creates a new instance of the form bean, if it was not found in the scope or if the scope has "request" type. If the bean exists in the scope, it is reused. 
<LI>If form bean defines reset() method, it is called (1) 
<LI>Struts populates the fields with request arguments, using mutators (2) 
<LI>Struts calls validate() method if "validate" attribute of action mapping is not set to "false" (3) 
<LI>If validate() returns non-empty ActionErrors object, control is forwarded to an URI identified by "input" attribute of the action mapping (4a) 
<LI>if validate() returns empty ActionErrors object or null, Struts calls execute() method of the action class (4b) 
<LI>execute() method returns an ActionForward object, which is used by Struts to select the destination URI (5) <BR>
<LI class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan; tab-stops: list 36.0pt; mso-list: l0 level1 lfo1"><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Struts</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">框架的控制器组件接收到一个</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Request</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">请求；</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt"><o:p></o:p></SPAN> 
<LI class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan; tab-stops: list 36.0pt; mso-list: l0 level1 lfo1"><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Struts</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">框架通过</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Action Mapping</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">配置来确定处理这个请求的</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Action</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">；</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt"><o:p></o:p></SPAN> 
<LI class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan; tab-stops: list 36.0pt; mso-list: l0 level1 lfo1"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">如果在可见域（</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">scope</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">）内不存在该</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Action</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">对应的</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Form Bean</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">或者可见域为</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Request</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">时，</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Struts</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">框架创建一个新的（该</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Action</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">对应的）</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Form Bean</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">的实例。如果在可见域内存在此</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Form Bean</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">，则可以重用；</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt"><o:p></o:p></SPAN> 
<LI class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan; tab-stops: list 36.0pt; mso-list: l0 level1 lfo1"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">如果在</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Form Bean</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">中定义了</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">reset</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">（）方法，则调用该方法；（１）</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt"><o:p></o:p></SPAN> 
<LI class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan; tab-stops: list 36.0pt; mso-list: l0 level1 lfo1"><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Struts</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">框架以</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Request</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">域中的变量自动填充</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Form Bean</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">中的变量，使用</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">mutators</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">；（２）</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt"><o:p></o:p></SPAN> 
<LI class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan; tab-stops: list 36.0pt; mso-list: l0 level1 lfo1"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">如果配置文件（</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">struts-config.xml</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">）</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Action-Mapping</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">对应的</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">validate</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">属性被设置为</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">True</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">，那么</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Struts</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">框架将自动调用</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">validate</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">（）方法；（３）</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt"><o:p></o:p></SPAN> 
<LI class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan; tab-stops: list 36.0pt; mso-list: l0 level1 lfo1"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">如果</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Validate</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">（）方法返回一个非空的</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">ActionErrors</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">对象，</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Struts</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">控制器会将页面导向至配置文件中定义个某个处理错误的页面；</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt"> <SPAN lang=EN-US><o:p></o:p></SPAN></SPAN>
<LI class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan; tab-stops: list 36.0pt; mso-list: l0 level1 lfo1"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">如果</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Validate</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">（）方法返回的</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">ActionErrors</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">对象为空，</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Struts</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">框架将会自动调用</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Action</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">的</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Execute</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">（）方法；（４</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">b</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">）</SPAN> 
<LI class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan; tab-stops: list 36.0pt; mso-list: l0 level1 lfo1"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'"></SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">Execute</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">（）方法将会返回一个</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">ActionForward</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">的对象，</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">Struts</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">框架会通过这个对象决定页面的转向地址。（５）</SPAN></LI></UL>
<H2>Consequences and usage tips</H2>
<UL>
<LI>execute() method of an action class is not called if ActionForm.validate() returns non-empty ActionErrors object. Instead, control is directly routed to the URI defined in "input" attribute of action mapping. 
<LI>"input" attribute of action mapping allows forwarding to an URI only. If you need to redirect, use Controller.inputForward property. This property was introduced in Struts 1.1. When it set to "true" it indicates that Action.input is not a URI, but a name of an Action.forward element. <BR></LI></UL>
<UL type=disc>
<LI class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan; tab-stops: list 36.0pt; mso-list: l0 level1 lfo1"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">如果</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Action</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">对应</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Form Bean</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">的</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">validate</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">（）方法返回的是一个非空的</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">ActionErrors</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">对象，那么</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Action</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">的</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Execute</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">（）方法将不会被调用。此时，</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Struts</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">框架将直接把页面导向</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Action Mapping</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">中</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">input</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">属性定义的错误处理页面；</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt"><o:p></o:p></SPAN></LI>
<LI class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan; tab-stops: list 36.0pt; mso-list: l0 level1 lfo1"><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Action Mapping</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">中“</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Input</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">”属性指定的仅为一个</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Form Bean</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">的</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">URL</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">路径。如果需要重定向页面，应当使用</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Controller.inputForward</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">属性（该属性在</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Struts1.1</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">版本中引入）。当该属性被设为“</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">True</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">”时，表明</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Input</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">属性设置的不是</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">URL</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">而是一个</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">Action.forward</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'">元素名。</SPAN><SPAN lang=EN-US style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt"><o:p></o:p></SPAN></LI></UL>
<H2>Form-only action</H2>
<P>This action combines a custom form bean and the standard ForwardAction class. This type of action can be used when an action has only two outcomes, one of which is an error.</P><PRE>    <ACTION path="/formOnlyAction" type="org.apache.struts.actions.ForwardAction" name="myForm" input="/WEB-INF/jsp/error.jsp" parameter="/WEB-INF/jsp/viewResult.jsp" />
</PRE>
<P><IMG src="http://www.blogjava.net/images/blogjava_net/qq13367612/4168/o_IMG02.gif"></P>
<H2>Form-only call sequence</H2>
<UL>
<LI>Struts creates a new instance of the form bean, if it was not found in the scope or if the scope has "request" type. If the bean exists in the scope, it is reused. 
<LI>If the form bean defines reset() method, it is called (1) 
<LI>Struts populates the fields with request arguments, using mutators (2) 
<LI>Struts calls validate() method if "validate" attribute of action mapping is not set to "false" (3) 
<LI>If validate() returns non-empty ActionErrors object, control is forwarded to an URI identified by "input" attribute of the action mapping (4a) 
<LI>if validate() returns empty ActionErrors object or null, control is forwarded to an URI identified by "parameter" attribute of the action mapping (4b) </LI></UL>
<H2>Consequences and usage tips</H2>
<UL>
<LI>There is no action class to put business code in, so all custom code must be called from either reset() or validate() methods of the form bean. 
<LI>validate() performs two functions: validating request arguments, and accessing the business layer. 
<LI>Because action mapping does not contain "forward" elements, control can be only forwarded, but cannot be redirected. 
<LI>One of the possible usages of a form-only action is response rendering. A form bean can receive a business object id with a request, then look up the business object in the business/persistence layer, fill in the form fields and forward to a JSP which would display the result. 
<LI>It may be convenient to use "session" scope for form-only actions, thus implementing caching of output data. </LI></UL>
<H2>Action class-only action</H2>
<P>Struts does not require to declare a form bean for an action mapping. Hence the seemingly tautological action-only action.</P><PRE>    <ACTION path="/actionOnlyAction" type="com.acme.struts.MyAction" input="/WEB-INF/jsp/error.jsp">
            <FORWARD path="/viewResult.do" name="OK" />
            <FORWARD path="/WEB-INF/jsp/error.jsp" name="ERROR" />
    </ACTION>
</PRE>
<H2><IMG src="http://www.blogjava.net/images/blogjava_net/qq13367612/4168/o_IMG03.gif"></H2>
<H2>Action-class only call sequence</H2>
<UL>
<LI>execute() is called on the action class (1) 
<LI>execute() returns ActionForward object; target URI must be defined in a "forward" element of action mapping (2) </LI></UL>
<H2>Consequences and usage tips</H2>
<UL>
<LI>This action does not declare a form bean, thus Struts passes null to execute() method instead of a form bean. 
<LI>If the action receives request parameters, they must be retrieved from the request object manually. Action class-only action may be used if just a few or no parameters are passed with request, otherwise it is easier to use a form bean. 
<LI>Control may be either forwarded or redirected to another action or JSP page. If you are forwarding control to a JSP, make sure that necessary form beans with output data exist in the scope. 
<LI>Action-class only action cannot be called from HTML FORM, because Struts expects to find the form bean definition in an action mapping which serves the FORM. As a workaround, you can call an action-class only action from a link. </LI></UL>
<H2>JSP-only action</H2>
<P>This is the most compact, most error-prone and the least useful type of action. It can be used if it is forwarded to from another action, or if there are other means to obtain needed data.</P><PRE>    <ACTION path="/JSPOnlyAction" type="org.apache.struts.actions.ForwardAction" parameter="/WEB-INF/jsp/viewResult.jsp" /></PRE>
<P><IMG height=145 alt=o_IMG04.gif src="http://www.blogjava.net/images/blogjava_net/qq13367612/4168/o_IMG04.gif" width=445 border=0></P>
<H2>The call chain</H2>
<UL>
<LI>request is received by Struts controller component 
<LI>Struts calls ForwardAction.execute() 
<LI>ForwardAction.execute() forwards control to an action defined in "parameter" attribute of the action mapping. </LI></UL>
<H2>Consequences and usage tips</H2>
<UL>
<LI>This action does not use a form bean, thus it is not created, not initialized, not populated and not passed to an action class. 
<LI>Though I called it JSP-only operation, it can forward to any URI including other action if needed. 
<LI>Because a form bean is not instantiated during the course of this operation, JSP relies on a form bean which was created earlier and is in the scope of the action. Form bean could be created in another action which forwards control to this action, or it could be created with "session" or higher scope during processing of another request. 
<LI>Usage of this action is very limited. For example, it can be used as a switching yard to forward to another action. After application is compiled and deployed, the course of operation can be switched in the config file using this action. </LI></UL>
<H2>Two actions, one form</H2>
<P>Struts allows to call one action from another, thus it is possible to implement a simple Chain of Responsibility.</P><PRE>  <IMG height=375 alt=o_IMG05.gif src="http://www.blogjava.net/images/blogjava_net/qq13367612/4168/o_IMG05.gif" width=497 border=0></PRE>
<H2>Two-action call sequence and usage tips</H2>
<P>The call sequence does not differ from the full-action case. The problem is, that Struts calls reset() and validate() methods again for the target action, and it populates form bean fields as well. To use form bean as a transport/command object we must prevent overwriting of form bean fields.</P>
<P>The solution depends on how the target action is called. If the target action is forwarded to, we can use a token in the HttpRequest object to distinguish if an action is the first action in the chain.</P>
<UL>
<LI>Check for the token in the reset() method of the form. If token not found, then this action is the first in the chain. If token is found, do not reset form fields, because this is a chained action. 
<LI>Plant a token into the request object. This must be done in reset() method, because it is always called unlike validate(). validate() may be not called if "validate" property is set to "false" in struts-config.xml file. 
<LI>Verify in each mutator, that the action is first in chain. If not, do not allow changing the field value. This prevents Struts from modifying the form fields. • 
<LI>check for token in validate() method. If not present, validate form fields, because this is the first action in chain. </LI></UL>
<P>You do not need to remove the token from the request object, the request will be disposed automatically.</P>
<P>If you use redirection to call the target action, you cannot use request token, because request object is recreated after redirection. The following solutions are possible:</P>
<UL>
<LI>Read action mapping name. This works only if you have strict rules defining when each action is called. If struts-config.xml is changed, the code would have to be updated. 
<LI>Store a token on the server in the object with session or higher scope. The token should be promptly removed when the last action in chain finishes. 
<LI>Stick a token into the target URI of the response object, it would be passed to a target action as an HTTP request parameter after redirect completes. This solution takes some additional effort, but the result worth it. </LI></UL>
<P>Important: use the same form scope in both actions for predictable behavior.</P>
<H2>Two actions, two forms</H2>
<P>As long as we already have two actions, why not to have two different forms.</P><PRE>    <ACTION path="/inputAction" type="com.acme.struts.Action1" name="inputForm" input="/WEB-INF/jsp/error1.jsp">
 <IMG height=335 alt=o_IMG06.gif src="http://www.blogjava.net/images/blogjava_net/qq13367612/4168/o_IMG06.gif" width=457 border=0>      <FORWARD path="/WEB-INF/jsp/viewTarget.jsp" name="OK" />
  </ACTION></PRE>
<H2>Two-action, two form usage tips</H2>
<P>The call sequence does not differ from the previous case. But because now we have two different form types and different instances, we can make the code much cleaner.</P>
<P>This design can be used to handle input and output of web applications. The source action receives the request, the source form validates the input data. If input is valid, the control is redirected to output action. Struts would want to populate form bean fields again, but here is the trick: you can either define fields with different names, or even better, you can define only accessors for the output form bean. Struts uses accessors and mutators to operate on form bean fields, so without mutators it would not be able to modify the fields of the output form.</P>
<H2>The control flow looks like this:</H2>
<UL>
<LI>Struts calls reset() on the input form bean (1) 
<LI>Struts populates the fields of input form bean using mutators (2). Input form bean does not even have to define the accessors. 
<LI>truts calls validate() on input form bean, which validates request data (3) 
<LI>If validate() returns non-empty ActionErrors object, control is forwarded to an error page identified by "input" attribute of the action mapping (4a) 
<LI>if validate() returns empty ActionErrors object or null, Struts calls execute() method of the input action class (4b) 
<LI>execute() updates business and persistent objects. 
<LI>execute() creates new ActionForward instance with modified URI of the target action, adding to it the ID of an object which must be displayed. 
<LI>if execute() returns "OK", Struts redirects to the output action (5) 
<LI>Struts calls reset() on the output form bean (6) 
<LI>Struts tries to populate the fields of the output form bean, but because there are no mutators defined, they are not changed (7) 
<LI>validate() has nothing to validate in the output form, so it returns null (8) 
<LI>execute() method of the action class locates business object using ID passed with the request, fills out the fields of the output form with business data and returns "OK" (9b) 
<LI>Struts displays the result page (10) </LI></UL>
<P>Because I fill out the output form manually with the persistent data, I do not need to preserve values of the input form bean. Thus, I do not need to use forwarding, and I can employ redirection instead. This way, input action and output action become less tied to each other. </P>
<P>A very nice side effect of this solution is that output page can be easily reloaded without processing the request in input action again. This helps to prevent double submission of input data.</P>
<P>More on double submit problem and how it can be defeated see in my other article: <A href="http://www.theserverside.com/articles/article.tss?l=RedirectAfterPost">Redirect After Post</A></P>
<H2>About the Author</H2>
<P>Michael holds an MS in Computer Science from Moscow Aviation Institute (technical university), Moscow, Russia. He has more than 10 years of experience developing applications for MS-DOS, Windows and Java platform. he has devoted the last 5 years to server-side Java applications. Curently he is employed as a software engineer at International Lottery and Totalizator, Inc. </P><img src ="http://www.blogjava.net/qq13367612/aggbug/16660.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qq13367612/" target="_blank">Sung</a> 2005-10-24 22:17 <a href="http://www.blogjava.net/qq13367612/articles/16660.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Struts原理与实践 </title><link>http://www.blogjava.net/qq13367612/articles/16658.html</link><dc:creator>Sung</dc:creator><author>Sung</author><pubDate>Mon, 24 Oct 2005 14:15:00 GMT</pubDate><guid>http://www.blogjava.net/qq13367612/articles/16658.html</guid><wfw:comment>http://www.blogjava.net/qq13367612/comments/16658.html</wfw:comment><comments>http://www.blogjava.net/qq13367612/articles/16658.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qq13367612/comments/commentRss/16658.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qq13367612/services/trackbacks/16658.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: (第1部分) 一、 什么是Struts 框架（Framework）是可重用的，半完成的应用程序，可以用来产生专门的定制程序。 您只要细心地研究真实的应用程序，就会发现程序大致上由两类性质不同的组件组成，一类与程序要处理的具体事务密切相关，我们不妨把它们叫做业务组件；另一类是应用服务。比如说：一个税务征管系统和一个图书管理系统会在处理它们的业务方面存在很大的差异，这些直接处理业务的组件由于业...&nbsp;&nbsp;<a href='http://www.blogjava.net/qq13367612/articles/16658.html'>阅读全文</a><img src ="http://www.blogjava.net/qq13367612/aggbug/16658.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qq13367612/" target="_blank">Sung</a> 2005-10-24 22:15 <a href="http://www.blogjava.net/qq13367612/articles/16658.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Struts入门经验 </title><link>http://www.blogjava.net/qq13367612/articles/16657.html</link><dc:creator>Sung</dc:creator><author>Sung</author><pubDate>Mon, 24 Oct 2005 14:14:00 GMT</pubDate><guid>http://www.blogjava.net/qq13367612/articles/16657.html</guid><wfw:comment>http://www.blogjava.net/qq13367612/comments/16657.html</wfw:comment><comments>http://www.blogjava.net/qq13367612/articles/16657.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qq13367612/comments/commentRss/16657.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qq13367612/services/trackbacks/16657.html</trackback:ping><description><![CDATA[<SPAN class=myp111><FONT id=zoom><B>Struts安装：</B> <BR><BR>首先请到<A href="http://jakarta.apache.org/Struts">http://jakarta.apache.org/Struts</A>下载Struts，建议使用release版，现在最高版本为1.1，下载后得到的是一个ZIP文件。 <BR><BR>将ZIP包解开，可以看到这个目录：lib和webapps，webapps下有一些WAR文件。假设你的Tomcat装在c:\Tomcat下，则将那些WAR文件拷贝到C:\Tomcat\webapps，重新启动Tomcat即可。打开浏览器，在地址栏中输入：<A href="http://localhost:8080/Struts-example/index.jsp">http://localhost:8080/Struts-example/index.jsp</A>，若能见到“powered by Struts”的深蓝色图标，即说明成功了。这是Struts自带的一个例子，附有详细的说明文档，可以做为初学者的入门教程。另外，Struts还提供了一系统实用对象：XML处理、通过Java reflection APIs自动处理JavaBeans属性、国际化的提示和消息等 <BR><BR><B>一个实例：</B> <BR><BR>一个用户注册系统，用户通过网页输入相关信息：注册ID号，密码，EMAIL，若注册成功，则返回成功提示信息，反之出现注册失败提示信息。 <BR><BR>以下是相关文件的部分核心代码。 <BR><BR><B>项目建立：</B> <BR><BR>正式开发前，需要在Tocmat（我的tomcat装在c:\tomcat）中建立此项目。比较快的一种建立方式为：在C:\tomcat\webapps下新建目录test，再将C:\tomcat\webapps\struts-example下的 <BR><BR>WEB-INF目录拷贝到test目录下，然后将test\WEB-INF下的src和classes目录清空，以及struts-config.xml文件中内容清空即可。这样，我们需要的Struts类包及相关的配置文件就都齐了。 <BR><BR>开发时，将JSP文件放在test目录下，Java原文件放在test\WEB-INF\src下，编译后的类文件放在test\WEB-INF\classes下。 <BR><BR><B>注册页面：reguser.jsp</B> <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>&lt;%@ page contentType="text/html;charset=UTF-8" language="java" %&gt;
&lt;%@ taglib uri="/WEB-INF/Struts-bean.tld" prefix="bean" %&gt;
&lt;%@ taglib uri="/WEB-INF/Struts-html.tld" prefix="html" %&gt;
&lt;html:html locale="true"&gt;
&lt;head&gt;
&lt;title&gt;RegUser&lt;/title&gt;
&lt;html:base/&gt;
&lt;/head&gt;
&lt;body bgcolor="white"&gt;
&lt;html:errors/&gt;
&lt;html:form action="/regUserAction" focus="logname"&gt;
&lt;table border="0" width="100%"&gt;
  &lt;tr&gt;
    &lt;th align="right"&gt;
      Logname:
    &lt;/th&gt;
    &lt;td align="left"&gt;
      &lt;html:text property="logname" size="20" maxlength="20"/&gt;
    &lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;th align="right"&gt;
      Password:
    &lt;/th&gt;
    &lt;td align="left"&gt;
      &lt;html:password property="password" size="20" maxlength="20"/&gt;
    &lt;/td&gt;
  &lt;/tr&gt; 
  &lt;tr&gt;
    &lt;th align="right"&gt;
      E-mail:
    &lt;/th&gt;
    &lt;td align="left"&gt;
      &lt;html:password property="email" size="30" maxlength="50"/&gt;
    &lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td align="right"&gt;
      &lt;html:submit property="submit" value="Submit"/&gt;
    &lt;/td&gt;
    &lt;td align="left"&gt;
      &lt;html:reset/&gt;
    &lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;
&lt;/html:form&gt;
&lt;/body&gt;
&lt;/html:html&gt;</PRE></TD></TR></TBODY></TABLE>
<P><BR><BR>此JSP页面不同于普通的JSP页，因为它大量运用了taglib，这些taglib对初学者而言，可能难于掌握，可这却是Struts的精华之一。灵活运用，将大大提高开发效率。 </P></FONT></SPAN>
<P></P>
<P></P>
<P>上一篇Struts入门经验，我们主要讲述了如何安装Struts以及注册页面：reguser.jsp，本文将主要介绍Struts应用实例、优缺点和实施经验。 <BR><BR><B>Struts-config.xml：</B> <BR><BR><BR><BR><BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>&lt;Struts-config&gt; 
&lt;form-beans&gt;
&lt;form-bean      name="regUserForm"
type="org.cjea.Struts.example. RegUserForm "/&gt; 
&lt;/form-beans&gt;
&lt;action-mappings&gt;
&lt;action  path="/regUserAction"
        type=" org.cjea.Struts.example.RegUserAction "
        attribute=" regUserForm "
        scope="request"
        validate="false"&gt;
      &lt;forward name="failure"   path="/ messageFailure.jsp"/&gt;
      &lt;forward name="success"  path="/ messageSuccess.jsp"/&gt;
&lt;/action&gt;
&lt;/action-mappings&gt;
&lt;/Struts-config&gt;</PRE></TD></TR></TBODY></TABLE><BR><BR>Struts的核心是Controller，即ActionServlet，而ActionServlet的核心就是Struts-config.xml，Struts-config.xml集中了所有页面的导航定义。对于大型的WEB项目，通过此配置文件即可迅速把握其脉络，这不管是对于前期的开发，还是后期的维护或升级都是大有裨益的。掌握Struts-config.xml是掌握Struts的关键所在。 <BR><BR><B>FormBean：RegUserForm</B> <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>package org.cjea.Struts.example;

import javax.Servlet.http.HttpServletRequest;
import org.apache.Struts.action.ActionForm;
import org.apache.Struts.action.ActionMapping;

public final class RegUserForm extends ActionForm{

  private String logname;
  private String password;
  private String email;

  public RegUserForm(){
    logname = null;
    password = null;
    email = null;
  }

  public String getLogName() {
    return this.logname;
  }
  public void setLogName(String logname) {
    this.logname = logname;
  }
  public void setPassWord(String password) {
    this.password = password;
  }
  public String getPassWord() {
    return this.password;
  }
  public void setEmail(String email) {
    this.email = email;
  }
  public String getEmail() {
    return this.email;
  }

  public void reset(ActionMapping mapping, HttpServletRequest request)
    {
        logname = null;
  password = null;
  email = null;
    }
}</PRE></TD></TR></TBODY></TABLE><BR><BR>每一个FormBean 都必须继承ActionForm类，FormBean是对页面请求的封装。即把HTTP request 封装在一个对象中，需要说明的一点就是多个HTTP request可以共用一个FormBean，便于维护和重用。 <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>ActionBean：RegUserAction

package org.cjea.Struts.example;

import javax.Servlet.http.*;
import org.apache.Struts.action.*;

public final class RegUserAction extends Action
{

 public ActionForward perform(ActionMapping mapping,
  ActionForm form,  HttpServletRequest req,
  HttpServletResponse res)
 {  
  String title = req.getParameter("title");
  String password = req.getParameter("password");
  String email = req.getParameter("email");
  /*
  取得用户请求,做相应数据库操作，略
  */  
 }
}</PRE></TD></TR></TBODY></TABLE><BR><BR>FormBean的产生是为了提供数据给ActionBean，在ActionBean中可以取得FormBean中封装的数据，经相应的逻辑处理后，调用业务方法完成相应业务要求。 <BR><BR>Servlet的演变：在常规的 JSP，Servlet，JavaBean三层结构中，JSP实现View的功能，Servlet实现Controller的功能，JavaBean实现Model的实现。 <BR><BR>在Struts中，将常规情况下的Servlet拆分与ActionServlet、FormBean、ActionBean三个部分。ActionServlet配合Struts-config.xml，专职完成页面导航，而不再负责具体的数据获取与相应逻辑，这两部分功能由FormBean和ActionBean来完成。 <BR><BR><B>Struts优缺点</B> <BR><BR>优点： <BR><BR>Struts跟Tomcat、Turbine等诸多Apache项目一样，是开源软件，这是它的一大优点。使开发者能更深入的了解其内部实现机制。 <BR><BR>除此之外，Struts的优点主要集中体现在两个方面：Taglib和页面导航。Taglib是Struts的标记库，灵活动用，能大大提高开发效率。另外，就目前国内的JSP开发者而言，除了使用JSP自带的常用标记外，很少开发自己的标记，或许Struts是一个很好的起点。 <BR><BR>关于页面导航，我认为那将是今后的一个发展方向，事实上，这样做，使系统的脉络更加清晰。通过一个配置文件，即可把握整个系统各部分之间的联系，这对于后期的维护有着莫大的好处。尤其是当另一批开发者接手这个项目时，这种优势体现得更加明显。 <BR><BR>缺点： <BR><BR>Taglib是Struts的一大优势，但对于初学者而言，却需要一个持续学习的过程，甚至还会打乱你网页编写的习惯，但是，当你习惯了它时，你会觉得它真的很棒。 <BR><BR>Struts将MVC的Controller一分为三，在获得结构更加清晰的同时，也增加了系统的复杂度。 <BR><BR>Struts从产生到现在还不到半年，但已逐步越来越多运用于商业软件。虽然它现在还有不少缺点，但它是一种非常优秀的J2EE MVC实现方式，如果你的系统准备采用J2EE MVC架构，那么，不妨考虑一下Struts。 <BR><BR><B>Struts实施经验：</B> <BR><BR>1、基于Struts架构的项目开发，首先需要有一个很好的整体规划，整个系统中包括哪几个模块，每个模块各需要多少FormBean和ActionBean等，而且最好有专人负责Struts-config.xml的管理。开发基于Struts的项目的难点在于配置管理，尤其是对Struts-config.xml的管理 <BR><BR>2、如果你的项目非常紧，并且项目组中又没有富有经验的Struts开发人员，建议不要冒然采用Struts。Struts的掌握需要一个过程，对于一个熟练的JSP程序员，自学大概需要半个月左右的时间。如果结合titls，则需要更长的时间 <BR><BR>3、如果你在网页中大量运用taglib，那么你的美工将做出部分牺牲。当你结合Tiles，功能增强的同时，这种牺牲尤为明显。当然，你对功能和美观的取舍由你自己决定 <BR><BR>4、Taglib是一个好东西，但灵活运用它却需要一个过程，如果你不想在Taglib上花太多的时间，那么只需理解与FORM有关的几个标记，其它的标记就放着吧，以后再看，先去研究ActionServlet和Struts-config.xml，你会觉得很有成就感 <BR><BR>5、Struts是否只适合于大型项目呢？No！Struts适合于各种大小的项目，当然，对于大型项目，它所体现出来的优势更加明显 </P><img src ="http://www.blogjava.net/qq13367612/aggbug/16657.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qq13367612/" target="_blank">Sung</a> 2005-10-24 22:14 <a href="http://www.blogjava.net/qq13367612/articles/16657.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>克服Struts开发障碍</title><link>http://www.blogjava.net/qq13367612/articles/16656.html</link><dc:creator>Sung</dc:creator><author>Sung</author><pubDate>Mon, 24 Oct 2005 14:13:00 GMT</pubDate><guid>http://www.blogjava.net/qq13367612/articles/16656.html</guid><wfw:comment>http://www.blogjava.net/qq13367612/comments/16656.html</wfw:comment><comments>http://www.blogjava.net/qq13367612/articles/16656.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qq13367612/comments/commentRss/16656.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qq13367612/services/trackbacks/16656.html</trackback:ping><description><![CDATA[<A name=1><B>一、摘要</B></A> <BR><BR>建立和维护企业应用程序非常困难。而为这些应用设计出上乘的、易于维护的用户界面则是所有工作中最让人畏惧的任务。来自Apache Jakarta 项目的Struts框架为J2EE(Java2平台企业版)带来了Model 2 结构。在本文中，两位作者讨论了开发者在使用Struts 的过程中所遇到的问题，以及简化这些问题的相应方法。 <BR><BR>除非你过去几年内潜居于石洞之中，否则你不可能没听说过Struts framework。Struts是由Apache软件基金会最初发起的开源，主要是为了促进Web应用演示层内的模型-视图-控制器(MVC)设计范例。truts 提供了使用Service的MVC模式给Worker 模式。一个设计优秀的结构总是力争耦合宽松、结合性高。Struts为在多捆绑的企业Web应用的演示层实现这个目标提供了一个机制。 实现企业应用结构所面对的最让人望而生畏的任务之一就是演示层的创建和维护。用户期望得到非常功能化的、坚固的、和优雅的灰土用户界面。因此，演示层的代码库使得应用层超负荷运行。另外，不同的显示平台如无线电话和PDAs 的出现使得原本复杂的状况更加复杂的多。 <BR><BR>各种不同的书和文章已经讲述了Struts的内部工作原理并且教我们如何使用这个框架。本文详细阐述了使用Struts 的Web应用开发者所遇到的问题，以及如何解决这些问题。下列方法中有许多可以应用到不同的MVC框架中如即将上市的JavaServer Faces 规范。 Craig R. McClanahan，Struts的创始人之一，造就了这个规范。 <BR><BR>本讨论的主题包括：在使用Struts框架，用BEA WebLogic Server建立J2EE（Java2平台企业版）应用的过程中出现最多问题的所有区域。我们将讨论下列专题： <BR>·创建/维护 struts-config.xml <BR>·表格/会话期管理 <BR>·Struts 映射和用户界面的关系 <BR>·管理Back按钮 <BR>·用户认证 <BR>·用户界面控制流程 <BR>· 异常处理 <BR>·测试 <BR><BR><A name=2><B>二、挑两个，早上呼我</B></A> <BR><BR>Struts框架毫无疑问，减轻了企业应用程序的用户界面的开发和维护。但是，即使只是在一个简单的应用中使用了Struts ，开发者也会迅速的认识到struts-config.xml这个恶魔。 这个文件很有可能迅速变得难于处理。在建立企业应用时，struts-config.xml 能够多出 500个动作映射，使得自身变得真正地难于管理。 <BR><BR>我们推荐两个工具来帮助治理这个头疼的问题。首先，使用来自Alien-Factory 的Microsoft Visio 和StrutsGUI 文档化你的用户界面流程。StrutsGUI是一个Visio 模版，它对使用Struts 术语描述用户流程图有帮助。在Struts 模版内有一个隐藏的功能：只要右键点击该项，选择Edit Title Properties，然后选择Tools项，你就能够在该图的基础上生成struts-config.xml 文件。例如，图1中显示的简单应用生成了如下列代码所示的struts-config.xml ： <BR><BR>
<CENTER><IMG height=170 src="http://tech.ccidnet.com/pub/attachment/2004/2/272032.gif" width=653> <BR><BR>Figure 1. StrutsGUI model. Click on thumbnail to view full-size image. </CENTER><BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>&lt;?xml version="1.0" encoding="ISO-8859-1" ?&gt;

&lt;!-- Struts Config XML - Sample Struts App --&gt;
&lt;!-- ===================================== --&gt;

&lt;!-- AutoGenerated from : c:\dev\javaworld\app\sample.vsd --&gt;
&lt;!-- AutoGenerated on   : 02-18-2003 23:05:47 --&gt;
&lt;!-- AutoGenerated by   : Struts GUI v2.11   (c)2002 Alien-Factory --&gt;
&lt;!--                    : See 'http://www.alien-factory.co.uk' for details --&gt;

&lt;!-- GET YOUR STICKY FINGERS OFF! i.e. Do not edit. --&gt;

&lt;!DOCTYPE struts-config PUBLIC
      "-//Apache Software Foundation//DTD Struts Configuration 1.0//EN"
      "http://jakarta.apache.org/struts/dtds/struts-config_1_0.dtd"&gt;

&lt;struts-config&gt;

  &lt;!-- ====================== Form Bean Definitions =================== --&gt;
  &lt;form-beans&gt;
  &lt;/form-beans&gt;

  &lt;!-- ================= Global Forward Definitions =================== --&gt;
  &lt;global-forwards&gt;
  &lt;/global-forwards&gt;

  &lt;!-- ======================= Action Definitions ===================== --&gt;
  &lt;action-mappings&gt;
    &lt;action  path="/Login"
             type="com.agilquest.onboard.presentation.actions.LoginAction"&gt;
      &lt;description&gt;Authenticates and authorizes a user.&lt;/description&gt;
    &lt;/action&gt;
  &lt;/action-mappings&gt;
  
&lt;/struts-config&gt;</PRE></TD></TR></TBODY></TABLE><BR><BR>为了使你的用户界面流程图更加复杂，我们推荐在使用StrutsGUI 时增加一个步骤。在你的StrutsGUI Visio 文档内，你可以轻易的将每个JSP (JavaServer Pages)页链接到它在应用中的实际屏幕快照。创建这个界面不但确实有助于应用程序的文档化，更重要的是，它成为了培训新的从事用户界面设计的开发者的一件极好的工具。 <BR><BR>另一个帮助管理Struts应用的工具就是由James Holmes 发明的Struts Console。本质上，这个工具提供了一组设备，这些设备使你能够得到与StrutsGUI 相同的终点，但是它们在途径和长度上有区别。这两个工具都执行良好，其中任何一个都可以增强基于Struts的企业应用的可维护性。 <BR><BR><A name=3><B>三、现在，我将表格放在哪里？</B></A> <BR><BR>ActionForm 会话期管理有点棘手。ActionForm的周期怎样？它在请求周期内或者会话期周期内吗？为了得到它所代表的功能周期，方案之一就是将ActionForm置于会话期之内。在这种情况下，你通常怎样维护这些ActionForm 对象呢？谁知道不再需要他们时删除他们要承担什么责任呢？典型的情况是：用户通过菜单从一个功能转为使用另一个功能。在这种情况下，原来的ActionForm 对象就应该从会话期删除，并且创建新的ActionForm 对象。这时还应该出现一个集中的Action类，MenuAction，它只处理菜单切换。这个Action 类从会话期删除多余的ActionForm 对象。然后将用户前进到创建新ActionForm 对象所在的新页面。 <BR><BR>在这种情况下，站在用户的立场上或者基于用户权限，我们应该如何显示不同的菜单项呢？这个菜单也应该国际化，并且它修改时应该以用户权限为基础；也就是说，如果许可修改了，菜单也要相应的修改。有一种方法可以持续用户的权限。当用户注册时， MenuFactory根据这些权限创建菜单，为了增加安全性， MenuAction类在允许用户进行到他所选择的功能之前需要认证用户。命名struts-config.xml 中的ActionForm 对象的首要规则是对象名以Form 结束，从而简化了会话期内这些表格的维护。例如： ReservationForm, SearchUserForm, BankAccountForm, UserProfileForm,等等。 <BR><BR>下列代码描述了一个具有Action 映射的普通菜单切换动作，它进一步阐明了ActionForm(s)管理： <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>public class MenuAction {

  public ActionForward perform(ActionMapping       _mapping,
                               ActionForm          _form,
                               HttpServletRequest  _request,
                               HttpServletResponse _response)
                                  throws IOException, ServletException {

    // Check end-user permissions whether allowed into the requested     
    // functionality 
    checkIfUserAllowedToProceed(_mapping, _form, _request, _response); 

    // Clean up the session object (this logic is in its own method)
    String formName = null; 

    HttpSession session = _request.getSession();
    Enumeration e = session.getAttributeNames();  

    while(e.hasMoreElements()) {
     
      formName = (String)e.nextElement();

      if (formName.endsWith("Form")){
        session.removeAttribute(formName);
      }    
    }

    // Now find out which functionality the end-user wants to go to
    String forwardStr = _request.getParameter("nextFunctionality");

    if (forwardStr != null &amp;&amp; forwardStr.trim().length() &gt; 0){
      return _mapping.findForward(forwardStr);
    }
    else {
      return _mapping.findForward("index");
    }
  }  
}</PRE></TD></TR></TBODY></TABLE><BR><BR>下列Action映射就是一个阐述如何以菜单选择为基础实现动作的例子： <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>&lt;!-- A generic menu action that forwards the user from one 
     functionality to another functionality (after checking permissions)
--&gt;
&lt;action path="/menuAction"
        type="x.y.z.MenuAction"
        input="/menu.jsp"&gt;      
  &lt;forward name="create_reservation" path="/actionResv.do"/&gt; 
  &lt;forward name="index"              path="/menu.jsp"/&gt; 
  &lt;forward name="add_person"         path="/actionPerson.do"/&gt; 
  &lt;forward name="logout"             path="/actionLogout.do"/&gt; 
&lt;/action&gt;</PRE></TD></TR></TBODY></TABLE><BR><BR>例子和映射都是可以自我解释的。 <BR><BR><A name=4><B>四、再说一次，我们是怎样关联的？</B></A> <BR><BR>任何JSP页的许多输入点与许多现有点之间都有一个关系，这取决于页面本身的复杂程度。认识到这些关系对于理解和维护用户界面是至关重要的。我们已经将JSP页和Action 类之间的关系定义为： <BR>·1:1 关系 <BR>·1:N 关系 <BR>·N:N关系 <BR><BR><B>1:1 关系</B> 在1:1 关系中，用户通过Action类从一个JSP页切换到另一个页面；这就使得JSP页和Action 之间容易形成一个紧密的耦合。唯一的额外开销就是struts-config.xml 中有一个Action映射。这个在struts-config.xml 中只有一个Action 映射的简单Action 可用于从一个页面切换到另一个页面。直接通过一个JSP页访问另一个JSP页是不太现实的；他不能够检查转向目标JSP页的用户权限（如果可行的话）。他还导致了维护方面的问题。为了避免这些问题，可以总是通过Action 类从一个JSP页转向另一个JSP页： <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>&lt;!-- A generic action that forwards request from one JSP page to another JSP page --&gt;
&lt;action path="/forwardAction"
        type="x.y.z.One2OneAction"
        input="/test1.jsp"&gt;      
  &lt;forward name="continue"  path="/test2.jsp"/&gt; 
&lt;/action&gt;</PRE></TD></TR></TBODY></TABLE><BR><BR><B>1:N关系</B> 稍微复杂一点的关系就是JSP页有多个现有点但是只有一个输入点，也叫做1:N关系。在这种情况下，总是使用一个单一 Action类分支到不同的目标。这就保证了Action 在将用户推进到目标之前能够检查不同的情况或者权限。唯一的额外开销就是在struts-config.xml 中有一个Action 映射。这也推动了JSP页与Action 映射之间的1:1 映射。下面的Action映射标出了一个映射，它有一个单一输入点和多个前推，多个前推代表着多个现有点： <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>&lt;!-- A generic action that forwards request from one JSP page to different 
     branches depending on the selected hyperlink, by the end-user
--&gt;
&lt;action path="/branchAction"
         type="x.y.z.One2NAction"
         input="/test1.jsp"&gt;      
  &lt;forward name="target1"   path="/test2.jps"/&gt; 
  &lt;forward name="target2"   path="/test3.jsp"/&gt; 
  &lt;forward name="target3"   path="/someAction.do"/&gt; 
&lt;/action&gt;</PRE></TD></TR></TBODY></TABLE><BR><BR><B>N:N 关系</B> 最复杂的关系，即N:N关系，指的是JSP页或者Action 类有多个输入点和多个现有点。N:N 关系是频繁出现在企业应用程序中的一个有趣和复杂的部分。N:N关系最初应用在不同的JSP页访问一个公共JSP页或者一个公共Action类的情况下。假设用户进入的JSP页是一个网络中心（特别是这个JSP页由不同的JSP页都可到达），但是用户又想返回或者取消这个流程；那么开发者就处于进退两难的局面：不知道怎样将用户送往正确的页面。 <BR><BR>另一个场景是：Action类接合到数据库（通过不同的功能函数或者JSP页），并且出现错误。以用户原来所在的位置为基础，将用户发送回原来所在的位置或者适当前推，这需要仔细推敲。struts-config.xml映射证明是没有帮助的，因为输入域是一个确定的JSP页或者 Action 类。我们创建的结构应该足够灵活，这样开发者不必在struts-config.xml 折腾就能够轻而易举的修改流程逻辑。这就是N:N关系所要解决的问题。通过实现一个能够灵活发送用户到目标所在地或者目的文件的界面，这个值修改起来就比较容易。下面的Action映射给出的映射有多个输入点和多个前推，这些前推代表多个现有点： <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>public class N2NAction {

  public ActionForward perform(ActionMapping      _mapping,
                               ActionForm         _form,
                               HttpServletRequest _request,
                               HttpServletResponse _response)
                                  throws IOException, ServletException {

    N2NInterface if = (N2NInterface)_form;

    //Execute some business functionality here
    try{
      //Business logic successful?
               
    }
    catch(Exception e){

      //Indicates failure
      return _mapping.findForward(if.getSource()); 
    }

    //Indicates success
    return _mapping.findForward(if.getDestination());            

  } 

}

&lt;!-- A generic action that forwards request from one JSP page to another JSP page --&gt;
&lt;action  path="/sourceAndDestinationAction"
         type="x.y.z.N2NAction"
         input="/test1.JSP"&gt;      
  &lt;forward name="source1"          path="/source1.JSP"/&gt; 
  &lt;forward name="source2"          path="/source2.JSP"/&gt; 
  &lt;forward name="source3"          path="/someAction.do"/&gt; 
  &lt;forward name="destination1"     path="/destination1.JSP"/&gt; 
  &lt;forward name="destination2"     path="/destination1.JSP"/&gt; 
  &lt;forward name="destination3"     path="/destination2.JSP"/&gt;
&lt;/action&gt;

   A hyerplink can be something like
   &lt;a href="sourceAndDestinationAction.do?
    source=source1&amp;destination=destination1"&gt;click me&lt;/a&gt;
   &lt;a href="sourceAndDestinationAction.do?
    source=source2&amp;destination=destination2"&gt;click me too&lt;/a&gt;</PRE></TD></TR></TBODY></TABLE>
<P><BR><BR>所有的ActionForms 默认地都必须所有这三种关系（通常通过界面）。使用普通的Action 类，你可以自由地在用户界面流程中移动. </P>. 
<P></P>
<P></P>
<P><SPAN class=myp111><FONT id=zoom><B>目录： <BR><A href="http://tech.ccidnet.com/pub/article/c322_a89817_p1.html#1">五、Back之痛!</A> <BR><A href="http://tech.ccidnet.com/pub/article/c322_a89817_p1.html#2">六、你是谁，在这做什么？</A> <BR><A href="http://tech.ccidnet.com/pub/article/c322_a89817_p1.html#3">七、我们去往何处？</A> <BR><A href="http://tech.ccidnet.com/pub/article/c322_a89817_p1.html#4">八、犯错乃人之常情...我们不是圣贤</A> <BR><A href="http://tech.ccidnet.com/pub/article/c322_a89817_p1.html#5">九、测试，就是用户想要的！</A> <BR><A href="http://tech.ccidnet.com/pub/article/c322_a89817_p1.html#6">十、简化Struts 开发</A></B> <BR><BR><A name=1><B>五、Back之痛!</B></A> <BR><BR>设计演示层，有一个好方法就是按照功能设计。例如：在一个预订系统中预订的时候，将所有的相关动作类封装到一个包装内如 <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>com.companyname.productname.presentation.
   reservation.mak</PRE></TD></TR></TBODY></TABLE><BR><BR>就是一个不错的方法。深度封装也可以应用到ActionForm类中。表格应该处在功能周期的会话期内。这就保证了该完整功能所需的数据放在表格对象本身之内。这样用户就能够前进到功能的任何页面并且找到该页上显示的正确数据。接着用户还能够在最终保存该数据之前更新数值。因此，就会产生一个有趣的两难局面：当用户确认数据、按下浏览器中的Back 按钮、修改并再次提交的话会发生什么事情？例如，在创建了数据库中的预定后，用户返回并试图再次提交同样的数据。演示层必须在应用层有机会抱怨之前先捕捉到这个错误。处理这种情况的方法之一就是在提交之前创建一个令牌，提交之后检查令牌的有效性，并立即修改令牌值——这样用户就不能够再次使用Back 按钮来提交同样的值。 <BR><BR>这个方法的弊病之一就是需要管理令牌：例如，如果用户试图保存数据失败了，但是令牌值却已经修改了。如果这样的话，用户就不能够修改数据，和在不重新设置令牌的情况下重新提交。相应的Action 类也不会允许提交。那么到底什么时候才应该重置令牌呢？用户可以遍历六个页面，那么在确认它的修改时就会收到错误，然后定向到六个页面中的任何一个页面。 <BR><BR>要管理这个问题，就需要在用户请求一个特别功能时创建一个表格并在会话期内存储一个默认的令牌值。在保存之前，用户可以多次使用Back按钮进行修改。一旦用户提交了这些修改，只有在保存成功之后才能重新设置令牌。如果确认失败，用户可以使用Back 按钮或者前进到产生失败的页面，修改数据然后重新提交数据。一旦确认成功的话，令牌值就会修改。ActionForm 对象本身也可以包含令牌值（令牌值可以通过程序设置）。还有一个方法就是，在第一次提交之后，Submit 按钮就变得无效、不允许用户再次提交直到有事情发生。我们建议每个ActionForm 处理他自己的令牌，应用至多是使用不止一个不同的ActionForm对象来处理一个特殊功能。 <BR><BR>要了解另外一个复制表格提交的方法，请参考Romain Guay的 <A href="http://www.javaworld.com/javaworld/javatips/jw-javatip136.html">"Java Tip 136: Protect Web Application Control Flow" </A>(JavaWorld, March 2003). <BR><BR><A name=2><B>六、你是谁，在这做什么？</B></A> <BR><BR>企业应用必须设计成能够同时支持多个认证模式。这对于来自ISVs（独立的软件开发商）的软件更为重要。例如，假设一个应用的认证要求是单一登录、询问用户密码、条形码认证或者指纹认证，甚至是将来有可能出现的声音认证。JAAS (Java 认证和授权服务)，这个可插入的认证机制，证明可用于这个方面。默认的， Struts 1.1 支持JAAS。JAAS也可用在具有极好结果的Struts 1.0中。对于认证，一个很好的继承性设计将会推动使用不同的认证动作类，每个动作类都有他自己唯一的Action 映射。这种设计方法将会推动对不同认证的同时支持。如果需要添加新的认证机制，只要用一个支持该认证的Action类在struts-config.xml内创建一个新的动作映射即可。 <BR><BR><A name=3><B>七、我们去往何处？</B></A> <BR><BR>流程控制器的设计目的是限制和引导用户通过应用程序，它在保证用户遵循特殊流程方面很实用。让流程控制器以系统的地位为基础证明是有用的。无论用户什么时候试图访问系统中的功能，流程控制器都可以确保用户有权进入到特殊流程中。而且，就算出现了意外情况，用户也能够被引导到恰当的页面。放置流程控制器最好的地方是在超类中。只有在流程控制器满意之后用户才允许执行特定动作。 <BR><BR>图 2 给出了一个简单的继承性模型，它可用来使用合并到用户认证中的流程控制器。 <BR><BR>
<CENTER><IMG height=298 src="http://tech.ccidnet.com/pub/attachment/2004/2/272051.jpg" width=525> <BR><BR>Figure 2. Simple authentication class model</CENTER>
<P><BR><BR><A name=4><B>八、犯错乃人之常情...我们不是圣贤</B></A> <BR><BR>Struts框架通过ActionError和ActionErrors类为我们提供了异常处理结构。 ActionError就是——存在于Action 或者ActionForm类中的错误，或者应用层给出的错误。ActionError 类典型地可通过使用简单的钥匙构造，或者通过使用钥匙/值对来构造。如果你的应用有国际化关系，那么该钥匙可用于查找国际化信息资源数据库。如果这些国际化关系不存在的话，那么取代值可用于显示错误信息。至多有四个占位符设置在对象排列中，每个占位符都包含整个错误信息的一个单独部分。这些值可构造得与MessageFormatter 类相似。 <BR><BR>ActionErrors类，扩展了ActionMessage 类，它是具有单一公共方法的ActionError 类的集合，这个单一公共方法是add(java.lang.String property, ActionError error)。这个方法签名中的第二个参数是直接的：他指的是已经存在的真实错误(ActionError)。通过将错误信息与指定的域关联起来，属性参数可用于域级别的校验。既然错误信息与指定域关联，你可以轻易地将信息定位于有疑问的域附近或者定位于它能产生最大意义的任何地方。例如，如果你在用户的逻辑标记符之上进行域级别的校验，并且在类LoginAction 中出现错误，你可以使用下列代码片断： <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>ActionErrors errors = new ActionErrors();
errors.add("logiinID", new ActionError("loginID.invalid"));
saveErrors(_request, errors);
return (new ActionForward(_mapping.getInput()));</PRE></TD></TR></TBODY></TABLE><BR><BR>字符串"loginID.invalid"就是用于信息资源数据库中国际化字符串值的钥匙。为了显示错误信息，在你的login.jsp中，使用下列HTML： <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>&lt;font color="red"&gt;&lt;html:errors property="loginID"/&gt;&lt;/font&gt;</PRE></TD></TR></TBODY></TABLE><BR><BR>有了对用于异常和异常链的Struts 框架设备的这个特别理解，要管理整个企业应用结构中的错误需要一个更加通用的方法。企业应用异常框架中最重要的宗旨有： <BR>·开发异常类体系 <BR>·从系统异常中退耦用户异常 <BR>·给出异常的内容、类型和严重级别 <BR>·退耦异常处理和应用日志 <BR>·创建用于异常链的工具 <BR>·具体化用于国际化用途的异常字符串 <BR><BR>许多文章和关于这个问题的完整书籍，都讨论了使用Java的异常处理。Brian Goetz，在他的JavaWorld 系列 "Exceptional Practices" 中提供了关于这个主题的非常好的建议。 <BR><BR><A name=5><B>九、测试，就是用户想要的！</B></A> <BR><BR>尽管许多开发者都把测试看作是软件开发的最不吸引人的部分，测试企业应用对于它的整体成功还是很关键的。许多灵活的方法，如极限程序设计(XP)，将测试放在企业应用开发的最前部。这种强调实际上是相当爽的。为了简洁起便，我们只讨论用于Struts 类的单元和集成测试策略。 <BR><BR>两个原始策略可用于服务器端的测试：模拟对象(MO)测试和容器内(IC)测试。模拟对象测试从本质上扩展了"多树桩的"行为，并且它是自我说明的。从本质上说，开发者负责模拟定义接口的类，这些接口归进行测试的类使用。使用这个方法，开发者可以模拟容器。模拟对象测试也被叫做endotesting ，因为设置测试的动作是在受限环境中的类的内部进行的。 <BR><BR>容器内测试这个策略应用于下列情况：在产品环境中将要使用的实际容器也用于整个单元测试过程中。这些测试案例必须至少合并到使用Ant的每夜建立过程中。单元测试Java类的有效方法之一就是使用JUnit。他是用来测试普通JavaBeans 的一件极好的工具。另外一个重要的开源工具就是Cactus。Cactus，JUnit框架的扩展，可以在单元级别上测试服务器端的代码。Cactus 支持用于服务器端测试的容器内方法。这两个测试工具都是很有用的，它是任何追求品质的企业应用开发团队的基石。 <BR><BR>对于测试Struts来说，普遍接受的策略就是通过应用层测试演示层。你选择模拟对象测试方法还是容器内测试方法，主要取决于你们团队的需要和安慰级别。要自动执行Struts 测试，需要创建一个名为StrutsTestCase 的、对于JUnit测试方法的扩展，它对MO 和 IC都支持。使用StrutsTestCase 测试Action 和ActionForm 类，是整个测试策略的一部分，它应该包括这里讨论的回归测试工具。其他工具如Apache JMeter 提供了应力/负载测试。 <BR><BR><A name=6><B>十、简化Struts 开发</B></A> <BR><BR>总的来说，我们讨论了你应该如何简化struts-config.xml文件的设计和维护，定义了错误处理和测试策略，简化了常见问题如处理Web浏览器的Back按钮，基于会话期的表格管理以及用户认证。最后，我们还清楚的文档化了用户界面控制流程的管理。我们的经历告诉我们：开发高品质的企业应用是困难的。当你使用Struts框架创建企业应用时，融合我们的建议到你的开发计划中，你就能够使你的设计、开发和维护费用减至最低。 <BR><BR><B>关于作者</B> Michael Coen 是AgilQuest Corporation的软件结构师。在AgilQuest时， Mike成为了OnBoard的基于J2EE的企业软件应用程序开发团队中的一员。Mike 从事专业软件开发已有11年多。 <BR><BR>Amarnath Nanduri 是AgilQuest Corporation的资深软件开发工程师。 Amar在过去六年内一直从事企业软件应用程序的设计和开发，特别是在用户界面设计和开发方面。Amar 使用Struts框架进行开发已有两年。</P></FONT></SPAN><img src ="http://www.blogjava.net/qq13367612/aggbug/16656.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qq13367612/" target="_blank">Sung</a> 2005-10-24 22:13 <a href="http://www.blogjava.net/qq13367612/articles/16656.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Struts成功之路:Dynaforms </title><link>http://www.blogjava.net/qq13367612/articles/16655.html</link><dc:creator>Sung</dc:creator><author>Sung</author><pubDate>Mon, 24 Oct 2005 14:12:00 GMT</pubDate><guid>http://www.blogjava.net/qq13367612/articles/16655.html</guid><wfw:comment>http://www.blogjava.net/qq13367612/comments/16655.html</wfw:comment><comments>http://www.blogjava.net/qq13367612/articles/16655.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qq13367612/comments/commentRss/16655.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qq13367612/services/trackbacks/16655.html</trackback:ping><description><![CDATA[<SPAN class=myp111><FONT id=zoom>只要你使用了Struts一段时间，你就会开始注意到你花了很多时间来创建ActionForm 类。尽管这些类对于Struts的MVC结构很重要（因为他们实现了视图部分），但他们通常只是bean属性和 validate 方法（有时也称为reset 方法）的汇集。有了Struts 1.1版本，开发者就有了一组新的选项来创建他们的视图对象，在DynaBeans的基础上创建。DynaBeans是动态配置的Java Beans，这就意味着：他们可从外部配置（通常为XML）的某些种类中获取他们的属性，而不是通过在类中明确定义的方法处获得。 <BR><BR>为了说明DynaBeans (和Struts实现，Dynaforms)的工作原理，我们首先讨论一个简单的 Struts Form ，它主要记录姓名、地址、和电话号码。下面就是如何使用ActionForm 来实现它的过程。 <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>article1.CustomerForm
package article1;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionError;
import javax.servlet.http.HttpServletRequest;

public class CustomerForm extends ActionForm {

    protected boolean nullOrBlank (String str) {
        return ((str == null) || (str.length() == 0));
    }
    public  ActionErrors validate(ActionMapping mapping,
            HttpServletRequest request) {
        ActionErrors errors = new ActionErrors();
        if (nullOrBlank(lastName)) {
            errors.add("lastName",
                   new ActionError("article1.lastName.missing"));
        }
        if (nullOrBlank(firstName)) {
            errors.add("firstName",
                   new ActionError("article1.firstName.missing"));
        }
        if (nullOrBlank(street)) {
            errors.add("street",
                   new ActionError("article1.street.missing"));
        }
        if (nullOrBlank(city)) {
            errors.add("city",
                   new ActionError("article1.city.missing"));
        }
        if (nullOrBlank(state)) {
            errors.add("state",
                   new ActionError("article1.state.missing"));
        }
        if (nullOrBlank(postalCode)) {
            errors.add("postalCode",
                   new ActionError("article1.postalCode.missing"));
        }
        if (nullOrBlank(phone)) {
            errors.add("phone",
                   new ActionError("article1.phone.missing"));
        }
        return errors;
    }

    private String lastName;
    private String firstName;
    private String street;
    private String city;
    private String state;
    private String postalCode;
    private String phone;

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getStreet() {
        return street;
    }

    public void setStreet(String street) {
        this.street = street;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }

    public String getPostalCode() {
        return postalCode;
    }

    public void setPostalCode(String postalCode) {
        this.postalCode = postalCode;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }
}</PRE></TD></TR></TBODY></TABLE><BR><BR>如你所见，这是一个带有有效方法的标准JavaBean，它保证所有的域都正确设置。 <BR><BR>与这个bean接口的JSP 页也同样简单： <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>customer.jsp
&lt;%@ taglib uri="/WEB-INF/c.tld" prefix="c" %&gt;
&lt;%@ taglib prefix="fmt" uri="/WEB-INF/fmt.tld" %&gt;
&lt;%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %&gt;
&lt;%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %&gt;

&lt;head&gt;
&lt;title&gt;Example of a standard Customer form&lt;/title&gt;
&lt;/head&gt;
&lt;h1&gt;Example of a standard Customer form&lt;/h1&gt;
&lt;html:form action="/addCustomer"&gt;
Last Name: &lt;html:text property="lastName"/&gt;
&lt;html:errors property="lastName" /&gt;&lt;br&gt;
First Name: &lt;html:text property="firstName"/&gt;
&lt;html:errors property="firstName" /&gt;&lt;br&gt;
Street Addr: &lt;html:text property="street"/&gt;
&lt;html:errors property="street" /&gt;&lt;br&gt;
City: &lt;html:text property="city"/&gt;
&lt;html:errors property="city" /&gt;&lt;br&gt;
State: &lt;html:text property="state" maxlength="2" size="2" /&gt;
&lt;html:errors property="state" /&gt;&lt;br&gt;
Postal Code: &lt;html:text property="postalCode" maxlength="5"
                                              size="5" /&gt;
&lt;html:errors property="postalCode" /&gt;&lt;br&gt;
Telephone: &lt;html:text property="phone" maxlength="11" size="11" /&gt;
&lt;html:errors property="phone" /&gt;&lt;br&gt;
&lt;html:submit/&gt;
&lt;/html:form&gt;</PRE></TD></TR></TBODY></TABLE><BR><BR>用于该页的Action只发送值到标准输出（它会将值放在 Catalina 日志文件内)： <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>article1.AddCustomerAction
package article1;

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionForm;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletException;
import java.io.IOException;

public class AddCustomerAction extends Action {
    public ActionForward execute(ActionMapping mapping,
                                 ActionForm form,
                                 HttpServletRequest request,
                                 HttpServletResponse response)
    throws ServletException, IOException{
        CustomerForm custForm = (CustomerForm) form;
        System.out.println("lastName   = "
                            + custForm.getLastName());
        System.out.println("firstName  = "
                            + custForm.getFirstName());
        System.out.println("street     = " + custForm.getStreet());
        System.out.println("city       = " + custForm.getCity());
        System.out.println("state      = " + custForm.getState());
        System.out.println("postalCode = "
                            + custForm.getPostalCode());
        System.out.println("phone      = " + custForm.getPhone());

        return mapping.findForward("success");
    }
}</PRE></TD></TR></TBODY></TABLE>
<P><BR><BR>原文地址：<A href="http://www.developer.com/java/ejb/article.php/2214681">http://www.developer.com/java/ejb/article.php/2214681</A> </P></FONT></SPAN>
<P></P>
<P>这就是一起绑定的所有东西，他们总是与Struts一起，放在struts-config.xml 文件内: <BR><BR><BR><BR><BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>&lt;struts-config&gt;
&lt;form-beans&gt;
&lt;form-bean name="customerForm" type="jdj.article1.Customer" /&gt;
      &lt;/form-beans&gt;
&lt;action-mappings&gt;
&lt;action path="/addCustomer" type="article1.AddCustomerAction"
                            name="customerForm" scope="request"
                            input="/addCustomer.jsp"&gt;
&lt;forward name="success" path="/addCustomerSucceeded.jsp"
                        redirect="false" /&gt;
&lt;/action&gt;
&lt;/action-mappings&gt;
&lt;message-resources parameter="ApplicationResources" /&gt;
&lt;plug-in className="org.apache.struts.validator.ValidatorPlugIn"&gt;
&lt;set-property value="/WEB-INF/validator-rules.xml"
              property="pathnames" /&gt;
struts-config.xml&lt;/plug-in&gt;&lt;/struts-config&gt;
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;!DOCTYPE struts-config PUBLIC 
  "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
  "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd"&gt;
&lt;struts-config&gt;
 &lt;form-beans&gt;
  &lt;form-bean name="customerForm" type="article1.CustomerForm" /&gt;
 &lt;/form-beans&gt;
 &lt;action-mappings&gt;
  &lt;action path="/addCustomer" type="article1.AddCustomerAction"
          name="customerForm" scope="request" input="/customer.jsp"&gt;
      &lt;forward name="success" path="/addCustomerSucceeded.jsp"
               redirect="false" /&gt;
  &lt;/action&gt;
 &lt;/action-mappings&gt;
 &lt;message-resources parameter="ApplicationResources" /&gt;
 &lt;plug-in className="org.apache.struts.validator.ValidatorPlugIn"&gt;
   &lt;set-property value="/WEB-INF/validator-rules.xml"
        property="pathnames" /&gt;
 &lt;/plug-in&gt;
&lt;/struts-config&gt;</PRE></TD></TR></TBODY></TABLE><BR><BR>customerForm链接到刚刚定义的CustomerForm 类上， /addCustomer动作也是定义用来使用该表格和使用article1.AddCustomerAction类来处理请求。 <BR><BR>当你将表格放在了你的浏览器上，你需要填写下列空白表格: <BR><BR><IMG height=410 src="http://tech.ccidnet.com/pub/attachment/2004/2/271077.jpg" width=576> <BR><BR>如果你提交了无任何实际内容的表格，就会出现下列内容： <BR><BR><IMG height=439 src="http://tech.ccidnet.com/pub/attachment/2004/2/271078.jpg" width=575> <BR><BR>当你认真填写了表格并提交后，在你的Web容器日志文件内（在Tomcat 下为catalina.out ）就会出现下列内容： <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>lastName = Bush
firstName = George
street = 1600 Pennsylvania Avenue NW
city = Washington
state = DC
postalCode = 20500
phone = 2024561414</PRE></TD></TR></TBODY></TABLE><BR><BR>至此，这都是人人熟知的Struts。但是，通过使用Struts 1.1的某些新特征，你可以彻底的删除原本需要编写的大量代码。例如: 我们使用Dynaform扩展，就不需要ActionForm类。如果这样的话，我们需要修改struts-config.xml 中的customerForm 的定义，以便使用org.apache.struts.action.DynaActionForm类(为了这篇指南，我们实际上将创建一个新的类和JSP页，这样你就能够比较他们两个) <BR><BR>通过使用DynaActionForm，你获得到form-property XML标记的访问，这个标记允许你直接定义struts-config.xml内表格的属性。它看起来如下： <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>&lt;form-bean name="dynaCustomerForm"
           type="org.apache.struts.action.DynaActionForm"&gt;
  &lt;form-property name="lastName" type="java.lang.String"/&gt;
  &lt;form-property name="firstName" type="java.lang.String"/&gt;
  &lt;form-property type="java.lang.String" name="street"/&gt;
  &lt;form-property name="city" type="java.lang.String"/&gt;
  &lt;form-property name="state" type="java.lang.String"/&gt;
  &lt;form-property name="postalCode" type="java.lang.String"/&gt;
&lt;/form-bean&gt;</PRE></TD></TR></TBODY></TABLE><BR><BR>这就不需要对JSP页做任何修改；DynaForms的使用对Struts HTML标记库是透明的。你确实需要对Action稍微修改一下，但是，因为你不能够再将传递到execute()方法内的表格直接传递给拥有存取器（用于你的数据的GET和SET方法）的类中。相反，你需要将表格传递给DynaActionForm，并且需要使用普通的get(fieldname)存取器。所以Action的新版本看起来如下： <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>article1.AddDynaCustomerAction
package article1;

import org.apache.struts.action.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletException;
import java.io.IOException;

public class AddDynaCustomerAction extends Action {
  public ActionForward execute(ActionMapping mapping,
                               ActionForm form,
                               HttpServletRequest request,
                               HttpServletResponse response)
                       throws ServletException, IOException{
  DynaActionForm custForm = (DynaActionForm) form;
  System.out.println("lastName   = " + custForm.get("lastName"));
  System.out.println("firstName  = " + custForm.get("firstName"));
  System.out.println("street     = " + custForm.get("street"));
  System.out.println("city       = " + custForm.get("city"));
  System.out.println("state      = " + custForm.get("state"));
  System.out.println("postalCode = "
                      + custForm.get("postalCode"));
  System.out.println("phone      = " + custForm.get("phone"));

      return mapping.findForward("success");
     }
}</PRE></TD></TR></TBODY></TABLE><BR><BR>如你所见，它完全删除了整个类(ActionForm)。但是，我们丧失了其他的功能:校验表格数据的能力。有两个方法可以重新获得这个功能。一个方法就是创建一个类，它产生子类DynaActionForm并且实现validate()方法。在我们的范例中，它看起来如下： <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>article1.DynaCustomerForm
package article1;

import org.apache.struts.action.*;

import javax.servlet.http.HttpServletRequest;

public class DynaCustomerForm extends DynaActionForm {

protected boolean nullOrBlank (String str) {
  return ((str == null) || (str.length() == 0));
 }

public ActionErrors validate(ActionMapping mapping,
                    HttpServletRequest request) {
  ActionErrors errors = new ActionErrors();
  if (nullOrBlank((String)this.get("lastName"))) {
    errors.add("lastName",
           new ActionError("article1.lastName.missing"));
  }
  if (nullOrBlank((String)this.get("firstName"))) {
    errors.add("firstName",
           new ActionError("article1.firstName.missing"));
  }
  if (nullOrBlank((String)this.get("street"))) {
    errors.add("street",
           new ActionError("article1.street.missing"));
  }
  if (nullOrBlank((String)this.get("city"))) {
    errors.add("city", new ActionError("article1.city.missing"));
  }
  if (nullOrBlank((String)this.get("state"))) {
    errors.add("state",
           new ActionError("article1.state.missing"));
  }
  if (nullOrBlank((String)this.get("postalCode"))) {
    errors.add("postalCode",
           new ActionError("article1.postalCode.missing"));
  }
  if (nullOrBlank((String)this.get("phone"))) {
    errors.add("phone", new ActionError("article1.phone.missing"));
  }
  return errors;
 }

}</PRE></TD></TR></TBODY></TABLE><BR><BR>请再次注意：我们需要使用get()存取器，而不是直接访问实际变量。我们也需要修改struts-config.xml 中表格的定义，以便用这个新类来取代一般的DynaActionForm 类。如果这样的话，就会重新获得校验功能。但是，我们得重新为每个表格定义明确的类。在Struts 1.1下进行校验，我推荐的方法是使用Struts Validator 框架，它将在后续文章中进行说明。 <BR><BR>在本系列的下一篇文章中，我们将看到DynaForms 的更高级的用途。特别是，我们将教你如何使用编入索引的属性和beans排列来实现复杂的细节繁琐的表格。 <BR></P><img src ="http://www.blogjava.net/qq13367612/aggbug/16655.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qq13367612/" target="_blank">Sung</a> 2005-10-24 22:12 <a href="http://www.blogjava.net/qq13367612/articles/16655.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Struts模块化编程教程 </title><link>http://www.blogjava.net/qq13367612/articles/16653.html</link><dc:creator>Sung</dc:creator><author>Sung</author><pubDate>Mon, 24 Oct 2005 14:11:00 GMT</pubDate><guid>http://www.blogjava.net/qq13367612/articles/16653.html</guid><wfw:comment>http://www.blogjava.net/qq13367612/comments/16653.html</wfw:comment><comments>http://www.blogjava.net/qq13367612/articles/16653.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qq13367612/comments/commentRss/16653.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qq13367612/services/trackbacks/16653.html</trackback:ping><description><![CDATA[<SPAN class=myp111><FONT id=zoom><B>1、前言</B> <BR><BR>STRUTS是标准的"模型2"的WEB应用框架，其中的ActionServlet代表了"模型2"MVC设计模式中的"控制器" 。STRUTS应用程序一般使用JSP代码生成用户界面，这些代码不包括任何商业逻辑，代表了MVC中的”VIEW”部分。需要执行商业逻辑的用户界面中的表单或超链将会由"控制器" ActionServlet接收和处理。在STRUTS中，只有一个ActionServlet实例，这个实例将接收和处理应用中的相关用户交互请求。ActionServlet实例将选择和调用相应的ACTION类来处理商业逻辑。在设计模式上，ACTION类被称为“控制辅助者”，它将修改JavaBeans，这些JavaBeans就是MVC中的” model”部分。本文将分析在STRUTS中进行模块化编程的具体细节。 <BR><BR><B>2、样例描述</B> <BR><BR>我们将作一个模块编程的例子，这个例子包括三个模块，缺省模块、registration模块和approval模块。缺省模块下有资源index.html，我们使用它来连接其它两个模块。registration模块和approval模块的编程类似，都包含一个index.jsp和一个结果jsp：result.jsp。下面是目录结构： <BR><BR>
<CENTER><IMG height=424 src="http://tech.ccidnet.com/pub/attachment/2004/1/269764.jpg" width=533></CENTER><BR><BR>目录结构表明，struts的模块由配置文件、java类(这里者action和form类)和资源文件构成，另外各模块可以共享web.xml，message （这里是applicatonResources.properties）文件。 <BR><BR>我们的例子的界面交互图可以表示如下： <BR><BR>
<CENTER><IMG height=352 src="http://tech.ccidnet.com/pub/attachment/2004/1/269765.jpg" width=539></CENTER>
<P><BR><BR>缺省模块的index.html包括两个链接，分别连接两个模块的index.jsp资源，registration模块的index.jsp提交后，如果验证失败会重新返回到该模块的index.jsp，否则用资源resultok.jsp显示注册成功的结果。模块approval的index.jsp提交后进入到resultok.jsp的界面，显示批准与否的结果。 <BR><BR>我们从应用程序的文件组成和交互两方面的模块情况对我们要实现的例子进行了比较清晰的组织，下面我们讲解如何在struts中实现模块化编程。 </P></FONT></SPAN>
<P></P>
<P><B>3、STRUTS的模块化机制</B> <BR><BR>我们将讲解STRUTS的相关配置，这些配置大部分与模块化编程有关系，有些没关系但对理解STRUTS程序有利。 <BR><BR>3.1 ActionServlet参数 <BR><BR>ActionServlet有好多参数可供设置，STRUTS在WEB应用部署描述符中定义这些参数： <BR><BR>·Config——逗号相隔的应用上下文相对的配置文件的路径，这些配置文件包含了STRUTS WEB应用的缺省模块的设置。缺省值为 /WEB-INF/struts-config.xml； <BR>·config/${module} -逗号相隔的应用上下文相对的配置文件的路径，这些配置文件包含了STRUTS WEB应用的${module}模块的设置。这个模块的前缀是/${module}，多个config/${module}参数定义了多个STRUTS WEB应用模块； <BR>·convertNull - 如果这个参数的值为 true, 数值型Java 包装类（比如java.lang.Integer）的初始值将会是null，而不是0。缺省值[false] <BR>·rulesets-逗号相隔的附加的org.apache.commons.digester.RuleSet列表，Digester在分析配置文件时，除了针对标准的配置元素的RuleSet之外，还会利用这些对象来分析配置文件，这样提供了一个配置扩展机制。 <BR>·validatin - 指示我们是否使用验证型的XML分析器来处理配置文件，缺省值为 [true] <BR><BR>3.2 配置文件 <BR><BR>我们说STRUTS针对每个模块可以有一个或多个配置文件，这些配置文件使用XML来书写，下面是标准的配置文件XML的元素解释。 <BR><BR>3.2.1 元素 action <BR><BR>这个元素描述了一个ActionMapping 对象，这个对象将用来处理用户针对某个模块相对应的URI 的请求。 <BR><BR><IMG height=558 src="http://tech.ccidnet.com/pub/attachment/2004/1/269845.jpg" width=668> <BR><BR><BR><BR>3.2.2元素 action-mappings <BR><BR>这个元素描述了一个ActionMapping 对象集，类型是org.apache.struts.action.ActionMapping。与STRUTS的ActionServlet 注册的URL模式匹配的用户请求将具体地被这些ActionMapping 对象处理。子元素定义了各个ActionMapping对象。 <BR><BR><IMG height=168 src="http://tech.ccidnet.com/pub/attachment/2004/1/269851.jpg" width=666> <BR><BR>3.2.3元素 controller <BR><BR>这个元素描述了一个struts模块运行环境的配置——ControllerConfig bean <BR><BR><IMG height=506 src="http://tech.ccidnet.com/pub/attachment/2004/1/269852.jpg" width=670> <BR><BR><IMG height=426 src="http://tech.ccidnet.com/pub/attachment/2004/1/269853.jpg" width=617> <BR><BR><IMG height=361 src="http://tech.ccidnet.com/pub/attachment/2004/1/269854.jpg" width=669> <BR><BR><BR><BR>3.2.4 元素 data-source <BR><BR>这个元素描述了一个DataSource 对象——JDBC 2.0 标准扩展。这个对象将被保存在应用上下文中，而且可以象JavaBean 一样被设置。 <BR><BR><IMG height=360 src="http://tech.ccidnet.com/pub/attachment/2004/1/269855.jpg" width=669> <BR><BR>3.2.5 元素 exception <BR><BR>这个元素向struts系统为一个exception类型注册了一个ExceptionHandler。. <BR><BR><IMG height=487 src="http://tech.ccidnet.com/pub/attachment/2004/1/269856.jpg" width=671> <BR><BR>3.2.6 元素 form-bean <BR><BR>这个元素定义了一个ActionForm[org.apache.struts.action.ActionForm子类，这个定义被"action"元素所引用。 <BR><BR><IMG height=259 src="http://tech.ccidnet.com/pub/attachment/2004/1/269857.jpg" width=670> <BR><BR>3.2.7 元素 form-property <BR><BR>这个元素描述了一个配置DynaActionForm 或其子类的JavaBean属性。当这个元素的父元素"form-bean" 的"type" 是 [org.apache.struts.action.DynaActionForm] 或其子类时有效。如果使用了一个定制的DynaActionForm 子类，父元素"form-bean" 的"dynamic"属性必须设为 "true"。 <BR><BR><IMG height=337 src="http://tech.ccidnet.com/pub/attachment/2004/1/269846.jpg" width=668> <BR><BR>3.2.8 元素 forward <BR><BR>这个元素描述了一个ActionForward 对象，这个对象将被Action的doPerform返回。在代码中一般用一个逻辑名字来引用ActionForward 对象。一个"forward" 可以用来描述全局或局部ActionForwards. 全局的 forwards对模块内所有的Action 对象有效，局部forwards 嵌套在<ACTION></ACTION> 元素内，只能被相应的ActionMapping 中的Action访问。 <BR><BR><IMG height=464 src="http://tech.ccidnet.com/pub/attachment/2004/1/269847.jpg" width=661> <BR><BR>3.2.9元素 message-resources <BR><BR><IMG height=464 src="http://tech.ccidnet.com/pub/attachment/2004/1/269848.jpg" width=666> <BR><BR>3.2.10元素 plug-in <BR><BR><IMG height=152 src="http://tech.ccidnet.com/pub/attachment/2004/1/269849.jpg" width=671> <BR><BR>3.2.11 元素 set-property <BR><BR><IMG height=132 src="http://tech.ccidnet.com/pub/attachment/2004/1/269850.jpg" width=666>&nbsp; <BR><BR></P>
<P></P>
<P><B>目录： <BR><BR><A href="http://tech.ccidnet.com/pub/article/c1077_a82053_p1.html#1">4、模块定义</A> <BR><A href="http://tech.ccidnet.com/pub/article/c1077_a82053_p1.html#2">5、模块选择</A> <BR><A href="http://tech.ccidnet.com/pub/article/c1077_a82053_p1.html#3">6、总结</A> <BR><BR></B><BR><BR><A name=1><B>4、模块定义</B></A> <BR><BR>通过上面对STRUTS的模块化机制的讲解，我们现在可以开始实现我们的模块化例子程序了。 <BR><BR>4.1 Actionservlet参数 <BR><BR>我们在struts的web.xml中定义模块。下面的代码定义了三个模块：缺省模块，approval和registration模块，前缀分别是””,/approval和/registration。 <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>&lt;web-app&gt;
    &lt;servlet&gt;
        &lt;servlet-name&gt;action&lt;/servlet-name&gt;
        &lt;servlet-class&gt;org.apache.struts.action.ActionServlet&lt;/servlet-class&gt;
        &lt;init-param&gt;
            &lt;param-name&gt;config&lt;/param-name&gt;
            &lt;param-value&gt;/WEB-INF/struts-config.xml&lt;/param-value&gt;
                    &lt;/init-param&gt;
        &lt;init-param&gt;
            &lt;param-name&gt;config/approval&lt;/param-name&gt;
            &lt;param-value&gt;/WEB-INF/struts-config-approval.xml&lt;/param-value&gt;
                    &lt;/init-param&gt;
        &lt;init-param&gt;
            &lt;param-name&gt;config/registration&lt;/param-name&gt;
            &lt;param-value&gt;/WEB-INF/struts-config-registration.xml&lt;/param-value&gt;
        &lt;/init-param&gt;
     &lt;/init-param&gt;
         &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;
            &lt;/servlet&gt;    &lt;servlet-mapping&gt;
        &lt;servlet-name&gt;action&lt;/servlet-name&gt;
        &lt;url-pattern&gt;*.do&lt;/url-pattern&gt;
            &lt;/servlet-mapping&gt;
    &lt;/web-app&gt;</PRE></TD></TR></TBODY></TABLE><BR><BR>这样在初始化actionservlet的过程中，servletcontext的属性中就会有这样的属性键/值关系： <BR><BR></P>
<CENTER><IMG height=212 src="http://tech.ccidnet.com/pub/attachment/2004/1/270101.jpg" width=506></CENTER>
<P><BR><BR>4.2 approval模块配置文件 <BR><BR>下面是approval模块的配置文件，定义了form和action，以及相应的forward。 <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//
                              DTD Struts Configuration 1.1//EN" 
"http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd"&gt;
&lt;struts-config&gt;
        &lt;form-beans&gt;
        &lt;form-bean name="approvalForm" type="com.i505.struts.approval.form.ApprovalForm"&gt;
         &lt;/form-bean&gt;
            &lt;/form-beans&gt;
       &lt;action-mappings&gt;
        &lt;action
            attribute="approvalForm"
            name="approvalForm"
            input="/index.jsp"
            path="/approval"
            scope="request"
            type="com.i505.struts.approval.action.ApprovalAction"&gt;
            &lt;forward name="success" contextRelative="false" path="/resultok.jsp" /&gt;
        &lt;/action&gt;
    &lt;/action-mappings&gt;
&lt;/struts-config&gt;</PRE></TD></TR></TBODY></TABLE><BR><BR>4.3 registration模块配置文件 <BR><BR>下面是registration模块的配置文件，定义了form和action，以及相应的message-resources和forward。 <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//
                              DTD Struts Configuration 1.1//EN" 
"http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd"&gt;
&lt;struts-config&gt;
    &lt;form-beans&gt;
        &lt;form-bean name="registrationForm" type="com.i505.struts.registration.form.RegistrationForm" /&gt;
            &lt;/form-beans&gt;
      &lt;action-mappings&gt;
        &lt;action
            attribute="registrationForm"
            input="/index.jsp"
            name="registrationForm"
            path="/registration"
            type="com.i505.struts.registration.action.RegistrationAction"&gt;
             &lt;forward name="success" path="/resultok.jsp" /&gt;
        &lt;/action&gt;
    &lt;/action-mappings&gt;
    &lt;message-resources    parameter="com.i505.struts.ApplicationResources"/&gt;
    &lt;/struts-config&gt;</PRE></TD></TR></TBODY></TABLE><BR><BR><A name=2><B>5、模块选择</B></A> <BR><BR>本节主要讲述struts中如何选择模块，实现模块的真正运作的。 <BR><BR>5.1 action的模块选择 <BR><BR>当我们在浏览器中使用http://hostaddress/contextpath/module/action.do式样的的url时,actionservlet会根据module选择模块对象，下面是actionservlet处理http请求的代码： <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>protected void process(HttpServletRequest request,
                           HttpServletResponse response)
        throws IOException, ServletException {
        RequestUtils.selectModule(request, getServletContext());
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;       getRequestProcessor(getModuleConfig(request)).process
            (request, response);
    }</PRE></TD></TR></TBODY></TABLE><BR><BR>RequestUtils.selectModule函数将使用下面的代码把url中的模块前缀（下面代码的prefix将代表上面url式样中的/module）指定的模块对象保存在request属性中，这个模块对象就成了处理这个请求的当前模块对象： <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>// Expose the resources for this module
        ModuleConfig config = (ModuleConfig)
 context.getAttribute(Globals.MODULE_KEY + prefix);
        if (config != null) {
            request.setAttribute(Globals.MODULE_KEY, config);
        }
 else {
            request.removeAttribute(Globals.MODULE_KEY);
        }</PRE></TD></TR></TBODY></TABLE><BR><BR>5.2 资源的模块化 <BR><BR>资源（比如jsp）的模块化是指资源可以按照模块一样来组织，比如approval模块的资源可以放在approval目录下，而registration模块的资源则放在registration目录下，缺省模块的资源放在webroot下。 <BR><BR>url访问这些资源很简单,url式样是 http://hostaddress/contextpath/module/xxx.jsp。对于input和forward访问这些资源，我们只需直接写相对于模块路径下的路径，注意它们必须以”/”开头。如果forward是相对servletcontext的，则要加上模块路径。 <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>&lt;action-mappings&gt;
        &lt;action
            attribute="registrationForm"
            input="/index.jsp"
            name="registrationForm"
            path="/registration"
            type="com.i505.struts.registration.action.RegistrationAction"&gt;
             &lt;forward name="success" path="/resultok.jsp" /&gt;
        &lt;/action&gt;
    &lt;/action-mappings&gt;</PRE></TD></TR></TBODY></TABLE><BR><BR>5.3 Formtag中表单action url的生成 <BR><BR>对于模块编程，struts在formtag的action属性好像有些问题，这些问题出现在struts没有考虑直接访问jsp时的情况。应为forward和直接访问这两种环境是不同的，主要是直接访问这些JSP，request属性中没有模块对象，而forward访问这些jsp时request属性中有模块对象。我们需要修改代码，使得在产生action属性时不受jsp所在环境的影响，也就是我们将在formtag的action属性中指定模块，而不是request中得到模块。下面是registration模块的index.jsp的代码，它的formtag的action属性包括了模块的前缀/registration： <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>&lt;%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%&gt;
 &lt;%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html"%&gt;
 &lt;head&gt;
&lt;title&gt;申请注册&lt;/title&gt;
&lt;%@ page contentType="text/html;charset=GB2312" %&gt;
 &lt;/head&gt;
&lt;body&gt;
&lt;html:form action="/registration/registration.do" &gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;姓名：&lt;html:text property="name" /&gt;&lt;html:errors property="name"/&gt;&lt;br /&gt;&lt;br /&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;年龄：&lt;html:text property="age" /&gt;&lt;html:errors property="age"/&gt;&lt;br /&gt;&lt;br /&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;html:submit /&gt;
&lt;/html:form&gt;
&lt;/body&gt;
&lt;/html&gt;</PRE></TD></TR></TBODY></TABLE><BR><BR>下面我们来修改struts的相关代码达到这个效果。 <BR><BR>5.3.1 Formtag <BR><BR>Formtag的setAction将识别form tag的acton属性的module前缀，并分离出真正的模块相对的action路径，lookup将直接从ServletContext中获取模块配置对象。 <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>private String getActionPath(String action) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String temp = action.trim();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String x;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;         int pos=0;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!temp.startsWith("/")) temp = "/"+ temp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pos = temp.indexOf("/", 1);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(pos&lt;=0) return action;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
                  return temp.substring(pos);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
private String getModulePrefix(String action) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String result;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int pos;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String temp=action.trim();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!temp.startsWith("/")) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;temp= "/"+temp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pos = temp.indexOf("/", 1);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(pos&lt;=1) return "";
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return temp.substring(0, pos);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
public void setAction(String action)
 {this.modulePrefix = this.getModulePrefix(action);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.action = this.getActionPath(action);
    }
protected void lookup() throws JspException {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//我们直接从ServletContext中获取模块配置对象
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;moduleConfig = (ModuleConfig)
 pageContext.getServletContext().getAttribute(Globals.MODULE_KEY + modulePrefix);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;…}
     rotected String renderFormStartElement() {
        HttpServletResponse response =
            (HttpServletResponse) this.pageContext.getResponse();
                    StringBuffer results = new StringBuffer("&lt;form");
        results.append(" name=\"");
        results.append(beanName);
        results.append("\""); 
       results.append(" method=\"");
        results.append(method == null ? "post" : method);
        results.append("\" action=\"");
//我们的action已经去掉了modulePrefix，所以我们得重新加上
       results.append(
            response.encodeURL(
                RequestUtils.getActionMappingURL(this.modulePrefix+ this.action, this.pageContext)));
         …
}</PRE></TD></TR></TBODY></TABLE><BR><BR>5.3.2 Requestutils <BR><BR>Requestutils的getActionMappingURL主要用作附加servletcontext 路径，因为我们现在在action参数附加了modulePrefix路径，所以没必要再追加模块前缀。 <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>public static String getActionMappingURL(String action, PageContext pageContext)
 {
        HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
        StringBuffer value = new StringBuffer(request.getContextPath());
        ModuleConfig config =
            (ModuleConfig) pageContext.getRequest().getAttribute(Globals.MODULE_KEY);
//我们jsp中的formtag的action属性已经表示了模块，所以我们不能再追加模块名//
 if (config != null) { 
      //
     value.append(config.getPrefix());
       // }
        // Use our servlet mapping, if one is specified
        String servletMapping =
            (String) pageContext.getAttribute(Globals.SERVLET_KEY,
 PageContext.APPLICATION_SCOPE);
        if (servletMapping != null) {
            String queryString = null;
            int question = action.indexOf("?");
            if (question &gt;= 0) {
                queryString = action.substring(question);
            }
            String actionMapping = getActionMappingName(action);
            if (servletMapping.startsWith("*.")) {
                value.append(actionMapping);
                value.append(servletMapping.substring(1));
            } else if (servletMapping.endsWith("/*")) {
                value.append(servletMapping.substring(0, servletMapping.length() - 2));
                value.append(actionMapping);
            } else if (servletMapping.equals("/")) {
                value.append(actionMapping);
            }
            if (queryString != null) {
                value.append(queryString);
            }
        }
        else {
            if (!action.startsWith("/")) {
                value.append("/");
            }
            value.append(action);
        }
        // Return the completed value
        return (value.toString());
     }</PRE></TD></TR></TBODY></TABLE><BR><BR><A name=3><B>6、总结</B></A> <BR><BR>模块化编程有利于提高编程效率，但是struts中的模块化支持有些小问题，本文详细分析了struts支持模块化编程的机制，并作了些修改，希望对大家有帮助。另外如果我们可以把其改进为模块化的相关的东西可以打成一个包进行动态部署（比如approval.mar）的话，那将会更加有用。 </P><img src ="http://www.blogjava.net/qq13367612/aggbug/16653.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qq13367612/" target="_blank">Sung</a> 2005-10-24 22:11 <a href="http://www.blogjava.net/qq13367612/articles/16653.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Struts动态控制表格大小</title><link>http://www.blogjava.net/qq13367612/articles/16651.html</link><dc:creator>Sung</dc:creator><author>Sung</author><pubDate>Mon, 24 Oct 2005 14:10:00 GMT</pubDate><guid>http://www.blogjava.net/qq13367612/articles/16651.html</guid><wfw:comment>http://www.blogjava.net/qq13367612/comments/16651.html</wfw:comment><comments>http://www.blogjava.net/qq13367612/articles/16651.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qq13367612/comments/commentRss/16651.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qq13367612/services/trackbacks/16651.html</trackback:ping><description><![CDATA[<SPAN class=myp111><FONT id=zoom>在Succeeding with Struts的前面安装部分，我间接提到了DynaForms在运行期内可以动态的控制表格大小。换句话说，就是能够根据需要得到5行、或者10行、或者15行长的表格。可能有点不明智，我把这种策略的实际实现作为一种练习留给了读者自己。在接下来的几个月内，我收到了几十个读者的请求，他们请求给出详细的实现细节，所以这个月我将用两种不同的方法来实现动态调整的表格。 <BR>第一个方法就是我在前面的栏目中提到的那个方法，将尺寸参数留给DynaForm 的form-property 属性来实现。为了演示详细过程，我们来看看一个非常简单的应用：添加关于不同Star Wars 演员的注释。在这个应用中我们感兴趣的关键事实是：演员的数量在表格配置中动态设定，而不是在struts-config.xml文件中动态设定。 <BR>首先，我们先来看看struts-config.xml 文件： <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN" 
                               "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd"&gt;
&lt;struts-config&gt;
    &lt;form-beans&gt;
        &lt;form-bean name="dynamicArrayForm" type="org.apache.struts.validator.DynaValidatorForm"&gt;
            &lt;form-property name="people" type="demo.Person[]"/&gt;
        &lt;/form-bean&gt;
    &lt;/form-beans&gt;


&lt;action-mappings&gt;
    &lt;action path="/setupForm" type="demo.SetupFormAction" name="dynamicArrayForm" scope="session"
 
     validate="false"&gt;
        &lt;forward name="success" path="/displayForm.jsp"/&gt;
    &lt;/action&gt;
    
&lt;action path="/processActorComments"
type="demo.ProcessFormAction"
        name="dynamicArrayForm" scope="session" 
validate="false"&gt;
        &lt;forward name="success" path="/displayForm.jsp"/&gt;
    &lt;/action&gt;
&lt;/action-mappings&gt;
&lt;/struts-config&gt;</PRE></TD></TR></TBODY></TABLE><BR><BR>如你所见，这是一个相当简单的配置文件，只定义了一个表格和两个动作。第一个动作，/setupForm，用来在初始显示之前配置表格；另一个动作，/processActorComments 用来处理用户输入的注释。 <BR>在这个文件中有两个重要的事情需要注意，它们对于事态的发展很关键： <BR>1. people 表格属性定义为demo.Person[] 类型(即demo.Person的一个排列)，但不给出任何size 参数。这就为要创建的排列产生了一个占位符，但是没有任何例示的实排列。 <BR>2. 这两个动作将表格定义在会话期范围内。这是很关键的，因为用户在填写数值之后提交表格时，数值在动作执行之前已经填充到表格内了。这就意味着没有机会手动创建具有恰当空位数的排列，正如你在表格显示之前在SetupFormAction 类中看到的情况一样。换句话说，当表格提交时，必须已经有恰当的空位来接受表格值，唯一能保证这个的方法就是在会话期范围内就已经有了这个表格。 <BR>基本上在Person bean 中是没有值的，他只是一个具有lastName、 firstName、 dateOfBirth、gender 和comment字段的普通bean。源文件包括在WAR 文件内。 <BR>现在我们来看看SetupFormAction 类，它在表格第一次显示之前调用。 <BR><BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>package demo;

/**
 *  Copyright 2004, James M. Turner.
 * All Rights Reserved
 *
 * A Struts action that sets up a DynaForm which is globally scoped
 */

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.*;

import org.apache.struts.action.*;
import org.apache.struts.validator.DynaValidatorForm;

public class SetupFormAction extends Action {
    public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request,
                                 HttpServletResponse response)
            throws ServletException, IOException {

        DynaValidatorForm df = (DynaValidatorForm) form;
        Person[] p = new Person[3];
        p[0] = new Person();
        p[0].setDateOfBirth("07/13/1942");
        p[0].setLastName("Ford");
        p[0].setFirstName("Harrison");
        p[0].setGender("M");
        p[1] = new Person();
        p[1].setDateOfBirth("10/21/1956");
        p[1].setLastName("Fisher");
        p[1].setFirstName("Carrie");
        p[1].setGender("F");
        p[2] = new Person();
        p[2].setDateOfBirth("09/25/1951");
        p[2].setLastName("Hamill");
        p[2].setFirstName("Mark");
        p[2].setGender("M");

        df.set("people", p);

        return mapping.findForward("success");
    }
}</PRE></TD></TR></TBODY></TABLE><BR><BR>这一次也没有许多东西要看的。execute 方法要做的第一件事情，和任何基于DynaForm的动作所做的一样，就是将泛型ActionForm 类放到DynaValidatorForm内。这就使得我们可以在表格上使用get和set 方法。第二件事情就是，创建一个具有三个元素的类型Person 的排列。在这个方法中，尺寸是硬布线的，在实际应用中可以从数据库中选择一个尺寸。我们需要考虑的重要事情是排列应该在代码中创建，而不是由Struts引擎自己创建。这样行数可根据应用要求由代码随意指定。 <BR>一旦排列已经确定，方法将创建三个Person 类实例并赋与数值。同样，在实际的应用中可通过一个循环来实现，这个循环不断地从数据库中读取行和填充表格行。最后，动作返回成功，导致Struts转移控制到displayForm.jsp 页。 <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>&lt;!--
    Copyright 2004, James M Turner.
    All Rights Reserved
    
    --&gt;

&lt;%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %&gt;
&lt;%@ taglib uri="/WEB-INF/c.tld" prefix="c" %&gt;

&lt;head&gt;
&lt;title&gt;Star Wars Actor Fact Page&lt;/title&gt;
&lt;/head&gt;
&lt;H1&gt;&lt;center&gt;Start Wars Actor Fact Page&lt;/title&gt;
&lt;html:form action="/processActorComments" &gt;
    &lt;table border="1" width="80%"&gt;
        &lt;tr&gt;&lt;th&gt;Last Name&lt;/th&gt;&lt;th&gt;First Name&lt;/th&gt;&lt;th&gt;Date of Birth&lt;/th&gt;&lt;th&gt;Comment&lt;/th&gt;&lt;/tr&gt;
        &lt;c:forEach var="people" items="${dynamicArrayForm.map.people}"&gt;
            &lt;tr&gt;&lt;td&gt;&lt;c:out value="${people.lastName}"/&gt;&lt;/td&gt;
                &lt;td&gt;&lt;c:out value="${people.firstName}"/&gt;&lt;/td&gt;
                &lt;td&gt;&lt;c:out value="${people.dateOfBirth}"/&gt;&lt;/td&gt;
                &lt;td&gt;&lt;html:text name="people" indexed="true" property="comment"/&gt;&lt;/td&gt;
            &lt;/tr&gt;
        &lt;/c:forEach&gt;
    &lt;/table&gt;
    &lt;P/&gt;
    &lt;html:submit value="Update Comments"/&gt; 
&lt;/html:form&gt;</PRE></TD></TR></TBODY></TABLE><BR><BR>同样，这里也没有很多东西要看的，他与我们上一篇文章查看固定长度的行时的代码完全一样。该页迭代行（记住在JSTL中我们必须使用map 属性来获得到DynaForm 属性的访问），显示演员的姓、名和出生日期，并提供文本域以便输入注释。 <BR>当我们聚焦我们的浏览器合请求时，http://localhost:8080/struts/setupForm.do (假设你把struts.war 文件放在你本地机器的Tomcat 内)，将会出现下列页面： <BR><BR><CCID_NOBR></CCID_NOBR>
<H3>Start Wars Actor Fact Page 
<TABLE width="40%" border=1>
<TBODY>
<TR>
<TH>Last Name</TH>
<TH>First Name</TH>
<TH>Date of Birth</TH>
<TH>Comment</TH></TR>
<TR>
<TD>Ford</TD>
<TD>Harrison</TD>
<TD>07/13/1942</TD>
<TD><INPUT name=people[0].comment height="95507296"> </TD></TR>
<TR>
<TD>Fisher</TD>
<TD>Carrie</TD>
<TD>10/21/1956</TD>
<TD><INPUT name=people[1].comment height="95506144"> </TD></TR>
<TR>
<TD>Hamill</TD>
<TD>Mark</TD>
<TD>09/25/1951</TD>
<TD><INPUT name=people[2].comment height="95141832"> </TD></TR></TBODY></TABLE>
<P><INPUT type=submit value="Update Comments" height="95505840"> </P></H3><BR></FONT></SPAN>一旦表格提供，另一个简单的Struts动作来处理结果： <BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>package demo;

/**
 *  Copyright 2004, James M. Turner.
 * All Rights Reserved
 *
 * A Struts action that sends the new comments to the console
 */

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.*;

import org.apache.struts.action.*;
import org.apache.struts.validator.DynaValidatorForm;

public class ProcessFormAction extends Action {
    public ActionForward execute(ActionMapping mapping, 
ActionForm form, 
HttpServletRequest request,
                                 HttpServletResponse response)
            throws ServletException, IOException {

        DynaValidatorForm df = (DynaValidatorForm) form;
        Person[] p = (Person[]) df.get("people");

        for (int i = 0; i &lt; p.length; i++) {
            System.out.println(p[i].getFirstName() + " " + p[i].
getLastName() + ":" + p[i].getComment());
        }

        return mapping.findForward("success");
    }
}</PRE></TD></TR></TBODY></TABLE><BR><BR>在实际的应用中，这就是数据写回到数据库的地方。在这种情况下，他只将数据倒在控制台上所以我们可以看到他是正确收到的。假设我们为每个演员都填充了恰当的值，我们在控制台上会看到下列内容： <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>Harrison Ford:Indiana Jones
Carrie Fisher:Postcards from the Edge
Mark Hamill:Wing Commander</PRE></TD></TR></TBODY></TABLE><BR><BR>正如我在文章开头提到的一样，还有另一个方法可以解决这个问题，而且它不需要使用会话期范围内的表格。这个方法就是使用HashMaps 来存储行。我们来看看使用HashMaps编写的同一段代码： <BR>首先，我们添加一个新表格到struts-config.xml： <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>&lt;form-bean name="dynamicHashmapForm" type="org.apache.struts.validator.DynaValidatorForm"&gt;
            &lt;form-property name="people" type="java.util.HashMap"/&gt;
            &lt;form-property name="comments" type="java.util.HashMap"/&gt;
        &lt;/form-bean&gt;</PRE></TD></TR></TBODY></TABLE><BR><BR>现在，我们不使用beans的排列，改为使用HashMap 来存储每个人的数据。另外，我们需要一个新的HashMap 来存储注释，原因我稍后再解释。我们也需要一个新的动作来填充数据： <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>package demo;

/**
 *  Copyright 2004, James M. Turner.
 * All Rights Reserved
 *
 * A Struts action that sets up a DynaForm which is globally scoped
 */

import java.io.IOException;
import java.util.HashMap;
import javax.servlet.ServletException;
import javax.servlet.http.*;

import org.apache.struts.action.*;
import org.apache.struts.validator.DynaValidatorForm;

public class SetupHashFormAction extends Action {
    public ActionForward execute(ActionMapping mapping, 
ActionForm form, HttpServletRequest request,
                                 HttpServletResponse response)
            throws ServletException, IOException {

        DynaValidatorForm df = (DynaValidatorForm) form;
        HashMap hm = (HashMap) df.get("people");
        Person p = new Person();
        p = new Person();
        p.setDateOfBirth("07/13/1942");
        p.setLastName("Ford");
        p.setFirstName("Harrison");
        p.setGender("M");
        hm.put("1", p);
        p = new Person();
        p.setDateOfBirth("10/21/1956");
        p.setLastName("Fisher");
        p.setFirstName("Carrie");
        p.setGender("F");
        hm.put("2", p);
        p = new Person();
        p.setDateOfBirth("09/25/1951");
        p.setLastName("Hamill");
        p.setFirstName("Mark");
        p.setGender("M");
        hm.put("3", p);
        return mapping.findForward("success");
    }
}</PRE></TD></TR></TBODY></TABLE><BR><BR>基本上，这段代码与前面的代码相同，除了我们将Person 对象存储到HashMap 中，而不是排列中之外。我们也不需要创建HashMap，因为它可以作为表格初始化的一部分来动态实现。 <BR>在JSP本身中相应的技巧部分为： <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>&lt;!--
    Copyright 2004, James M Turner.
    All Rights Reserved
    
    --&gt;

&lt;%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %&gt;
&lt;%@ taglib uri="/WEB-INF/struts-html-el.tld" prefix="html-el" %&gt;
&lt;%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %&gt;
&lt;%@ taglib uri="/WEB-INF/c.tld" prefix="c" %&gt;
&lt;%@ taglib prefix="fmt" uri="/WEB-INF/fmt.tld" %&gt;

&lt;head&gt;
&lt;title&gt;Star Wars Actor Fact Page&lt;/title&gt;
&lt;/head&gt;
&lt;H1&gt;&lt;center&gt;Start Wars Actor Fact Page&lt;/title&gt;
&lt;html:form action="/processHashActorComments" &gt;
    &lt;table border="1" width="80%"&gt;
        &lt;tr&gt;&lt;th&gt;Last Name&lt;/th&gt;&lt;th&gt;First Name&lt;/th&gt;
&lt;th&gt;Date of Birth&lt;/th&gt;&lt;th&gt;Comment&lt;/th&gt;&lt;/tr&gt;
        &lt;c:forEach var="people" items="${dynamicHashmapForm.map.people}"&gt;
            &lt;tr&gt;&lt;td&gt;&lt;c:out value="${people.value.lastName}"/&gt;&lt;/td&gt;
                &lt;td&gt;&lt;c:out value="${people.value.firstName}"/&gt;&lt;/td&gt;
                &lt;td&gt;&lt;c:out value="${people.value.dateOfBirth}"/&gt;&lt;/td&gt;
                &lt;td&gt;&lt;html-el:text property="comments(${people.value.lastName},
${people.value.firstName})" /&gt;&lt;/td&gt;
            &lt;/tr&gt;
        &lt;/c:forEach&gt;
    &lt;/table&gt;
    &lt;P/&gt;
    &lt;html:submit value="Update Comments"/&gt; 
&lt;/html:form&gt;</PRE></TD></TR></TBODY></TABLE><BR><BR>记住：在初始化时填充的HashMap 值，只要表格显示就会消失，因为表格是请求范围的，而不是会话期范围的。特别是对于我们来说这就意味着所有的Person 对象都会消失。所以，如果我们粘贴文本域到Person bean 的注释属性上，在提交表格时我们将得到一个空的指针异常，因为Person 对象不再位于HashMap 内(实际上，我们得到的是一个全新的空的HashMap.)。所以，我们需要将注释存储在一个单独的并行HashMap 内，它将注释当作简单的字符串来存储。 <BR>在上述的代码中还须注意几件事情。首先，因为现在正迭代HashMap条，来自c:forEach 标记的值实际上是用于堆栈条的占位符，同时具有两个属性。key 属性的值用来访问堆栈（在我们的例子中如字符"1", "2", "3"等等），value 属性的值存储在关键字之下。所以，在这种情况下，我们必须使用value 属性来得到Person bean 的实属性。 <BR>而且，我们需要构造一个用于文本框的有效的Struts属性域。在html-el 标记库中使用JSTL 扩展就可以实现。在这种情况下，我们通过一个由演员的最后一个名字、逗号和第一个名字组成的字符串来存储注释。 <BR>最后，我们需要一个新的动作来处理结果： <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>package demo;

/**
 *  Copyright 2004, James M. Turner.
 * All Rights Reserved
 *
 * A Struts action that sends the new comments to the console
 */

import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import javax.servlet.ServletException;
import javax.servlet.http.*;

import org.apache.struts.action.*;
import org.apache.struts.validator.DynaValidatorForm;

public class ProcessHashFormAction extends Action {
    public ActionForward execute(ActionMapping mapping, 
ActionForm form, HttpServletRequest request,
                                 HttpServletResponse response)
            throws ServletException, IOException {

        DynaValidatorForm df = (DynaValidatorForm) form;
        HashMap hm = (HashMap) df.get("comments");

        Iterator it = hm.keySet().iterator();
        while (it.hasNext()) {
            String key = (String) it.next();
            String comment = (String) hm.get(key);
            System.out.println(key + ":" + comment);
        }

        return mapping.findForward("success");
    }
}</PRE></TD></TR></TBODY></TABLE>
<P><BR><BR>同样，这里最大的差别是数据都是作为HashMaps 来存储的。代码获取关键字(lastname,firstname)，然后显示关键字和在控制台注释: <BR><BR>Fisher,Carrie:Leia <BR>Ford,Harrison:Han <BR>Hamill,Mark:Luke <BR><BR>请注意，当控制返回到JSP页时，打印一个空白表格。这是因为我们在初始化操作中创建的HashMap 已经没有了，在处理结果时我们不能重新创建它。你可以将该数据保存在会话期变量中，但是接着你要返回到你使用第一个方案的地方。最好是选择一个关键字，在表格提交时它可以允许你在后台对象上获得，并且能够总是重新创建需要的任何其他的表格数据。 <BR>哪种方式更好？基于排列的方案允许你将所有的数据都保存在一个bean 内，而基于堆栈的方法避免了任何会话期范围的数据。你觉得哪种方案最好就采用哪种。 <BR>注意：包含运行这些例子所需的所有代码和库的WAR 文件在http://www.blackbear.com/struts.war.上可以找到。 </P><img src ="http://www.blogjava.net/qq13367612/aggbug/16651.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qq13367612/" target="_blank">Sung</a> 2005-10-24 22:10 <a href="http://www.blogjava.net/qq13367612/articles/16651.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>类反射简化Struts应用程序的开发 </title><link>http://www.blogjava.net/qq13367612/articles/16652.html</link><dc:creator>Sung</dc:creator><author>Sung</author><pubDate>Mon, 24 Oct 2005 14:10:00 GMT</pubDate><guid>http://www.blogjava.net/qq13367612/articles/16652.html</guid><wfw:comment>http://www.blogjava.net/qq13367612/comments/16652.html</wfw:comment><comments>http://www.blogjava.net/qq13367612/articles/16652.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qq13367612/comments/commentRss/16652.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qq13367612/services/trackbacks/16652.html</trackback:ping><description><![CDATA[<SPAN class=myp111><FONT id=zoom>本文讲述了如何利用Java的反射的机制来简化Structs应用程序的开发。 <BR><BR><B>一、Struts中引入ActionForm类的意义与缺陷：</B> <BR><BR>在Struts应用程序中，ActionForm是一个很重要的概念,它的主要功能就是为Action的操作提供与客户表单相映射的数据（如果在客户指定的情况下，还包括对数据进行校验）。Action根据业务逻辑的需要，对数据状态进行修改，在改变系统状态后，ActionForm则自动的回写新的数据状态并保持。程序员对JSP与ActionForm Bean的对应关系，通常感到很迷惑，JSP与ActionForm到底是1:1,还是N:1,对此，Struts本身对此并没有提出自己的观点。无论是一对一，还是多对一，Struts本身并不关心，它都能很好得工作。Struts在它的开发文档中指出，对于较小规模的开发，开发人员可以根据自己的需要，每个模块只写一个ActionForm Bean，甚至整个应用程序只写一个ActionForm Bean.当然，Struts也不反对每个ActionForm Bean只对应一个JSP,他们之间的对应关系，由开发人员自己决定。 <BR><BR>在我看来，正如Entity EJB对J2EE的重大贡献一样，Entity EJB使得程序员对二维关系数据库的存取对象化了，程序员可以使用Set 或者Get等面向对象的方法来操纵关系数据库的数据，而ActionForm也使得程序员对网页的数据存取奇迹般的对象化了，程序员同样也可以使用Set 或者Get等面向对象的方法存取网页上的数据，这是一个开发模式方式上的重大转变。基于此，我个人认为ActionForm与JSP即VIEW层的关系最好是一对一的关系，这样，在理解上会更清晰一些。但是，这样也会带来一个很现实的问题，在一个应用程序中，也许有非常多得JSP页面，如果每个ActionForm 都只对应一个JSP页面，那么系统的Java代码就会急剧膨胀起来，而且，每个ActionForm都是只有很简单的Set或者Get方法存取数据，那么，如何简化Struts应用程序的开发呢？ <BR><BR>在Struts1.1 中，Struts引入了DynaActionForm和Dyna Bean,试图解决这个问题，在我看来，DynaActionForm的引入，破坏了对网页存取对象化的概念，使开发人员重新回到了使用HashTable、Map、Collection、ArrayList等集合对象来实现对数据进行存取的老路上来。虽然应用程序的灵活性大大增加了，但是代码的可读性也大大降低了，开发人员之间的交流难度也增加了。 <BR><BR>在传统的应用程序对ActionForm Bean的访问中，我们通常都写成如下的形式： <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>Connection conn=DriverManager.getConnection("JDBC URL ");
      sql=" select *  from some tables ";
PreparedStatement stmt = conn.prepareStatement(sql);
      ResultSet rs = stmt.executeQuery();
ArrayList array=new ArrayList();
while (rs.next()) {
   AActionForm actionForm =new AActionForm ();
   actionForm.setId(rs.getString("Id"));
   actionForm.setName(rs.getString("Name"));           
   array.add(actionForm);
}</PRE></TD></TR></TBODY></TABLE><BR><BR>在Action 的Execute方法中，我们 把这个集合用request.setAttribute("array", array)存储起来，然后在JSP页面中，我们用iterate Tag把数据循环现实出来。代码通常都是这个样子： <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>&lt;logic:present name=" array " scope="request"&gt;
&lt;logic:iterate name=" array " id=" array " 
type="com.bhsky.webis.Goods"&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;tr align="center"&gt; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    &lt;td class="table2"&gt;
&lt;bean:write name=" array " property="goodsid"/&gt;
&lt;/td&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;td class="table2"&gt;
&lt;bean:write name=" array " property="goodsname"/&gt;
&lt;/td&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;/tr&gt;
  &lt;/logic:iterate&gt; 
&lt;/logic:present&gt;</PRE></TD></TR></TBODY></TABLE>
<P><BR><BR>在Struts中，对数据的访问和显示的写法通常都是很固定的，在VIEW层，我们是没有办法简化自己的代码的，在Action层，其写法通常也很固定，只是做一个页面的跳转，商业逻辑和对数据得访问，通常都是放在JavaBean中。那么，在此，我提出一种运用类反射的机制，使应用程序对ActionForm Bean的赋值自动化，即应用程序通过一个简单的接口，使用一个通用的方法，就可以完成对ActionForm Bean的赋值，而不必在每个使用ActionFormBean的地方，都把数据库中的值手动赋值给ActionForm Bean，然后再在JSP页面中显示出来。虽然它不能减少ActionForm Bean的数量，但是，它至少使应用程序对ActionForm Bean的赋值自动化了，从而减少了程序出错概率，提高了程软件开发效率。 <BR><BR><B>二、类反射的概念：</B> <BR><BR>关于类反射的概念，在此我就不详细介绍了，它不是本文的重点，IBM developerWorks网站上有大量介绍类反射概念的文章，大家可以找出来参考一下。其实，Struts本身就大量利用了类反射的机制. </P></FONT></SPAN>. 
<P></P>
<P></P>
<P><B>三、如何应用类反射机制简化Struts应用程序的开发:</B> <BR><BR><BR><BR><BR><BR>1、 先定义Action FormBean: <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>package com.bhsky.webis.system;
import org.apache.struts.action.*;
import javax.servlet.http.*;
    
public class UsersActionForm extends ActionForm {
private String usr_id;
private String usr_name;
public void setUsr_id(String usr_id) {
    this.usr_id = usr_id;
}
public String getUsr_id() {
    return usr_id;
}
public String getUsr_memo() {
    return usr_memo;
}
public void setUsr_name(String usr_name) {
    this.usr_name = usr_name;
}
}</PRE></TD></TR></TBODY></TABLE><BR><BR>2、 编写通用的为ActionFormBean赋值的方法： <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>/////////////////////////////////////////////////////////////////////////////
    //Function: 完成ResultSet对象向ArrayList对象为集合的对象的转化
    //Para:sql,指定的查询Sql
   //Para:className,Sql相对应得JavaBean/FormBean类的名字
   //Return:以类className为一条记录的结果集，完成ResultSet对象向ArrayList对象为集
   //合的className对象的转化
  //////////////////////////////////////////////////////////////////////////////
  public ArrayList Select(String sql,String className){
    ArrayList paraList=new ArrayList();
    try{
      if (conn == null){
        Connection();
      }
      PreparedStatement stmt = conn.prepareStatement(sql);
      ResultSet rs = stmt.executeQuery();
      String recordValue="";
      Object c1=null;
      paraList=new ArrayList();
      ResultSetMetaData rsmd = rs.getMetaData();
      int columnCount = rsmd.getColumnCount();
      while (rs.next()){
          c1=Class.forName(className).newInstance();
          for (int i=1; i&lt;=columnCount; i++) {
            if(rs.getString(rsmd.getColumnName(i))!=null){
              recordValue=rs.getString(rsmd.getColumnName(i));
            }else{
              recordValue="";
            }
Method 
m=c1.getClass().getMethod(getSetMethodName(rsmd.getColumnName(i)),
new Class[]{recordValue.getClass()});
            m.invoke (c1, new Object[]{recordValue});
          }
          paraList.add(c1);
      }
    }catch(SQLException ex){
      
}catch(ClassNotFoundException e){

}catch(NoSuchMethodException e) {

}catch(InvocationTargetException e){

}catch (IllegalAccessException e){

}catch(InstantiationException e){

} finaly{
        closeConnection();
return paraList;
}
  }</PRE></TD></TR></TBODY></TABLE><BR><BR>3、 在JavaBean封装的商业逻辑中调用Select 方法，然后在JSP页面上显示出来： <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>//Function:取得用户列表
  //Para:
  //Return:返回用户列表
  /////////////////////////////////////////////////////////////////////////////
  public ArrayList getUsers(){
      ArrayList ret=null;
      DatabaseManage db=new DatabaseManage();
      String sql=" select usr_id,usr_name "
          +" from users " ;
      ret=db.Select(sql," com.bhsky. webis.system.UsersActionForm");
      return ret;
  }</PRE></TD></TR></TBODY></TABLE><BR><BR>4、 在Action的execute方法中调用getUsers()方法： <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>public ActionForward execute(
            ActionMapping actionMapping, 
            ActionForm actionForm, 
            HttpServletRequest request, 
            HttpServletResponse httpServletResponse) 
   {
    /**@todo: complete the business logic here, this is just a skeleton.*/
    UsersActionForm uaf=(UsersActionForm)actionForm;
    SystemService ubb=new SystemService();
    ArrayList userList=ubb.getUsers();
    request.setAttribute("userList",userList);
    ActionForward actionForward=actionMapping.findForward(url);
    return actionForward;
  }</PRE></TD></TR></TBODY></TABLE><BR><BR>5、 在JSP中显示： <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>&lt;table width="700" class="1" border="1" cellspacing="1" align="center"&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;tr&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;td class="list" &gt;用户ID&lt;/td&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;td class="list" &gt;姓  名&lt;/td&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/tr&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;logic:present name="userList" scope="request"&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;      &lt;logic:iterate name="userList" id="userList" 
type="com.bhsky.webis.system.UsersActionForm"&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;tr&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;td class="cell1"  height="22"&gt;&lt;bean:write name="userList" 
property="usr_id"/&gt;&lt;/td&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;td class="cell1"  height="22"&gt;&lt;bean:write name="userList" 
property="usr_name"/&gt;&lt;/td&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    &lt;/tr&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/logic:iterate&gt;
      &lt;/logic:present&gt;
&lt;/table&gt;</PRE></TD></TR></TBODY></TABLE><BR><BR><B>四、结语：</B> <BR><BR>我们通过运用类反射机制，在一个Struts应用开发中，完成了一个通用查询方法的实现。它使得程序员摆脱了在每个应用程序中都要编写枯燥的set、get等方法来访问ActionForm Bean,从而简化了Struts应用程序的开发。 </P><img src ="http://www.blogjava.net/qq13367612/aggbug/16652.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qq13367612/" target="_blank">Sung</a> 2005-10-24 22:10 <a href="http://www.blogjava.net/qq13367612/articles/16652.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>应用Struts的安全隐患及解决方案 </title><link>http://www.blogjava.net/qq13367612/articles/16647.html</link><dc:creator>Sung</dc:creator><author>Sung</author><pubDate>Mon, 24 Oct 2005 14:07:00 GMT</pubDate><guid>http://www.blogjava.net/qq13367612/articles/16647.html</guid><wfw:comment>http://www.blogjava.net/qq13367612/comments/16647.html</wfw:comment><comments>http://www.blogjava.net/qq13367612/articles/16647.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qq13367612/comments/commentRss/16647.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qq13367612/services/trackbacks/16647.html</trackback:ping><description><![CDATA[<SPAN class=myp11><FONT id=zoom>重要提示：根据lironghai的评论，经验证，发现在WebLogic下由于安全限制不能使用本文所推荐的目录安排。为了保证系统的可移植性，不建议大家采用本文的方式。 <BR><BR><B>问题</B> <BR><BR>使用Struts框架时，权限通常控制在Action级（比如将权限验证放在Action的基类中，这样新的Action都继承于这个Action基类，所有Action就可以专注于业务逻辑，而不需要重复地进行权限控制了），这也符合MVC中的角色划分。然而，这会产生一个安全隐患。因为权限控制在Action中，所以，页面也就没有安全屏障了。一般的新增数据、更新数据不会有什么问题，因为这些数据必须通过HTML的Form提交到Struts的中心控制器，最终由相应的Action来处理，所以Action中就可以验证该用户的权限了。然而，对于一些不需要Action进行数据存取，或者有的页面没有严格按照MVC的角色划分而在页面中有获取数据的代码，那么这个页面就危险了。比如，显示一张通知页面，通常可以通过配置权限，使部分授权的用户才可以看到该级别的通知。这个通知页面是不需要从数据库中获取数据的。所以，可以不通过Action的调用来显示，而是直接敲入显示该通知的页面的链接就可以看到了。甚至不需要登录系统，不用管是否有查看该通知的权限！ <BR><BR>比如下图中，请求1： <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>http://.../showannouncement.do</PRE></TD></TR></TBODY></TABLE><BR><BR>是通过正常的途径访问的，需要经过权限验证。而请求2： <BR><BR><CCID_NOBR></CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE></CCID_CODE>http://.../announcementshow.jsp</PRE></TD></TR></TBODY></TABLE><BR><BR>则完全绕过了权限检查，任何人，不需要登录系统就可以访问到该信息了。 <BR><BR><IMG height=281 src="http://tech.ccidnet.com/pub/attachment/2003/12/263985.gif" width=432> <BR><BR><B>解决方案</B> <BR><BR>解决的办法也不是没有，非常简单。大家都知道JSP Web容器会对应用的WEB-INF目录下的所有文件加以保护的，任何用户都不能直接通过浏览器访问WEB-INF目录（包括子目录）下的任何资源，然而这些资源可以被JSP Web容器访问。所以，解决办法已经出来了。可以把你的JSP页面放到WEB-INF目录下，在struts-config.xml的action的配置中注意要把转向的页面指向类似： <BR><BR>/WEB-INF/pages/announcementshow.jsp。 <BR><BR>这样就保证了所有数据的安全了。 <BR><BR>使用本文的方法，甚至可以对静态的页面，比如html的页面进行保护，设置权限以限制访问</FONT></SPAN> <img src ="http://www.blogjava.net/qq13367612/aggbug/16647.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qq13367612/" target="_blank">Sung</a> 2005-10-24 22:07 <a href="http://www.blogjava.net/qq13367612/articles/16647.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在Eclipse中开发struts应用程序 </title><link>http://www.blogjava.net/qq13367612/articles/16648.html</link><dc:creator>Sung</dc:creator><author>Sung</author><pubDate>Mon, 24 Oct 2005 14:07:00 GMT</pubDate><guid>http://www.blogjava.net/qq13367612/articles/16648.html</guid><wfw:comment>http://www.blogjava.net/qq13367612/comments/16648.html</wfw:comment><comments>http://www.blogjava.net/qq13367612/articles/16648.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qq13367612/comments/commentRss/16648.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qq13367612/services/trackbacks/16648.html</trackback:ping><description><![CDATA[<SPAN class=myp111><FONT id=zoom><B>一． 下载并安装Easy Struts包</B> <BR><BR>1． Easy Struts是开放源代码组织sourceforge.net上的一个项目，目前最新的版本是0.64，可以在它的网站http://sourceforge.net/projects/easystruts上下载压缩文件org.easystruts.eclipse_0.6.4.zip (Eclipse的安装这里不再描述) <BR><BR>2． 将下载后的压缩包解压到{ECLIPSE}\plugins目录下，其中{ECLIPSE}为Eclipse所在的目录。应该注意的是解压后plugins目录下应该多一个子目录，目录名为：com.cross.easystruts.eclipse_[ver]，[ver]为相应的版本号。 <BR><BR>3． Easy Struts的初始化设置：启动Eclipse，通过菜单Windows-&gt;Preferences打开设置窗口。窗口的左边会多出一个选项：Easy Struts。如下图所示： <BR><BR>
<CENTER><IMG height=249 src="http://tech.ccidnet.com/pub/attachment/2004/5/292627.png" width=191> <BR><BR>图1 </CENTER><BR><BR>在设置Easy Struts之前要先准备好struts所需的文件（可在Jakarta网站上下载），包括struts.jar，然后是几个用于定义标签库的描述文件包括：struts_html.tld、struts_bean.tld、struts_logic.tld。点击设置窗口左边的Easy Struts后出现如下图2：Easy Struts的初始化设置界面。根据所下载struts的版本选择struts 1.0或者struts 1.1，最新的版本都是struts 1.1。在这里我们选择struts 1.1并在struts 1.1所需的库文件中找到并添加struts.jar文件。在struts 1.1所需的类型库描述文件中建议至少加入前面提到的三个描述文件分别是：struts_html.tld、struts_bean.tld、struts_logic.tld，这三个文件会在创建struts应用项目时自动拷贝到项目的WEB-INF目录下。设置界面上的其他内容基本上按照默认的值即可，无需改动。好了，点击OK按钮关闭设置对话框使设置生效。至此我们已经完成Easy Struts的基本设置可以开始struts的开发了。 <BR><BR>
<CENTER><IMG height=400 src="http://tech.ccidnet.com/pub/attachment/2004/5/292629.png" width=401> <BR><BR>图2 </CENTER><BR><BR><B>二． 配置和开发struts应用项目</B> <BR><BR>1． 新建JAVA项目并设置为支持Easy Struts：新建一个JAVA项目，暂且把这个项目命名为：StrutsDemo，新建完项目后除了Eclipse本身用来描述JAVA项目的两个文件.project和.classpath外并没有其他任何文件。为了使该项目集成Easy Struts，只需点击工具条上的新建图标，选择Java-&gt;Easy Struts-&gt;Add Easy Struts Support并点击下一步按钮，如下图3所示： <BR><BR>
<CENTER><IMG height=400 src="http://tech.ccidnet.com/pub/attachment/2004/5/292631.png" width=400> <BR><BR>图3 </CENTER><BR><BR>点击下一步按钮后到了Easy Struts项目一些基本信息的输入界面，如下图4所示： <BR><BR>
<CENTER><IMG height=376 src="http://tech.ccidnet.com/pub/attachment/2004/5/292633.png" width=450> <BR><BR>图4 </CENTER><BR><BR>在图4的界面中输入web应用程序的目录名，例如struts_demo，发布的时候只需要把该目录打包成WAR文件即可。根据应用服务器的实际情况选择web应用程序的版本，建议使用2.3，目前大部分应用服务器的主流版本都支持2.3版本的WEB应用程序。选择Struts 1.1。修改Easy Struts自动产生的程序包名，例如test.struts。点击完成按钮后Easy Struts会自动产生文件.easystrutsplugin以及创建刚刚在设置界面中输入的web应用服务器目录名的目录，该目录包含WEB-INF子目录，Easy Struts会自动拷贝几个tld文件到该目录下，我们还必须手工的将struts.jar文件拷贝到WEB-INF\lib目录下。 <BR><BR>同时产生一个配置文件：ApplicationResources.properties，这个文件可以用来存放用户自己的配置信息。该配置文件支持多语言，struts会自动根据环境配置信息来获取相应的配置文件，例如ApplicationResources_zh_CN.properties对应的是中文简体的配置信息。web.xml也在这个时候产生，该文件已经自动定义好ActionServlet入口，以及这个servlet所需的参数，用户无需再行配置，极大的方便了初学者学习和使用struts。要改变刚刚所输入的信息只需要打开项目的属性对话框即可修改这些配置。 <BR><BR>2． 开发struts应用程序：在开发struts应用程序之前还有一项准备工作要做，需要给项目的类路径中添加struts.jar以及servlet.jar这两个文件否则新建struts程序时将会有一大堆错误信息，并设置项目的默认输出文件夹为\struts_demo\WEB-INF\classes。在解压完后，Easy Struts插件已经在Eclipse开发环境中添加了几个用于创建struts相关程序的向导。点击工具条上的新建图标打开图3所示的对话框即可选择与struts相关的程序的开发，例如最常用的Action类的开发，Form类的开发等等。下面我们着重介绍一下Action类的开发。 <BR><BR>在新建对话框中选择新建Easy Action并点击下一步按钮 <BR><BR>
<CENTER><IMG height=400 src="http://tech.ccidnet.com/pub/attachment/2004/5/292635.png" width=382> <BR><BR>图5</CENTER><BR><BR>在用例文本框(Use case)中输入Action类的名称，Easy Struts会自动根据你输入的值更新对应的URL请求的路径(path)以及Action类名(Type)。在这个界面中Module name文本框指的是当有多个struts_config文件时选择其他文件，默认的是使用struts_config.xml。而Form name是当Action类需要与一个Form类对应时做的选择。其他信息使用默认的值，点击下一步添加错误处理，以及页面的跳转处理。点击完成按钮即已完成Action类的向导，Easy Struts自动产生类XxxxAction.java，并在struts_config.xml做相应的配置信息。所有的这些向导也可以通过双击项目文件struts_config.xml，并在struts_config.xml界面中操作链接来完成，这是一个可视化的界面用来编辑struts_config.xml内容。如下图所示： <BR><BR>
<CENTER><IMG height=294 src="http://tech.ccidnet.com/pub/attachment/2004/5/292637.png" width=450> <BR><BR>图6</CENTER><BR><BR><B>三． 总结</B> <BR><BR>Easy Struts现在还是一个开发中的版本，但是其具有的强大的功能以及易用性已经显露无疑。通过与Eclipse的结合使Struts的开发变成一件非常简单的事情。本文只是简单的介绍了如何开始来使用Easy Struts这个插件帮助我们开发struts应用程序，具体与struts相关的开发已经有非常多的文章介绍了，况且这也不是我们的本意，所以此处并没有做深入的叙述。总而言之，Easy Struts还有很多功能需要我们继续的发掘。 <BR><BR><B>四． 参考资料</B> <BR><BR>www.eclipse.org Eclipse的官方网站； <BR><BR>http://sourceforge.net/projects/easystruts Easy Struts项目网站 <BR><BR>http://jakarta.apache.org/struts/index.html Apache Struts网站 </FONT></SPAN><img src ="http://www.blogjava.net/qq13367612/aggbug/16648.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qq13367612/" target="_blank">Sung</a> 2005-10-24 22:07 <a href="http://www.blogjava.net/qq13367612/articles/16648.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>struts数据源管理器</title><link>http://www.blogjava.net/qq13367612/articles/16213.html</link><dc:creator>Sung</dc:creator><author>Sung</author><pubDate>Mon, 19 Sep 2005 08:28:00 GMT</pubDate><guid>http://www.blogjava.net/qq13367612/articles/16213.html</guid><wfw:comment>http://www.blogjava.net/qq13367612/comments/16213.html</wfw:comment><comments>http://www.blogjava.net/qq13367612/articles/16213.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qq13367612/comments/commentRss/16213.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qq13367612/services/trackbacks/16213.html</trackback:ping><description><![CDATA[<P>从网上找到的第一个struts连接数据库的例子是在struts的config文件里面配置数据源的，即struts数据源管理器，结果用1.2的struts怎么都弄不好，为了这个问题费尽了周折，今天总算在struts的文档中找到了答案。看来以后学习新东西还是要从英文文档入手-_-</P><BR>
<P>理论上，商务罗基层应该包含数据链接的描述，包括数据库链接。但是一些早期的程序员习惯于在调用(caller)中包含数据库链接或者数据源实例。当你需要使用继承的设计时，struts数据源管理器可以在你使你的action类能够在你需要的时候生成这样的数据源。</P><BR>
<P>注意：默认情况下数据库链接是直接由商务逻辑的类来控制的，一般通过JNDI。struts数据源管理器应当仅由那些没有独立数据链接的业务逻辑的类继承得到。如果可能，极力推荐使用标准的DAO模式，这样业务逻辑层不需要知道任何数据库的细节。数据源管理器在struts1.x中仍然保留并向下兼容，但是在后续版本中可能不再被支持。</P><BR>
<P><STRONG></STRONG> </P>
<P></P><A name=more></A>
<P>
<P>这还不是问题的关键，如果要用数据库管理器，需要手动下载dbcp's BasicDataSource <A href="http://jakarta.apache.org/commons/dbcp/downloads.html">Commons DBCP</A>. </P><BR>
<P>并且1.2版本之后为了更好的配合BasicDataSource插件和别的数据库的执行，先前版本的struts通用数据源被移除了，这就是为什么1.2的lib里面没有struts-legacy.jar这个文件的原因了。</P><BR>
<P>以下是我成功的配置信息：</P><BR>
<P><data-sources><BR><!-- configuration for commons BasicDataSource --><BR><data-source type="org.apache.commons.dbcp.BasicDataSource"><BR>    <set-property<BR>      property="driverClassName"<BR>      value="com.mysql.jdbc.Driver" /><BR>    <set-property<BR>      property="url"<BR>      value="jdbc:mysql://localhost:3306/mysql?useUnicode=true&characterEncoding=UTF-8" /><BR>    <set-property<BR>      property="username"<BR>      value="root" /><BR>    <set-property<BR>      property="password"<BR>      value="yourpass" /><BR>    <set-property<BR>      property="maxActive"<BR>      value="10" /><BR>    <set-property<BR>      property="maxWait"<BR>      value="5000" /><BR>    <set-property<BR>      property="defaultAutoCommit"<BR>      value="false" /><BR>    <set-property<BR>      property="defaultReadOnly"<BR>      value="false" /><BR>    <set-property<BR>      property="validationQuery"<BR>      value="SELECT COUNT(*) FROM db" /><BR></data-source><BR></data-sources><BR>最后面那一行不是必需的，但是如果写上的话返回的结果及至少要有一条记录！</P><BR>
<P>mysql的jdbc也可以写成org.gjt.mm.mysql.Driver这样子。</P><![CDATA[<P>从网上找到的第一个struts连接数据库的例子是在struts的config文件里面配置数据源的，即struts数据源管理器，结果用1.2的struts怎么都弄不好，为了这个问题费尽了周折，今天总算在struts的文档中找到了答案。看来以后学习新东西还是要从英文文档入手-_-</P><BR>
<P>理论上，商务罗基层应该包含数据链接的描述，包括数据库链接。但是一些早期的程序员习惯于在调用(caller)中包含数据库链接或者数据源实例。当你需要使用继承的设计时，struts数据源管理器可以在你使你的action类能够在你需要的时候生成这样的数据源。</P><BR>
<P>注意：默认情况下数据库链接是直接由商务逻辑的类来控制的，一般通过JNDI。struts数据源管理器应当仅由那些没有独立数据链接的业务逻辑的类继承得到。如果可能，极力推荐使用标准的DAO模式，这样业务逻辑层不需要知道任何数据库的细节。数据源管理器在struts1.x中仍然保留并向下兼容，但是在后续版本中可能不再被支持。</P><BR>
<P><STRONG></STRONG> </P>
<P></P><A name=more></A>
<P>
<P>这还不是问题的关键，如果要用数据库管理器，需要手动下载dbcp's BasicDataSource <A href="http://jakarta.apache.org/commons/dbcp/downloads.html">Commons DBCP</A>. </P><BR>
<P>并且1.2版本之后为了更好的配合BasicDataSource插件和别的数据库的执行，先前版本的struts通用数据源被移除了，这就是为什么1.2的lib里面没有struts-legacy.jar这个文件的原因了。</P><BR>
<P>以下是我成功的配置信息：</P><BR>
<P><data-sources><BR><!-- configuration for commons BasicDataSource --><BR><data-source type="org.apache.commons.dbcp.BasicDataSource"><BR>    <set-property<BR>      property="driverClassName"<BR>      value="com.mysql.jdbc.Driver" /><BR>    <set-property<BR>      property="url"<BR>      value="jdbc:mysql://localhost:3306/mysql?useUnicode=true&characterEncoding=UTF-8" /><BR>    <set-property<BR>      property="username"<BR>      value="root" /><BR>    <set-property<BR>      property="password"<BR>      value="yourpass" /><BR>    <set-property<BR>      property="maxActive"<BR>      value="10" /><BR>    <set-property<BR>      property="maxWait"<BR>      value="5000" /><BR>    <set-property<BR>      property="defaultAutoCommit"<BR>      value="false" /><BR>    <set-property<BR>      property="defaultReadOnly"<BR>      value="false" /><BR>    <set-property<BR>      property="validationQuery"<BR>      value="SELECT COUNT(*) FROM db" /><BR></data-source><BR></data-sources><BR>最后面那一行不是必需的，但是如果写上的话返回的结果及至少要有一条记录！</P><BR>
<P>mysql的jdbc也可以写成org.gjt.mm.mysql.Driver这样子。</P>]]&gt;<img src ="http://www.blogjava.net/qq13367612/aggbug/16213.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qq13367612/" target="_blank">Sung</a> 2005-09-19 16:28 <a href="http://www.blogjava.net/qq13367612/articles/16213.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>运用Jakarta Struts的七大实战心法</title><link>http://www.blogjava.net/qq13367612/articles/16219.html</link><dc:creator>Sung</dc:creator><author>Sung</author><pubDate>Sun, 18 Sep 2005 03:45:00 GMT</pubDate><guid>http://www.blogjava.net/qq13367612/articles/16219.html</guid><wfw:comment>http://www.blogjava.net/qq13367612/comments/16219.html</wfw:comment><comments>http://www.blogjava.net/qq13367612/articles/16219.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qq13367612/comments/commentRss/16219.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qq13367612/services/trackbacks/16219.html</trackback:ping><description><![CDATA[<P>编者按：当作者 Chuck Cavaness（著有《Programming Jakarta Struts》一书）所在的网络公司决定采用Struts框架之后，Chuck曾经花费了好几个月来研究如何用它来构建公司的应用系统。本文叙述的正是作者在运用Struts过程中来之不易的若干经验和心得。如果你是个负责通过jsp和servlet开发Web应用的Java程序员，并且也正在考虑采用基于Struts的构建方法的话，那么你会在这里发现很多颇有见地同时也很有价值的信息。</P>
<P><STRONG>1. 只在必要的时候才考虑扩展Struts框架</STRONG> <BR><BR>　　一个好的framework有很多优点，首先，它必须能够满足用户的可预见的需求。为此 Struts为Web 应用提供了一个通用的架构，这样开发人员可以把精力集中在如何解决实际业务问题上。其次，一个好的framework还必须能够在适当的地方提供扩展接口，以便应用程序能扩展该框架来更好的适应使用者的实际需要。<BR><BR>　　如果Struts framework在任何场合，任何项目中都能很好的满足需求，那真是太棒了。但是实际上，没有一个框架声称能做到这一点。一定会有一些特定的应用需求是框架的开发者们无法预见到的。因此，最好的办法就是提供足够的扩展接口，使得开发工程师能够调整struts来更好的符合他们的特殊要求。<BR><BR>　　在Struts framework中有很多地方可供扩展和定制。几乎所有的配置类都能被替换为某个用户定制的版本，这只要简单的修改一下Struts的配置文件就可以做到。<BR><BR>　　其他组件如ActionServlet和 RequestProcessor 也能用自定义的版本代替. 甚至连Struts 1.1里才有的新特性也是按照扩展的原则来设计的。例如，在异常处理机制中就允许用户定制异常处理的句柄，以便更好的对应用系统发生的错误做出响应。<BR><BR>　　作为框架的这种可调整特性在它更适合你的应用的同时也在很大的程度上影响了项目开发的效果。首先，由于您的应用是基于一个现有的成熟的、稳定的framework如Struts，测试过程中发现的错误数量将会大大减少，同时也能缩短开发时间和减少资源的投入。因为你不再需要投入开发力量用于编写基础框架的代码了。<BR><BR>　　然而, 实现更多的功能是要花费更大的代价的。我们必须小心避免不必要的滥用扩展性能， Struts是由核心包加上很多工具包构成的，它们已经提供了很多已经实现的功能。因此不要盲目的扩展Struts框架，要先确定能不能采用其他方法使用现有的功能来实现。 在决定编写扩展代码前务必要确认Struts的确没有实现你要的功能。否则重复的功能会导致混乱将来还得花费额外的精力清除它。<BR><BR><STRONG>2. 使用异常处理声明</STRONG><BR><BR>　　要定义应用程序的逻辑流程，成熟的经验是推荐在代码之外，用配置的方法来实现，而不是写死在程序代码中的。在J2EE中，这样的例子比比皆是。从实现EJB的安全性和事务性行为到描述JMS消息和目的地之间的关系，很多运行时的处理流程都是可以在程序之外定义的。<BR><BR>　　Struts 创建者从一开始就采用这种方法，通过配置Struts的配置文件来定制应用系统运行时的各个方面。这一点在版本1.1的新特性上得到延续，包括新的异常处理功能。在Struts framework以前的版本中，开发人员不得不自己处理Struts应用中发生的错误情况。在最新的版本中，情况大大的改观了，Struts Framework提供了内置的一个称为 ExceptionHandler 的类， 用于系统缺省处理action类运行中产生的错误。这也是在上一个技巧中我们提到的framework许多可扩展接口之一。<BR><BR>　　Struts缺省的 ExceptionHandler类会生成一个ActionError对象并保存在适当的范围（scope）对象中。这样就允许JSP页面使用错误类来提醒用户出现什么问题。如果你认为这不能满足你的需求，那么可以很方便的实现你自己的ExcepionHandler类。<BR><BR><STRONG>具体定制异常处理的方法和机制</STRONG><BR><BR>　　要定制自己的异常处理机制，第一步是继承org.apache.struts.action.ExceptionHandler类。这个类有2个方法可以覆盖，一个是excute()另外一个是storeException(). 在多数情况下，只需要覆盖其中的excute()方法。下面是ExceptionHandler类的excute()方法声明：<BR><BR></P>
<P class=code>public ActionForward execute( Exception ex, <BR>                              ExceptionConfig exConfig,<BR>                              ActionMapping mapping,<BR>                              ActionForm formInstance,<BR>                              HttpServletRequest request,<BR>                              HttpServletResponse response<BR>  ) throws ServletException;</P>
<P></P>
<P>　　正如你看到的，该方法有好几个参数，其中包括原始的异常。方法返回一个ActionForward对象，用于异常处理结束后将controller类带到请求必须转发的地方去。<BR><BR>　　当然您可以实现任何处理，但一般而言，我们必须检查抛出的异常,并针对该类型的异常进行特定的处理。缺省的，系统的异常处理功能是创建一个出错信息，同时把请求转发到配置文件中指定的地方去。 定制异常处理的一个常见的例子是处理嵌套异常。假设该异常包含有嵌套异常，这些嵌套异常又包含了其他异常，因此我们必须覆盖原来的execute()方法，对每个异常编写出错信息。<BR><BR>　　一旦你创建了自己的ExceptionHandler 类，就应该在Struts配置文件中的部分声明这个类，以便让Struts知道改用你自定义的异常处理取代缺省的异常处理. <BR><BR>　　可以配置你自己的ExceptionHandler 类是用于Action Mapping特定的部分还是所有的Action对象。如果是用于Action Mapping特定的部分就在<action>元素中配置。如果想让这个类可用于所有的Action对象,可以在<global-sections> 元素中指定。例如，假设我们创建了异常处理类CustomizedExceptionHandler用于所有的Action类, <global-exceptions>元素定义如下所示：<BR><BR></P>
<P class=code><global-exceptions><BR>  <exception<BR>    handler="com.cavaness.storefront.CustomizedExceptionHandler"<BR>    key="global.error.message"<BR>    path="/error.jsp"<BR>    scope="request"<BR>    type="java.lang.Exception"/><BR></global-exceptions></P>
<P>　　在<exception />元素中可以对很多属性进行设置。在本文中，最重要的属性莫过于handler属性, handler属性的值就是自定义的继承了ExceptionHandler类的子类的全名。 假如该属性没有定义，Struts会采用自己的缺省值。当然，其他的属性也很重要，但如果想覆盖缺省的异常处理的话，handler无疑是最重要的属性。<BR><BR>　　最后必须指出的一点是，你可以有不同的异常处理类来处理不同的异常。在上面的例子中，CustomizedExceptionHandler用来处理任何java.lang.Exception的子类. 其实，你也可以定义多个异常处理类，每一个专门处理不同的异常树。下面的XML片断解释了如何配置以实现这一点。<BR><BR></P>
<P class=code><global-exceptions><BR>  <exception<BR>    handler="com.cavaness.storefront.CustomizedExceptionHandler"<BR>    key="global.error.message"<BR>    path="/error.jsp"<BR>    scope="request"<BR>    type="java.lang.Exception"/><BR><BR>  <exception<BR>    handler="com.cavaness.storefront.SecurityExceptionHandler"<BR>    key="security.error.message"<BR>    path="/login.jsp"<BR>    scope="request"<BR>    type="com.cavaness.storefront.SecurityException"/><BR></global-exceptions></P>
<P>　　在这里，一旦有异常抛出，struts framework将试图在配置文件中找到ExceptionHandler，如果没有找到，那么struts将沿着该异常的父类链一层层往上找直到发现匹配的为止。因此，我们可以定义一个层次型的异常处理关系结构，在配置文件中已经体现了这一点。<BR><BR><STRONG>3. 使用应用模块（Application Modules）</STRONG><BR><BR>　　Struts 1.1的一个新特性是应用模块的概念。应用模块允许将单个Struts应用划分成几个模块，每个模块有自己的Struts配置文件，JSP页面，Action等等。这个新特性是为了解决大中型的开发队伍抱怨最多的一个问题，即为了更好的支持并行开发允许多个配置文件而不是单个配置文件。<BR><BR>　　注：在早期的beta版本中，该特性被称为子应用（sub-applications），最近的改名目的是为了更多地反映它们在逻辑上的分工。<BR><BR>　　显然，当很多开发人员一起参加一个项目时，单个的Struts配置文件很容易引起资源冲突。应用模块允许Struts按照功能要求进行划分，许多情况已经证明这样更贴近实际。例如，假设我们要开发一个典型的商店应用程序。可以将组成部分划分成模块比如catalog（商品目录）, customer（顾客）, customer service（顾客服务）, order（订单）等。每个模块可以分布到不同的目录下，这样各部分的资源很容易定位，有助于开发和部署。图1 显示了该应用的目录结构。 <BR><BR>图 1. 一个典型的商店应用程序的目录结构<BR><BR><IMG alt="" src="http://www.pconline.com.cn/pcedu/empolder/gj/java/0507/pic/05-07-18-Struts-1.jpg" border=0><BR><BR>　　注：如果你无需将项目划分成多个模块，Struts框架支持一个缺省的应用模块。这就使得应用程序也可以在1.0版本下创建，具有可移植性，因为应用程序会自动作为缺省的应用模块。<BR><BR>　　为了使用多应用模块功能，必须执行以下几个准备步骤：<BR><BR>　　• 为每个应用模块创建独立的Struts配置文件。<BR><BR>　　• 配置Web 部署描述符 Web.xml文件。<BR><BR>　　• 使用org.apache.struts.actions.SwitchAction 来实现程序在模块之间的跳转. <BR><BR><STRONG>创建独立的Struts配置文件<BR><BR></STRONG>　　每个Struts应用模块必须拥有自己的配置文件。允许创建自己的独立于其他模块的Action，ActionForm，异常处理甚至更多。<BR><BR>　　继续以上面的商店应用程序为例，我们可以创建以下的配置文件：一个文件名为struts-config-catalog.xml，包含catalog（商品目录）、items(商品清单)、和其它与库存相关的功能的配置信息；另一个文件名为struts- config-order.xml, 包含对order（订单）和order tracking（订单跟踪）的设置。第三个配置文件是struts-config.xml,其中含有属于缺省的应用模块中的一般性的功能。<BR><BR><STRONG>配置Web部署描述符</STRONG> <BR><BR>　　在Struts的早期版本中，我们在Web.xml中指定Struts配置文件的路径。好在这点没变，有助于向后兼容。但对于多个应用模块，我们需要在Web部署描述符中增加新的配置文件的设定。<BR><BR>　　对于缺省的应用（包括Struts的早期版本），Struts framework 在Web.xml文件中查找带有config的元素<init-param>，用于载入Action mapping 和其它的应用程序设定。作为例子，以下的XML片断展现一个典型的<init-param>元素：<BR><BR></P>
<P class=code><init-param><BR>   <param-name>config>/param-name><BR>   <param-value>/WEB-INF/struts-config.xml</param-value><BR></init-param></P>
<P>　　注：如果在现有的<init-param>元素中找不到"config"关键字，Struts framework将缺省地使用/WEB/struts-config.xml<BR><BR>　　为了支持多个应用模块(Struts 1.1的新特性)，必须增加附加的<init-param>元素。与缺省的<init-param>元素不同的是，附加的<init-param>元素与每个应用模块对应，必须以config/xxx的形式命名，其中字符串xxx代表该模块唯一的名字。例如，在商店应用程序的例子中，<init-param>元素可定义如下（注意粗体字部分）：</P>
<P></P>
<P class=code><init-param><BR>   <param-name>config</param-name><BR>   <param-value>/WEB-INF/struts-config.xml</param-value><BR></init-param><BR><init-param><BR>   <param-name>config/catalog</param-name><BR>   <param-value>/WEB-INF/struts-config.xml</param-value><BR></init-param><BR><init-param><BR>   <param-name>config/order</param-name><BR>   <param-value>/WEB-INF/struts-config.xml</param-value><BR></init-param></P>
<P></P>
<P>　　第一个 <init-param>元素对应缺省的应用模块。第二和第三个元素分别代表非缺省应用模块catalog 和 order。<BR><BR>　　当Struts载入应用程序时，它首先载入缺省应用模块的配置文件。然后查找带有字符串config/xxx 形式的附加的初始化参数。对每个附加的配置文件也进行解析并载入内存。这一步完成后，用户就可以很随意地用config/后面的字符串也就是名字来调用相应的应用模块。<BR><BR><STRONG>多个应用模块之间调用Action类</STRONG><BR><BR>　　在为每个应用模块创建独立的配置文件之后，我们就有可能需要调用不同的模块中Action。为此必须使用Struts框架提供的SwitchAction类。Struts 会自动将应用模块的名字添加到URL,就如Struts 自动添加应用程序的名字加到URL一样。应用模块是对框架的一个新的扩充，有助于进行并行的团队开发。如果你的团队很小那就没必要用到这个特性，不必进行模块化。当然，就算是只有一个模块，系统还是一样的运作。<BR><BR><STRONG>4. 把JSP放到WEB-INF后以保护JSP源代码</STRONG><BR><BR>　　为了更好地保护你的JSP避免未经授权的访问和窥视， 一个好办法是将页面文件存放在Web应用的WEB-INF目录下。<BR><BR>　　通常JSP开发人员会把他们的页面文件存放在Web应用相应的子目录下。一个典型的商店应用程序的目录结构如图2所示。跟catalog （商品目录）相关的JSP被保存在catalog子目录下。跟customer相关的JSP，跟订单相关的JSP等都按照这种方法存放。<BR><BR>图 2.基于不同的功能 JSP 被放置在不同的目录下<BR><IMG alt="" src="http://www.pconline.com.cn/pcedu/empolder/gj/java/0507/pic/05-07-18-Struts-2.jpg" border=0><BR><BR><BR>　　这种方法的问题是这些页面文件容易被偷看到源代码，或被直接调用。某些场合下这可能不是个大问题，可是在特定情形中却可能构成安全隐患。用户可以绕过Struts的controller直接调用JSP同样也是个问题。<BR><BR>　　为了减少风险，可以把这些页面文件移到WEB-INF 目录下。基于Servlet的声明，WEB-INF不作为Web应用的公共文档树的一部分。因此，WEB-INF 目录下的资源不是为客户直接服务的。我们仍然可以使用WEB-INF目录下的JSP页面来提供视图给客户，客户却不能直接请求访问JSP。<BR><BR><BR>　　采用前面的例子，图3显示将JSP页面移到WEB-INF 目录下后的目录结构<BR><BR>图 3. JSP存放在 WEB-INF 目录下更为安全<BR><IMG alt="" src="http://www.pconline.com.cn/pcedu/empolder/gj/java/0507/pic/05-07-18-Struts-3.jpg" border=0><BR><BR>　　如果把这些JSP页面文件移到WEB-INF 目录下，在调用页面的时候就必须把"WEB-INF"添加到URL中。例如，在一个Struts配置文件中为一个logoff action写一个Action mapping。其中JSP的路径必须以"WEB-INF"开头。如下所示： </P>
<P></P>
<P class=code><action<BR>  path="/logoff"<BR>  type="org.apache.struts.webapp.example.LogoffAction"><BR>  <forward name="success" path="/WEB-INF/jsp/index.jsp"/><BR></action></P>
<P>　　这个方法在任何情况下都不失为Struts实践中的一个好方法。是唯一要注意的技巧是你必须把JSP和一个Struts action联系起来。即使该Action只是一个很基本的很简单JSP，也总是要调用一个Action，再由它调用JSP。<BR><BR>　　最后要说明的是，并不是所有的容器都能支持这个特性。WebLogic早期的版本不能解释Servlet声明，因此无法提供支持，据报道在新版本中已经改进了。总之使用之前先检查一下你的Servlet容器。<BR><BR><STRONG>5. 使用 Prebuilt Action类提升开发效率</STRONG><BR><BR>　　Struts framework带有好几个prebuilt Action类，使用它们可以大大节省开发时间。其中最有用的是org.apache.struts.actions.ForwardAction 和 org.apache.struts.actions.DispatchAction.<BR><BR><STRONG>使用 ForwardAction<BR></STRONG><BR>　　在应用程序中，可能会经常出现只要将Action对象转发到某个JSP的情况。在上一点中曾提到总是由Action调用JSP是个好习惯。如果我们不必在Action中执行任何业务逻辑，却又想遵循从Action访问页面的话，就可以使用ForwardAction，它可以使你免去创建许多空的Action类。运用ForwardAction的好处是不必创建自己的Action类，你需要做的仅仅是在Struts配置文件中配置一个Action mapping。<BR><BR>　　举个例子，假定你有一个JSP文件index.jsp ，而且不能直接调用该页面，必须让程序通过一个Action类调用，那么，你可以建立以下的Action mapping来实现这一点：<BR></P>
<P class=code><action path="/home" parameter="/index.jsp" type="org.apache.struts.actions.ForwardAction" scope="request" validate="false"> </action></P>
<P>　　正如你看到的，当 /home 被调用时, 就会调用ForwardAction 并把请求转发到 index.jsp 页面.<BR><BR>　　再讨论一下不通过一个Action类直接转发到某个页面的情况，必须注意我们仍然使用<action>元素中的forward属性来实现转发的目标。这时<action>元素定义如下：</P>
<P></P>
<P class=code><action<BR>   path="/home"<BR>   forward="/index.jsp"><BR></action></P>
<P></P>
<P>　　以上两种方法都可以节省你的时间，并有助于减少一个应用所需的文件数。<BR><BR><STRONG>使用 DispatchAction</STRONG><BR><BR>　　DispatchAction是Struts包含的另一个能大量节省开发时间的Action类。与其它Action类仅提供单个execute()方法实现单个业务不同，DispatchAction允许你在单个Action类中编写多个与业务相关的方法。这样可以减少Action类的数量，并且把相关的业务方法集合在一起使得维护起来更容易。<BR><BR>　　要使用DispatchAction的功能，需要自己创建一个类，通过继承抽象的DispatchAction得到。对每个要提供的业务方法必须有特定的方法signature。例如，我们想要提供一个方法来实现对购物车添加商品清单，创建了一个类ShoppingCartDispatchAction提供以下的方法：</P>
<P class=code>public ActionForward addItem( ActionMapping mapping, <BR>                              ActionForm form,<BR>                              HttpServletRequest request,<BR>                              HttpServletResponse response)<BR>  throws Exception;</P>
<P>　　那么，这个类很可能还需要一个deleteItem()方法从客户的购物车中删除商品清单，还有clearCart()方法清除购物车等等。这时我们就可以把这些方法集合在单个Action类，不用为每个方法都提供一个Action类。<BR><BR>　　在调用ShoppingCartDispatchAction里的某个方法时，只需在URL中提供方法名作为参数值。就是说，调用addItem()方法的 URL看起来可能类似于：<BR><BR>http://myhost/storefront/action/cart?method=addItem<BR><BR>　　其中method参数指定ShoppingCartDispatchAction中要调用的方法。参数的名称可以任意配置，这里使用的"method"只是一个例子。参数的名称可以在Struts配置文件中自行设定。<BR><BR><STRONG>6.使用动态ActionForm<BR><BR></STRONG>　　在Struts framework中，ActionForm对象用来包装HTML表格数据（包括请求），并返回返回动态显示给用户的数据。它们必须是完全的JavaBean，并继承.Struts　里面的ActionForm类，同时，用户可以有选择地覆盖两个缺省方法。<BR><BR>　　该特性能节省很多时间，因为它可以协助进行自动的表现层的验证。ActionForm的唯一缺点是必须为不同的HTML表格生成多个ActionForm 类以保存数据。例如，如果有一个页面含有用户的注册信息，另一个页面则含有用户的介绍人的信息，那么就需要有两个不同的ActionForm类。这在大的应用系统中就会导致过多的ActionForm类。Struts 1.1对此做出了很好的改进，引入了动态ActionForm类概念<BR><BR>　　通过Struts framework中的DynaActionForm类及其子类可以实现动态的ActionForm ，动态的ActionForm允许你通过Struts的配置文件完成ActionForm的全部配置；再也没有必要在应用程序中创建具体的ActionForm类。具体配置方法是：在Struts的配置文件通过增加一个<form-bean>元素，将type属性设定成DynaActionForm或它的某个子类的全名。下面的例子创建了一个动态的ActionForm名为logonForm，它包含两个实例变量：username 和 password.<BR><BR></P>
<P class=code><form-bean<BR>  name="logonForm"<BR>  type="org.apache.struts.action.DynaActionForm"><BR>  <form-property name="username" type="java.lang.String"/><BR>  <form-property name="password" type="java.lang.String"/><BR></form-bean></P>
<P>　　动态的ActionForm可以用于Action类和JSP，使用方法跟普通的ActionForm相同，只有一个小差别。如果使用普通的ActionForm对象则需要提供get 和 set方法取得和设置数据。以上面的例子而言，我们需要提供getUsername() 和 setUsername()方法取得和设置username变量，同样地有一对方法用于取得和设置password变量.<BR><BR>　　这里我们使用的是DynaActionForm，它将变量保存在一个Map类对象中，所以必须使用DynaActionForm 类中的get(name) 和 set(name)方法，其中参数name是要访问的实例变量名。例如要访问DynaActionForm中username的值，可以采用类似的代码：<BR><BR></P>
<P class=code>　　String username = (String)form.get("username");<BR><BR></P>
<P>　　由于值存放在一个Map对象，所以要记得对get()方法返回的Object对象做强制性类型转换。<BR><BR>　　DynaActionForm有好几个很有用的子类。其中最重要的是DynaValidatorForm ，这个动态的ActionForm和Validator 一起利用公共的Validator包来提供自动验证。这个特性使你得以在程序代码之外指定验证规则。将两个特性结合使用对开发人员来说将非常有吸引力。<BR><BR><STRONG>7. 使用可视化工具</STRONG><BR><BR>　　自从Struts 1.0 分布以来，就出现了不少可视化工具用于协助创建，修改和维护Struts的配置文件。配置文件本身是基于XML格式，在大中型的开发应用中会增大变得很笨拙。为了更方便的管理这些文件，一旦文件大到你无法一目了然的时候，建议试着采用其中的一种GUI 工具协助开发。商业性的和开放源代码的工具都有不少，表1列出了可用的工具和其相关链接，从那里可以获取更多信息。<BR><BR>表 1. Struts GUI 工具</P>
<P>
<TABLE cellSpacing=1 cellPadding=1 width="100%" border=1>
<TBODY>
<TR>
<TD>应用程序</TD>
<TD>性质</TD>
<TD>网址</TD></TR>
<TR>
<TD>Adalon</TD>
<TD>商业软件</TD>
<TD><A href="http://www.synthis.com/products/adalon">http://www.synthis.com/products/adalon</A></TD></TR>
<TR>
<TD>Easy Struts</TD>
<TD>开放源码</TD>
<TD><A href="http://easystruts.sourceforge.net/">http://easystruts.sourceforge.net/</A></TD></TR>
<TR>
<TD>Struts Console</TD>
<TD>免费</TD>
<TD><A href="http://www.jamesholmes.com/struts/console">http://www.jamesholmes.com/struts/console</A></TD></TR>
<TR>
<TD>JForms</TD>
<TD>商业软件</TD>
<TD><A href="http://www.solanasoft.com/">http://www.solanasoft.com/</A> </TD></TR>
<TR>
<TD>Camino</TD>
<TD>商业软件</TD>
<TD><A href="http://www.scioworks.com/scioworks_camino.html">http://www.scioworks.com/scioworks_camino.html</A></TD></TR>
<TR>
<TD>Struts Builder</TD>
<TD>开放源码</TD>
<TD><A href="http://sourceforge.net/projects/rivernorth/">http://sourceforge.net/projects/rivernorth/</A></TD></TR>
<TR>
<TD>StrutsGUI</TD>
<TD>免费</TD>
<TD><A href="http://www.alien-factory.co.uk/struts/struts-index.html">http://www.alien-factory.co.uk/struts/struts-index.html</A></TD></TR></TBODY></TABLE><BR><BR><STRONG>相关资源</STRONG><BR><BR>　　要获取更为全面的Struts GUI 工具列表 (包括免费的和商业性的), 请访问 Struts resource page. </P><img src ="http://www.blogjava.net/qq13367612/aggbug/16219.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qq13367612/" target="_blank">Sung</a> 2005-09-18 11:45 <a href="http://www.blogjava.net/qq13367612/articles/16219.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>struts学习问答</title><link>http://www.blogjava.net/qq13367612/articles/16220.html</link><dc:creator>Sung</dc:creator><author>Sung</author><pubDate>Sun, 18 Sep 2005 03:21:00 GMT</pubDate><guid>http://www.blogjava.net/qq13367612/articles/16220.html</guid><wfw:comment>http://www.blogjava.net/qq13367612/comments/16220.html</wfw:comment><comments>http://www.blogjava.net/qq13367612/articles/16220.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qq13367612/comments/commentRss/16220.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qq13367612/services/trackbacks/16220.html</trackback:ping><description><![CDATA[<P>1 JSP Framework - Struts介绍 <BR>Struts是采用Java Servlet/JavaServer Pages技术，开发Web应用程序的开放源码的framework。 <BR><BR>采用Struts能开发出基于MVC(Model-View-Controller)设计模式的应用构架。 <BR><BR>Struts有如下的主要功能： <BR><BR>1. 包含一个controller servlet，能将用户的请求发送到相应的Action对象。 <BR><BR>2. JSP自由tag库，并且在controller servlet中提供关联支持，帮助开发员创建交互式表单应用。 <BR><BR>3. 提供了一系列实用对象：XML处理、通过Java reflection APIs自动处理JavaBeans属性、国际化的提示和消息。 <BR><BR>Struts是Jakarta项目的一部分，主页在http://jakarta.apache.org/struts. <BR><BR>Version 0.5的下载地址：http://jakarta.apache.org/builds/jakarta-struts/release/v0.5 <BR><BR><BR>1.1 1、什么是MVC模式。 <BR>MVC(Model/View/Controller)模式是国外用得比较多的一种设计模式，好象最早是在Smaltalk中出现。MVC包括三类对象。Model是应用对象，View是它在屏幕上的表示，Controller定义用户界面对用户输入的响应方式。 <BR><BR>1.2 2、是否所有JSP应用都该采用MVC模式？ <BR>不一定所有的JSP应用都该采用MVC模式。但对于大型应用来说，我认为还是该采用MVC模式。不使用MVC模式，用户界面界面设计往往将这些对象混在一起，而MVC则将它们分离以提高灵活性和复用性。 <BR><BR>1.3 3、Struts中能做XML吗，与Cocoon相比有何优点？ <BR>Struts把主要精力放在JSP上了。Cocoon才是专业级的XML Framework。 <BR><BR><BR>2. Struts的安装 <BR>2.1 安装Struts需要的软件 <BR><BR>Java Development Kit - 你需要download和install 1.2(或之后)版本的JDK。下载地址：http://java.sun.com/j2se <BR>Servlet Container - 通常的选择是下载Tomcat(至少是3.1版，推荐使用3.2版)。下载地址：http://jakarta.apache.org/tomcat <BR>Ant Build System - 如果你通过Struts源码发布包安装，你必须下载1.1或之后版本的ant build system。在你通过Struts来开发你自己的Web应用程序是，我也推荐使用ant来build你的应用。下载地址：http://jakarta.apache.org/ant <BR>Servlet API Classes - 为了编译Structs自己，或应用程序使用Struts，你需要一个包含Servlet和JSP API对象的servlet.jar包。大多数Servlet container（例如Tomcat)已经自带了这个文件。否则，你必需下载：http://jakarta.apache.org/builds/jakarta-servletapi <BR>XML Parser - Structs需要一个与Java API for XML Parsing(JAXP)规格兼容的XML处理器。我推荐使用Xerces。下载地址：http://xml.apache.org/xerces-j <BR>Xalan XSLT Processor - 如果你通过Structs源码发布版来构造你的Structs系统，你必须下载和安装1_2_D01或之后版本的Xalan XSLT处理器(Xerces中已自带Xalan)。这个处理器用于将基于XML的Structs文档转换为Html文档。 <BR><BR><BR><BR>2.2 通过源码构造Structs <BR><BR>1.下载Structs的源码发布包。 <BR>2.设置ANT_HOME环境变量，指向你的Ant目录。 <BR>3.设置JAVA_HOME环境变量，指向你的JDK目录。 <BR>4.设置SERVLETAPI_HOME环境变量，指向你的Servlet API目录（如果你的CLASSPATH已经包含了servlet.jar，就不需要指定该目录） <BR>5.将Structs的源码发布包进行解包。 <BR>6.进入Structs目录，运行以下命令： <BR>./build.sh dist <BR>该命令将创建Struts的二进制发布包，目录在../dist/structs(相对于你的编译目录）。 <BR><BR><BR><BR>2.3 通过Struts的二进制发布包安装Structs <BR><BR>1.下载Struts的二进制发布版。 <BR>2.将Struts的二进制发布版进行解包。(如果你是通过Struts源码构造Struts，build的结果就已经是已解包的Struts)。解包后的Struts包含以下内容： <BR>lib/struts.jar - 这个文件包含了Struts的所有Java对象。你需要把它拷贝到你的Web应用的WEB-INF/lib目录。 <BR>lib/structs.tld - 这是一个"tag library descriptor"文件，它描述了Struts库的自由tag。需要将它拷贝到你的Web应用的WEB-INF目录。 <BR>webapps/struts-documentation.war - 这是一个"web application archive"文件，包含了所有的Struts文档。你可以将它安装到支持Servlet API 2.2或之后版本的servlet container(推荐使用tomcat)中。 <BR>webapps/struts-example.war - 这是一个web应用实例，它广泛地演示了Struts的许多功能。你可以将它安装到兼容Servlet2.2或之后版本以及JSP1.1或之后版本规范的servlet容器中(推荐使用tomcat)。 <BR>webapps/struts-test.war - 这个web应用包含了Struts支持的许多tag的测试网页，可以作为使用Struts tag的例子。 <BR><BR>可通过以下的步骤在你自己的应用程序中使用Struts： <BR>1.将Struts目录的lib/struts.jar拷贝到web应用的WEB-INF/lib目录。<BR>2.将Struts目录的lib/struts*.tld拷贝到web应用的WEB-INF目录。 <BR>3.修改Web应用目录的WEB-INF/web.xml文件，增加一个<SERVLET>元素来定义controller servlet，增加一个<SERVLET-MAPPING>元素来建立URI请求与servlet的对应关系。可以参照Struts例子中的WEB-INF/web.xml文件来了解详细的语法要求。 <BR>4.修改Web应用目录的WEB-INF/web.xml文件，使之包含以下的tag库定义： <BR><TAGLIB><BR><TAGLIB-URI>/WEB-INF/struts.tld</TAGLIB-URI> <BR><TAGLIB-LOCATION>/WEB-INF/struts.tld</TAGLIB-LOCATION> <BR></TAGLIB><BR><TAGLIB><BR><TAGLIB-URI>/WEB-INF/struts-bean.tld</TAGLIB-URI> <BR><TAGLIB-LOCATION>/WEB-INF/struts-bean.tld</TAGLIB-LOCATION> <BR></TAGLIB><BR><TAGLIB><BR><TAGLIB-URI>/WEB-INF/struts-logic.tld</TAGLIB-URI> <BR><TAGLIB-LOCATION>/WEB-INF/struts-logic.tld</TAGLIB-LOCATION> <BR></TAGLIB><BR>5.创建一个WEB-INF/action.xml文件来定义你的web应用的action映射关系。可以参照Struts例子中的action.xml文件来了解详细的语法要求。 <BR>6.在使用Struts tag库的JSP网页中加入以下tag库定义： <BR><@ taglib uri="/WEB-INF/struts.tld" prefix="struts" %> <BR><@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %> <BR><@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %> <BR>7.最后，在编译你的web应用的java程序时，不要忘了在CLASSPATH中包含struts.jar文件</P><img src ="http://www.blogjava.net/qq13367612/aggbug/16220.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qq13367612/" target="_blank">Sung</a> 2005-09-18 11:21 <a href="http://www.blogjava.net/qq13367612/articles/16220.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Struts的几个精细之处</title><link>http://www.blogjava.net/qq13367612/articles/16247.html</link><dc:creator>Sung</dc:creator><author>Sung</author><pubDate>Fri, 09 Sep 2005 06:55:00 GMT</pubDate><guid>http://www.blogjava.net/qq13367612/articles/16247.html</guid><wfw:comment>http://www.blogjava.net/qq13367612/comments/16247.html</wfw:comment><comments>http://www.blogjava.net/qq13367612/articles/16247.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qq13367612/comments/commentRss/16247.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qq13367612/services/trackbacks/16247.html</trackback:ping><description><![CDATA[<A name=1><B>精细之处一：“利用Token解决重复提交”背后的前提</B></A> <BR><BR>我们知道，可以利用同步令牌（Token）机制来解决Web应用中重复提交的问题，Struts也给出了一个参考实现。服务器端在处理到达的请求之前，会将请求中包含的令牌值与保存在当前用户会话中的令牌值进行比较，看是否匹配。在处理完该请求后，且在答复发送给客户端之前，将会产生一个新的令牌，该令牌除传给客户端以外，也会将用户会话中保存的旧的令牌进行替换。这样如果用户回退到刚才的提交页面并再次提交的话，客户端传过来的令牌就和服务器端的令牌不一致，从而有效地防止了重复提交的发生。对应于这段描述，你可能会在你的Action子类中有这么一段代码： <BR><BR><CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE>if (isTokenValid(request, true)) {
	// your code here
return mapping.findForward("success");
} else {
saveToken(request);
return mapping.findForward("submitagain");
}</CCID_CODE></PRE></TD></TR></TBODY></TABLE></CCID_NOBR><BR><BR>其中isTokenValid()和saveToken()都是org.apache.struts.action.Action类中的方法，而具体的Token处理逻辑都在org.apache.struts.util.TokenProcessor类中。Struts中是根据用户会话ID和当前系统时间来生成一个唯一（对于每个会话）令牌的，具体实现可以参考TokenProcessor类中的generateToken()方法。 <BR><BR>不知道大家有没有注意到这样一个问题，因为Struts是将Token保存在Session的一个属性中，也就是说对于每个会话服务器端只保存而且只能保存一个最新Token值。对于这一点，我的同事就提出了疑问：那如果我在同一个会话中打开两个页面，那么后提交的那个页面肯定不能提交成功了。他还给出了一个实际的例子：比如现在需要把两个客户A和B的地址都改为某个值，那用户就可能同时打开两个页面，修改A，修改B，提交A，提交B，按照Struts中的处理逻辑，B的修改提交就肯定不能成功，但是这个提交操作对于用户来说并不存在操作不正确的地方。 <BR><BR>在这里，可能有人要问：怎么可能在同一个会话中打开两个页面呢？重新打开一个IE浏览器不是重新开始了一个会话吗？不错，这种情况下是两个会话，不存在任何问题。但是，你还可以通过菜单“文件”－“新建”－“窗口”（或者快捷键Ctrl+N）来复制当前窗口，这个时候你会发现该页面与原有页面同处在一个会话当中。其实，能够发现这个问题得归功于我的那位同事对IE习惯性的操作方法。 <BR><BR>这下我的那位同事不满意啦，他于是开始动手修改Struts中的实现方式，让每个页面（至少某类页面）在服务器端都保存有一个唯一的Token值。这样，前面所讲的客户A，B同时修改的限制就不存在了。但是不久，我的那位同事就开始意识到他正在走向一条危险的道路。首先，如果每个页面都在服务器端保存一个Token值，则服务器端保存的数据量将越来越大。而且，如果考虑这种同一个会话中打开多个页面的情况的话，就好像打开了潘多拉魔盒，将会给自己带来无穷无尽的麻烦。比如，首先打开页面P1，然后利用Ctrl+N得到页面P2，P1提交，P2提交，目前为止一切正常。但是如果此时，在P1，P2中点击“后退”按钮，然后再提交P1， P2呢，情况会是怎样？如果在P2中提交完后执行其它操作，而在P1中回退后提交，情况又是怎么样呢？如果有P1，P2，P3，那情况又是如何呢？太复杂啦！我想你也会和我们有同感，你需要考虑许多种可能的组合，而且有的时候结果并不是你想象中的那样简单。 <BR><BR>此路不通，还得回来看看Struts。其实经过以上一番折腾，我们可以发现在Struts中的Token机制背后隐藏着这样一个前提：不允许你（客户端）在同一会话中打开多个页面。注意是同一会话，如果打开两个IE浏览器，那已经是两个会话啦，不受该限制。其实，这个看似不合理的规定却自有其道理：一是它极大地简化了Token的实现，二个这种限定也符合大部分人的使用习惯。 <BR><BR><A name=2><B>精细之处二：页面流转控制中的职责分配</B></A> <BR><BR>我们知道，Struts的执行过程大致如下：首先，控制器接收到客户端请求，将这些请求映射至相应的Action，并调用Action的execute方法，这中间可能还涉及到ActionForm的创建和填充。Action的execute方法执行完以后，返回一个ActionForward对象，控制器根据该ActionForward对象将请求转发至下一个Action或JSP。最后，产生视图响应客户。在大的层面上，Struts是采用了MVC这种架构，没什么特别之处。但从一些小的地方，我们还是可以看出Craig R. McClanahan老兄的一些考虑。我们看到Action与控制器之间传递的是ActionForward对象，由于Action的execute方法要求返回一个ActionForward对象，所以你会经常在Action子类中看到如下语句： <BR><BR><CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE>return (new ActionForward(mapping.getInput()));</CCID_CODE></PRE></TD></TR></TBODY></TABLE></CCID_NOBR><BR><BR>或 <BR><BR><CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE>return (mapping.findForward("success"));</CCID_CODE></PRE></TD></TR></TBODY></TABLE></CCID_NOBR><BR><BR>其实返回的就是一个ActionForward对象。在Action中我们根据程序执行的不同情况，决定接下来的页面走向（比如返回到输入页面或者转到下一个页面），并将这些信息保存在ActionForward对象中。而接下来控制器就可以直接利用该ActionForward对象来进行页面的流转。下面是org.apache.struts.action.RequestProcessor类的processForwardConfig()方法的摘录，该方法调用发生在Action实例调用后。 <BR><BR><CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE>protected void processForwardConfig(HttpServletRequest
                                        request,
                                        HttpServletResponse
                                        response,
                                        ForwardConfig forward)
        throws IOException, ServletException {
        …
        
        String forwardPath = forward.getPath();
        String uri = null;
                
             // paths not starting with / 
                 should be passed through without any  processing
            // (ie. they're absolute)
        if (forwardPath.startsWith("/")) {
            uri = RequestUtils.forwardURL(request, forward);
    // get module relative uri
        } else {
            uri = forwardPath;
        }
                if (forward.getRedirect()) {
            // only prepend context path for relative uri
            if (uri.startsWith("/")) {
                uri = request.getContextPath() + uri;
            }
            response.sendRedirect(response.encodeRedirectURL(uri));
                    }
 else {
            doForward(uri, request, response);
        }
    }</CCID_CODE></PRE></TD></TR></TBODY></TABLE></CCID_NOBR><BR><BR><B>注意：</B> ForwardConfig是ActionForward的父类 <BR><BR>该方法首先调用ForwardConfig的getPath()方法获得下一步流转的路径，在某些条件下还需要进行一些拼装得到正确的URI，最后根据该URI进行页面跳转。可见在processForwardConfig()方法中只是对ActionForward进行了一些“技术上”的处理，没有任何和业务相关的内容，这样就将控制器（ActionServlet）和Action完全分开来，两者互不影响，达到了功能模块之间松散耦合的目的。 <BR><BR>模块间（系统间）松散耦合一直是OO设计所追求的，但是具体如何去实现这样一种松散耦合却不是那么容易做到的。Struts中的设计给了我们一些启示：模块间相互关联影响因素的传递可以用对象的形式来包装起来。其实，个人觉得Struts中的做法还可以稍微有一点点改进，就是在ActionForward中提供一个getURI()方法来给出最终的URI岂不是更好？ <BR><![CDATA[<A name=1><img src ="http://www.blogjava.net/qq13367612/aggbug/16247.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qq13367612/" target="_blank">Sung</a> 2005-09-09 14:55 <a href="http://www.blogjava.net/qq13367612/articles/16247.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一个掌握Struts企业级Web开发框架的实例</title><link>http://www.blogjava.net/qq13367612/articles/16257.html</link><dc:creator>Sung</dc:creator><author>Sung</author><pubDate>Fri, 09 Sep 2005 06:00:00 GMT</pubDate><guid>http://www.blogjava.net/qq13367612/articles/16257.html</guid><wfw:comment>http://www.blogjava.net/qq13367612/comments/16257.html</wfw:comment><comments>http://www.blogjava.net/qq13367612/articles/16257.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/qq13367612/comments/commentRss/16257.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qq13367612/services/trackbacks/16257.html</trackback:ping><description><![CDATA[<P align=left>Struts是源代码开放的企业级Web应用开发框架，它的设计目的是从整体上减轻构造企业Web应用的负担。本文通过一个Struts应用的实例，帮助你迅速掌握Struts。</P>
<P>　　Struts是在Jakarta项目下开发的源代码开放软件，由一系列的框架类、辅助类和定制的JSP标记库构成，定位在基于Model 2设计模式的J2EE应用开发。Model 2体系是MVC（Model-View-Controller）体系的一种应用。在MVC体系中，数据模型（Model）、表现逻辑（View）和控制逻辑（Controller）是分离的组件，但它们可以互相通信。Struts力图从整体上减轻构造企业级Web应用的负担，并提供国际化和数据库连接池支持。</P>
<P>　　Struts体系可以看成两个相对独立的部分：第一个部分是Struts API，用于编写支持Struts的应用组件；第二部分是Struts的JSP标记库，由html、bean、logic和template四个标记组成。Struts的两个部分有着各自不同的用户。对于规模较小的项目，同一个用户可能同时使用这两个部分；但对于规模较大的项目，通常开发者使用API组件，而负责HTML页面布局的人使用标记库。</P>
<P>　　Struts的设计目标是为Model 2 Web应用开发提供一个强大的框架。同时，Struts还包含了一些实用组件，例如Digest，但这些组件并不从属于上面提到的两个部分。</P>
<P><FONT color=#ff0000>Struts应用的体系结构</FONT></P>
<P>　　对于从传统编程环境转入Web开发的人来说，Web编程中令人很不习惯的一个特点是缺乏“程序”。传统的应用总是有主入口点、流程控制和出口点。但在Web网站上，用户可能从任何地方进入，按照一种完全随机的次序访问各个页面，甚至可能跳过多个页面，也可能在一、两个小时内毫无动静。这是HTTP访问的基本特征，无论是Struts还是其他Web编程框架，都无法改变这一点。然而，Struts能够隐藏Web访问固有的“混乱”，帮助开发者建立起清晰和明确的秩序和规则。</P>
<P>　　在Struts应用中，有一个称为ActionServlet的主调度程序（或称为分配器），如图1所示。不过，并非所有的请求都必须通过ActionServlet。用户的请求目标可以是非Struts的页面，也可以是那些使用了Struts标记库但不使用Struts请求分配服务的页面。这正是Struts体系的优点之一：按需使用。许多编程框架要求你要么不用，要么全部使用，而且一旦你决定使用，以后要悔改从前的错误就会付出高昂的代价。Struts按需使用的优点与这类系统形成了强烈对比。</P>
<P align=center>　　 <IMG height=145 src="http://www.sawin.cn/doc/CASE/TechSample/Struts1-1.gif" width=400 border=0></P>
<P align=center>　　图1 Struts框架中的请求处理</P>
<P>　　Struts应用由下面这些基本模块构成：</P>
<P>　　1.配置信息;</P>
<P>　　2.Servlet，主要是Struts的ActionServlet;</P>
<P>　　3.动作类（Action），执行逻辑和控制（请求分配）功能，它们由ActionServlet调用；</P>
<P>　　4.JSP页面（属于View），常常通过动作类分派；</P>
<P>　　5.JSP标记库，根据需要使用；</P>
<P>　　6.各种形式的JavaBean，包括用户定义的JavaBean。</P>
<P>　　典型的Struts应用要用到三种配置文件：web.xml、struts-config.xml和可选的应用资源文件。</P>
<P>　　web.xml是Web应用的标准配置文件，是所有J2EE Web应用必需的组成部分。应用服务器通过该配置文件把URL映射到Servlet和JSP，通过该配置文件为Servlet和JSP指定启动参数。为Struts应用提供的基本web.xml文件很简单，真正必需的只有一个主ActionServlet定义，以及一个确保Struts请求传递到ActionServlet的映射。按照惯例，以“.do”结尾的URL都是Struts请求，例如/login.do。应用服务器利用web.xml文件中的映射，把该请求传递给ActionServlet。接着，ActionServlet决定如何分配该请求。ActionServlet的决定依据是struts-config.xml中定义的规则，和/或是通过ActionServlet派生类额外定义的分配逻辑。</P>
<P>　　struts-config.xml称为Struts配置文件。Struts应用是一个依靠struts-config.xml文件把组件连接起来的网络。struts-config.xml文件为Web应用的组件定义了逻辑名称，也定义了它们在Struts框架下的属性和关系，就像web.xml文件在Web应用框架之内定义组件一样。struts-config.xml文件包含了与Struts框架有关的应用信息，这些信息分四个类：</P>
<P>　　1.数据源信息，它是可选的。在这里可以指定一个或者多个JDBC数据源，使得数据库定义信息集中化。对于数据库访问，Struts还有一个额外的优点，即支持基本的数据库连接池功能。</P>
<P>　　2. Form Bean是JavaBean的一种特殊类型，它简化了Web表单的处理。</P>
<P>　　3. Global Forwards是全局性的转发定义信息。Struts动作按照一种“请求—转发”机制运行。为了最大限度地分　　离动作模块与转发目标，这里使用了一种映射机制，允许通过同义词引用转发目标。一些目标页面可能被多个动作类引用，例如登录页面，因此可以在全局转发定义部分把逻辑目标页面映射到物理目标页面，避免把这部分信息加入到动作定义部分。</P>
<P>　　4. Actions定义了Struts应用体系的请求分配信息，它们是核心分配器的补充定义，负责处理各种具体的请求类型。</P>
<P><FONT color=#ff0000>一个简单的应用</FONT></P>
<P>　　基于Struts的Web应用和普通Web应用有着许多同样的要求，但Struts应用也有自己特殊的需求。一个可部署的Web应用应该可组织和构成一个WAR文件。WAR文件是带有图2所示目录结构的JAR包。对于Struts Web应用来说，Web-INF目录下还要加上一些额外的文件，例如struts-confg.xml文件和标记库描述器（TLD）文件。注意：应用的资源应该放入应用的类路径下，也就是Web-INF/lib目录或Web-INF/class目录下的JAR包内。对于大多数简单的Struts页面，我们只用到Struts标记库，而按照MVC的术语就不需要涉及Model和Controller部分，只涉及View。请看图3所示的主页例子。虽然这个页面没有表单，但Struts仍能够在设计这类页面时提供帮助。</P>
<P align=center><IMG height=92 src="http://www.sawin.cn/doc/CASE/TechSample/Struts1-2.gif" width=400 border=0></P>
<P align=center>　　图2 Struts应用的目录结构</P>
<P align=center><IMG height=161 src="http://www.sawin.cn/doc/CASE/TechSample/Struts1-3.gif" width=300 border=0></P>
<P align=center>　　图3 一个简单的View</P>
<P>　　要管理会话，最简单的途径是使用Cookie。会话标识符被传递到客户端之后，客户端把它保存到Cookie，以后的每次请求就把Cookie发送到服务器。然而，和其他的许多Web解决方案一样，Cookie方案也不是万能的，因为一些用户可能不信任Cookie，关闭浏览器的Cookie支持。由于这种情况，URL改写技术就出现了。使用URL改写技术时，整个网站的所有URL后面都将加上会话标识符。虽然这个方案不像采用Cookie方案那样简单、稳固，但它确实行得通。URL改写技术的不稳固是有两方面的原因。首先，和Cookie不同，URL没有过期时间，如果一个带有会话标识的URL被截取后又重新在以后的访问中使用，那么这种URL不会很有用，因为会话一般在一定的时间后会被作废。其次，如果有一个URL链接的后面没有带上会话标识符，整个链都会中断，客户程序无法再次获取会话标识符，除非它备份了带有会话标识符的URL访问历史。</P>
<P>　　Servlet能够只通过一次方法调用完成URL改写。从技术上讲，JSP也一样能够办到这一点，但一个好的JSP页面应该不包含Java代码，或包含尽量少的Java代码。为此，Struts提供了一个链接标记。本例使用了该标记来维持客户端和服务器之间的会话状态信息。</P>
<P><FONT color=#ff0000>绑定View、Model和Controller</FONT></P>
<P>　　前面的简单页面不需要Struts分配器，因为它只有简单的链接。图4显示了一个比较复杂的“类别”页面。它列举出了数据库中的类别条目，并将这些条目分别链接到对应的编辑页面。为显示这个页面，我们就要用到Struts的ActionServlet分配机制。</P>
<P align=center><IMG height=200 src="http://www.sawin.cn/doc/CASE/TechSample/Struts1-4.gif" width=300 border=0></P>
<P align=center>　　图4 类别页面</P>
<P>　　在web.xml文件中，放入一项表示所有以“.do”结尾的URL请求必须发送给Struts分配器的声明。这里的分配器可以是org.apache.struts.action.ActionServlet或其扩展类。Struts分配器在启动时读取struts-config.xml文件，并构造出一个动作映射图。本例指定了一个名为ShowCategories的动作类，来处理“ShowCategories”动作。可以看出，Struts应用的基本工作模式是：主分配器调用一个动作分配器，动作分配器确定或构造出Model部分（一个JavaBean或其它Java对象），并把它提供给View（通常是一个JSP页面）。</P>
<P>　　本例使用Bean的情况稍微有点复杂，它有多个数据项，因此我们不是使用单个提供数据的Bean，而是要生成一组Bean。遗憾的是，JSP页面以HTML为基础，HTML没有提供循环或其他控制逻辑。不过，Struts的logic:iterate允许对数组进行迭代操作，如下面的代码片断所示：</P>
<P>&lt;table&gt;<BR>&lt;logic:iterate id="category"<BR>type="com.strutsdemo.Category"<BR>name="&lt;%= Constants.CATALOG_CATEGORIES %&gt;"<BR>scope="application"&gt;<BR>&lt;tr&gt;<BR>&lt;td&gt;<BR>&lt;html:link page="/editCategory.do"<BR>name="category"<BR>property="mapping"&gt;<BR>编辑<BR>&lt;/html:link&gt;<BR>&lt;html:link page="/removeCategory.do"<BR>name="category"<BR>property="mapping"&gt;<BR>删除<BR>&lt;/html:link&gt;<BR>&lt;bean:write name="category"<BR>property="category"/&gt;<BR>&lt;/td&gt;<BR>&lt;/tr&gt;<BR>&lt;/logic:iterate&gt;<BR>&lt;/table&gt;</P>
<P><BR>　　上面讨论了Model 2体系的Model和View部分，下面来看看Controller部分。Struts体系有一个主控制器，即ActionServlet。ActionServlet负责选择和调用合适的动作控制器—即org.apache.struts.action.Action的扩展类。动作控制器实现了process()方法。process()方法分析从URL请求传入的每一个参数，执行必要的业务逻辑，并返回一个指定了调用链中下一个链接的动作（通常是View）。在本例中，我们想要从数据库提取数据，创建管理这些数据的JavaBean，把多个JavaBean整理成一个数组，再把数组保存到请求的上下文，从而使得作为View的JSP页面能够方便地进行页面布局。</P>
<P>为保证上述操作顺利进行，在struts-config.xml文件中加入声明，指定由哪一个动作处理器来处理指定的动作：</P>
<P>&lt;action path="/showCategories"<BR>scope="request"<BR>type="com.strutsdemo.ShowCategoriesAction"<BR>unknown="false"<BR>validate="false"&gt;<BR>&lt;forward name="viewCategories" path="/<BR>ShowCategories.jsp"/&gt;<BR>&lt;/action&gt;<BR></P>
<P><FONT color=#ff0000>表单处理</FONT></P>
<P>　　表单处理过程充分体现出Struts的优势。在Web应用中，大部分复杂的HTML处理任务都涉及到表单。表单编辑过程具有类似图5所示的请求或应答结构。更新操作的过程与创建操作的过程相似，但对于更新操作来说，“创建Model”这一步骤变成“装入Model”，而“保存Model”变成了“更新Model”。请注意Web应用的特点：操作过程随时可能中止，这既可能是因为用户通过显式的动作取消了当前的操作，也可能是因为用户没有提交表单，例如用户跳转到了一个不是用来处理当前表单的URL。</P>
<P align=center>　　 <IMG height=107 src="http://www.sawin.cn/doc/CASE/TechSample/Struts1-5.gif" width=400 border=0></P>
<P align=center>　　图5 表单处理流程</P>
<P>　　表单编辑过程分三个阶段：这里分别称之为准备（Preparation）、表现（Presentation）和存储（Preservation）。准备和存储阶段都属于Struts动作，而表现阶段主要是客户端的活动。表1显示了该过程中涉及的各种部件：</P>
<P>　　表单Bean（Form Bean）是一种特殊的JavaBean类型，它简化了表单处理。Form Bean从org.apache.struts. action.ActionForm类扩展而来。Form Bean有几个有用的特点，例如，通过reset()方法可以把Bean的属性设置成默认值，通过validate()方法让Bean验证属性的合法性。更重要的是，ActionServlet确保Form Bean被创建且可供它的动作方法调用。HTML标记库还能够确保Form Bean被正确地初始化并从Form View获取数据。</P>
<P>　　Form Bean应当属于Model部分，然而，由于它有validate()方法，因此从某些特征来看它更接近分配器。不过，不必太在乎这些概念上的问题。Model 2并不完全等同于MVC，而且一些人已经在责难MVC不外乎是几种简单设计模式的混合物。不管怎样，从应用实践的角度来讲，系统的稳定性远比概念的严格性更重要。在本例中，这个问题更加富有代表性，因为我们把持久化机制也包装到Form Bean里面。从技术上看，Bean数据的持久化副本就是一个View，因此，从这个意义上来讲，我们现在有了一个结合了分配器和View特点的Model。这种设计方式看起来似乎否定了引入Struts之类框架的理由，但实际上，这种设计方式两方面的特点弥补了许多遗憾。</P>
<P>　　首先，由于验证代码和SQL代码在很大程度上依赖于Form Bean拥有的属性，所以把它们作为一个单元管理会带来很大的方便。由于这里只对Form Bean的属性感兴趣，“重量级”的分配器和View部件都得到了有效的隔离。其次，Form Bean与HTML标记库一起使用时，Form Bean可以包含其他对象。这些对象可以通过“.”符号应用。使用预定义的Java对象时，“.”引用方式能够带来很大的方便，因为Java不支持多重继承。“.”引用方式避免了手工编写大量get/set代码的繁杂工作。</P>
<P>　　当内部对象是EJB时，“.”引用方式带来的方便更加突出，因为在JSP页面中引用EJB时，EJB往往显得很“笨重”。如果EJB嵌入到了Form Bean里面，许多这方面的遗憾就不再存在。更重要的是，它分离了Controller和Model，而且View持久化也简缩到了最简单的程度，因为EJB容器可以处理所有持久化方面的细节。这样，Form Bean就几乎成了一个纯粹的分配器，一切都变得整洁和清晰。</P>
<P>　　如果EJB有大量的属性，而且按照ActionServlet通常对Form Bean所做的那样，按照每个属性分别更新的方式进行更新，就会出现大量的RMI调用开销。对于要求较高的应用，更好的选择是利用EJB 2.0本地接口，或者在EJB之前加上一个传统的JavaBean（通常是会话EJB），并把该Bean传递给实体Bean的UpdateAllProperties()业务方法。后面这种方案允许在单个RMI调用中完成所有的更新操作。</P>
<P><FONT color=#0000ff>准备阶段</FONT></P>
<P>　　一次典型的编辑会话要求有一个动作处理器准备View，即一个作为View的JSP页面，还要求有第二个动作处理器存储更新后的View。当然，存储操作之后会有第二个属于View的页面被显示，例如一个“数据已经更新，点击此处继续”的页面（参见表1）。</P>
<P>　　 表1：基于Form Bean的编辑过程要用到的部件</P>
<P>部件 　　　　　　　　　　　　说明<BR>CatalogForm 　　　　　　　Form Bean<BR>EditCategoryAction 　　　准备阶段<BR>EditCategory.jsp 　　　　编辑<BR>SaveCategoryAction 　　　存储阶段<BR>EditDone.jsp 　　　　　　确认数据已经保存<BR>EditFailed.jsp 　　　　　“数据没有保存”错误</P>
<P><BR>　　下面的代码片断显示了如何在struts-config.xml文件中配置准备阶段：</P>
<P>&lt;action path="/editCategory"<BR>scope="request"<BR>name="catForm"<BR>type="com.strutsdemo.EditCategoryAction"<BR>unknown="false"<BR>validate="false"&gt;<BR>&lt;forward name="success"<BR>path="/EditCategory.jsp"/&gt;<BR>&lt;/action&gt;<BR></P>
<P><BR>　　在准备阶段，容器尝试从Session或Request找出指定的Form Bean，这是因为在动作中指定了“name=...”。ActionServlet在struts-config.xml文件的区域寻找Form Bean的别名，利用Form Bean的别名寻找对应的Java类。如果用户的请求带有参数，其名字匹配Form Bean属性名字的参数将被设置为属性值。Struts扩展了“属性名字”的含义，使得访问Form Bean内嵌对象的属性成为可能。本文的例子也用到了Struts的这一优点。</P>
<P>　　准备好Form Bean之后，ActionServlet接着调用动作的process()方法，Form Bean作为参数之一传入process()方法。在这里，我们对Form Bean的属性作最后的调整，调用业务方法，委派作为View的EditCategory，从而生成一个以Form Bean中合适数据为基础的HTML页面。这个页面被传递给客户端，接下来就进入了“表现”阶段。</P>
<P><FONT color=#0000ff>表现阶段</FONT></P>
<P>　　这一阶段用户编辑表单并提交。如果服务器端的应用认为用户提交的内容存在问题，它把表单再次显示给用户，加上适当的提示信息；重复该过程，直至用户提交了合法的表单，或取消了表单处理过程。编辑过程的中止可能是由于用户跳转到了其他页面，或者启动了一个取消动作（例如点击了一个由html:cancel标记定义的按钮）。虽然在理论上，View的验证和再次显示操作应该属于表现阶段，但在Struts应用中，这部分功能在存储阶段实现最方便。</P>
<P><FONT color=#0000ff>存储阶段</FONT></P>
<P>　　准备阶段创建了一个带有“name=”属性定义的动作CatForm，存储阶段要加入另外两个属性，即：“validate=‘true’”和“input=”属性。</P>
<P>&lt;action path="/saveCategory"<BR>scope="request"<BR>name="catForm"<BR>type="com.strutsdemo.SaveCategoryAction"<BR>unknown="false"<BR>input="/EditCategory1.jsp"<BR>validate="true"&gt;<BR>&lt;forward name="success"<BR>path="/CategoryUpdated.jsp"/&gt;<BR>&lt;/action&gt;<BR></P>
<P><BR>　　设置了“validate=‘true’”属性选项之后，服务器端就会增加一个处理步骤。重新用来自View的数据构造出Form Bean，或更新From Bean的时候，Form Bean的validate()方法会被调用。validate()方法执行必要的合法性验证操作。如果用户的输入数据中存在错误，validate()方法就创建一个或多个ActionError对象。这些ActionError对象包含了错误信息源ID和表单输入域的名称。这些ActionError对象被收集和整理到一个ActionErrors对象，随后ActionErrors对象由validate()方法返回。如果用户输入的数据不包含错误，validate()返回null。</P>
<P>　　由于指定了“input=”属性，一旦出现了错误，动作会被忽略，而“input=”指定的View被显示。这个View既包含Form Bean，也包含当前出现的错误对象集合。一般地，这个输入页面就是原来执行编辑功能的JSP页面。</P>
<P>　　大多数Struts的html标记有对应的HTML标记，但Struts有一个HTML没有的标记，即标记。要中止表单编辑过程，用户既可以手工输入URL，也可以点击不指向存储动作处理器的链接。因此，用标记定义的“取消”按钮，不是取消编辑操作的唯一方法。</P>
<P>　　假设validate()方法没有发现任何错误，且用户没有点击“取消”按钮，存储动作的process()方法将被调用。在本例的process()方法中，我们调用了Form Bean的save()方法把数据写入持久性存储设备，然后根据写入操作是否成功，显示“存储操作成功”或“存储操作失败”的View。</P>
<P><FONT color=#ff0000>构造和运行Struts应用</FONT></P>
<P>　　要构造和运行本文的示例应用，你必须了解如何使用Jakarta的Ant工具。如果你还不了解Ant，现在该是学习它的时候了！赶紧到网站下载Ant，通常要解开压缩，设置一下ANT_HOME环境变量，然后把Ant加入到执行路径就可以了。</P>
<P>本文示例的build.xml需要稍微定制一下，修改指示本地Tomcat位置的配置，使它能够找到在Tomcat下编译所必需的类。另外，你还要有一份Struts的JAR。你可以去下载最新的版本。</P>
<P>　　struts-config.xml文件是粘合Struts应用各个部分的配置文件。在部署完成后的Web应用中，struts-config.xml在Web-INF目录下。你应该修改一下数据源配置，使之符合你当前使用的DBMS环境。数据模型和SQL模式文件在下载包的DBMS目录下，SQL文件针对PostgreSQL DBMS编写。</P>
<P>　　示例中src/com/strutsdemo/ShowCategoriesAction. java是一个简单的分配器。ActionForward()是请求分配方法，从ActionServlet调用。该方法可以完成主要的工作，例如分析请求参数、执行计算，以及构造出View使用的JavaBean。另外，该方法还要根据处理结果，确定下一个要显示的是什么页面：可能是预设的多个页面之一，也可能是一个错误信息页面。</P>
<P><FONT color=#0000ff>ActionForward()的请求分配过程</FONT></P>
<P>　　当然，最复杂的处理过程与表单有关。ActionForward方法的请求分配过程是：</P>
<P>　　1. ActionServlet，对请求进行解码。由于为动作指定了Form Bean，ActionServlet处理Form Bean（参见下面有关“ActionServlet如何使用Form Bean”的说明）。然后，请求传递给了EditCategoryAction。</P>
<P>　　2. EditCategoryAction；准备处理View，或者从数据库装入现有数据，或者创建新的数据项。动作处理器利用Mapping.findForward把控制传递给EditCategory.jsp。</P>
<P>　　3. DitCategory.jsp，显示出Form Bean，允许用户编辑数据。用户提交数据后，控制转到ActionServlet。</P>
<P>　　4. ActionServlet，对请求进行解码。这一次，Form Bean将从View的数据初始化，因为它是一个Struts的JSP表单页面。由于有Form Bean，且struts-config.xml中指定了“validate=‘true’”，名为“catForm”的Form Bean的validate()方法被调用。如果用户提交的数据未能通过合法性验证，则控制转到EditCategory1.jsp。</P>
<P>　　5. EditCategory1.jsp，它只是EditCategory.jsp略加修改后的一个版本。如果有必要，原始编辑页面和带有错误提示的编辑页面可以使用同一个View。Struts的JSP标记能够帮助我们轻松地办到这一点。该页面提交给/saveCategory.do。这样，用户就在这几个页面之间绕圈子，直到他跳转到一个与编辑操作无关的页面，或者他提交的数据通过了合法性验证。</P>
<P>　　6. 如果Form Bean合法性验证通过，ActionServlet把请求（包括Form Bean）传递给SaveCategoryAction。在这个例子中，“save”可能意味着创建操作，也可能意味着更新操作，具体由URL提供的选项决定。写入数据的操作通过调用Form Bean的store()方法完成。注意：实际的应用应当使用某种类型的事务管理机制（或使用EJB，因为EJB有内建的事务管理机制），以避免并发访问带来的问题。</P>
<P><FONT color=#0000ff>ActionServlet如何使用Form Bean</FONT></P>
<P>　　涉及Form Bean的ActionServlet处理过程包含六个步骤：</P>
<P>　　1. 找到或创建Form Bean；</P>
<P>　　2. 据从HTTP请求传入的相应数据，更新Form Bean的各个属性；</P>
<P>　　3. 检查用户是否点击了“取消”按钮。如是，跳过步骤4和步骤5；</P>
<P>　　4. 验证Form Bean数据的合法性；</P>
<P>　　5. 如数据未能通过合法性验证，发送“input=”参数中指定的View；</P>
<P>　　6. 否则，把Form Bean传递给动作处理器。</P><img src ="http://www.blogjava.net/qq13367612/aggbug/16257.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qq13367612/" target="_blank">Sung</a> 2005-09-09 14:00 <a href="http://www.blogjava.net/qq13367612/articles/16257.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一个高效简洁的Struts分页方法</title><link>http://www.blogjava.net/qq13367612/articles/16259.html</link><dc:creator>Sung</dc:creator><author>Sung</author><pubDate>Fri, 02 Sep 2005 05:56:00 GMT</pubDate><guid>http://www.blogjava.net/qq13367612/articles/16259.html</guid><wfw:comment>http://www.blogjava.net/qq13367612/comments/16259.html</wfw:comment><comments>http://www.blogjava.net/qq13367612/articles/16259.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qq13367612/comments/commentRss/16259.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qq13367612/services/trackbacks/16259.html</trackback:ping><description><![CDATA[在网上看了几个Structs分页，感觉不是很完善，于是根据自己的经验，写了一个相对高效简洁的分页方法。由于本人水平有限，如果大家有什么更好的想法，欢迎不吝赐教。 <BR><BR>一、 开发环境 <BR>我的开发环境是：JBuilder x + Weblogic 8.1 + Oracle 9i + Windows 2003 ，如果朋友们的开发环境不一样亦无妨。 <BR><BR>二、开发思路 <BR>既然讲的是Struts，那自然离不了MVC，分页显示也是如此。 <BR>1、 建立数据库和对应的表，本例的表是TCertificate。 <BR>2、 建立适当的模型组件，对应你要查询数据库中的表。这部分由DAO数据访问层来实现，如果有的朋友对DAO不熟悉可以查询一下相关资料。本例由CertificateDAO.java来实现。 <BR>3 、建立分页所需要的模型组件，由javaBean来充当，并与CertificateDAO实现分离。网上介绍的很多方法，都存在着数据与分页组件藕合的现象，这也是本方法与其它分页方法的主要不同之处。 <BR><BR>4、建立控制器组件，这部分由Struts 中的Action来实现。主要负责将实例化CertificateDAO，只取要显示的数据记录，存入ArrayList对象然后返回，并放到request中。而分页部分则根据分页条件，单独进行构造，避免了与DAO混在一起的情况发生。网上其它介绍的一些分页方法中，基本上都是一次性读出所有查询的数据，然后再由分页相关组件进行构造。这样，如果数据量大的话，很容易形成瓶颈。在本例中由于不是一次性地读出查询的所有数据，而只是读出一个页面要显示的数据记录，这就节省了很多不必要的数据传输，提高了效率。本例中为CertificateAction.java。 <BR><BR>5、建立视图组件，这部分由jsp来充当，为了不出现java 代码，我们使用Struts提供的标签库，主要负责从request中取出刚刚放入的对象，通过反复调用CertificateAction以及action参数，而实现分页显示。本例中为listcertificate.jsp。 <BR>6、 建立并配置struts-config.xml。 <BR><BR>三、实例代码 <BR>确定好上面的开发思路后，代码的实现就有单可循了。 <BR>1、建数据库和相应的表。 <BR>2、数据逻辑层的相关代码。 <BR>1）、通用的DAO类：CommonDAO.java <BR>这是一个很多DAO都要继承到的通用DAO类，是我根据实践总结出来的，为了减少篇幅，这里只显示和本例相关的代码。 <BR><BR><BR>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><B>java代码: </B></TD></TR>
<TR>
<TD class=code>
<DIV><BR>package com.xindeco.business ; <BR>import java.io.*; <BR>import java.sql.*; <BR>import java.util.*; <BR>import javax.sql.*; <BR>import java.lang.IllegalAccessException; <BR>import java.lang.reflect.InvocationTargetException; <BR>import org.apache.commons.beanutils.BeanUtils; <BR>public class DAO <BR>{ <BR>  protected DataSource ds; <BR>/** <BR>  * 说明:取得当前查询的总记录数 <BR>  */ <BR>public int getRows () <BR>{ <BR>  return this.count; <BR>} <BR>  public void rsHandler (ResultSet rs, int offset, int limit) <BR>  { <BR>   try <BR>   { <BR>    count = 0; <BR>    rs.absolute ( -1) ; <BR>    count = rs.getRow () ; <BR>    if (offset <= 0) <BR>    { <BR>     rs.beforeFirst () ; <BR>    } <BR>    else <BR>    { <BR>     rs.absolute (offset) ; <BR>    } <BR>   } <BR>   catch (Exception e) <BR>   { <BR>    e.printStackTrace () ; <BR>   } <BR>  } <BR>  public DAO(DataSource ds) { <BR>          this.ds = ds; <BR>  } <BR><BR>  public void setDataSource(DataSource ds) { <BR>    this.ds = ds; <BR>  } <BR><BR>  protected void close(ResultSet rs) { <BR>    if (rs != null) { <BR>            try { <BR>                    rs.close(); <BR>            } catch (SQLException e) { <BR>            } <BR>            rs = null; <BR>    } <BR>  } <BR><BR>  protected void close(PreparedStatement pstmt) { <BR>    if (pstmt != null) { <BR>            try { <BR>                    pstmt.close(); <BR>            } catch (SQLException e) { <BR>            } <BR>            pstmt = null; <BR>    } <BR>  } <BR>  protected void close(Connection conn) { <BR>    if (conn != null) { <BR>            try { <BR>                    conn.close(); <BR>            } catch (SQLException e) { <BR>                    e.printStackTrace(); <BR>            } <BR>            conn = null; <BR>    } <BR>  } <BR><BR>  protected void rollback(Connection conn) { <BR>    if (conn != null) { <BR>            try { <BR>                    conn.rollback(); <BR>            } catch (SQLException e) { <BR>                    e.printStackTrace(); <BR>            } <BR>            conn = null; <BR>    } <BR>  } <BR>}</DIV></TD></TR></TBODY></TABLE><BR><BR>这个类主要是通过子类传进来的先进结果集，取得查询的记录总数，并对数据库连接进行简单的管理。 <BR>2）、对数据库进行访问：CertificateDAO.java <BR><BR><BR>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><B>java代码: </B></TD></TR>
<TR>
<TD class=code>
<DIV><BR>package com.xindeco.business; <BR><BR>import java.io.*; <BR>import java.sql.*; <BR>import java.util.*; <BR>import javax.sql.*; <BR><BR>import com.xindeco.common.dbconn.DbConn; <BR><BR>public class CertificateDAO extends DAO <BR>{ <BR><BR>  public NationDAO(DataSource ds) { <BR>    super(ds); <BR>  } <BR><BR>public List findCertificateList(int offset,int limit) throws SQLException <BR>        { <BR>        int countRows = 0 ; <BR>        ArrayList list = null ; <BR>    Connection conn = null; <BR>    PreparedStatement pstmt = null; <BR>ResultSet rs = null; <BR>try <BR>        { <BR>             conn = ds.getConnection(); <BR>                String sql = <BR>                                "SELECT certificateID, certificateCode,certificateName,photoURL," <BR>                                + "description,graduateID FROM TCertificate " ; <BR>      pstmt = conn.prepareStatement(sql); <BR>      rs = pstmt.executeQuery(); <BR>                        /*对游标进行处理，rsHandler 方法在父类DAO中*/ <BR>                        this.rsHandler(rs,offset,limit); <BR>                        if (rs != null && rs.next ()) <BR>                        { <BR>                                list = new ArrayList () ; <BR>                                do <BR>                                { <BR>                                        countRows++ ; <BR>                                        list.add (rs2VO (rs)) ; <BR>                                } <BR>                                while ( (countRows++ < limit) && rs.next ()) ; <BR>                        } <BR>      close(rs); <BR>      close(pstmt); <BR>          } catch (SQLException e) { <BR>      close(rs); <BR>      close(pstmt); <BR>      rollback(conn); <BR>                e.printStackTrace(); <BR>                  } <BR>finally { <BR>            close(conn); <BR>    } <BR>        return list ; <BR>        } <BR><BR>        private CertificateVO rs2VO (ResultSet rs) <BR>        { <BR>                try <BR>                { <BR>                        CertificateVO certificateVO = new CertificateVO () ; <BR>                        certificateVO.setCertificateID (rs.getInt ("certificateID")) ; <BR>                        certificateVO.setCertificateCode (rs.getString ("certificateCode")) ; <BR>                        certificateVO.setCertificateName (rs.getString ("certificateName")) ; <BR>                        certificateVO.setPhotoURL (rs.getString ("photoURL")) ; <BR>                        certificateVO.setDescription (rs.getString ("description")) ; <BR>                        certificateVO.setGraduateID (rs.getInt ("graduateID")) ; <BR>                        return certificateVO ; <BR>                } <BR>                catch (Exception ex) <BR>                { <BR>                        ex.printStackTrace () ; <BR>                        return null ; <BR>                } <BR>        } <BR>}</DIV></TD></TR></TBODY></TABLE><BR>findCertificateList(int offset,int limit)是查得所有要显示的数据，并放入ArrayList中。看过网上有些例子，把数据记录放入ArrayList的动作过程直接在while循环体里完成，如果字段多的话，会造成方法过于宠大，又不美观。 这里，数据记录放入ArrayList的动作过程由rs2VO方法完成，就比较整洁了。另外，if (rs != null && rs.next ()) 配合while ( (countRows++ < limit) && rs.next ()) 是为了程序的健壮性考虑的，稍分析一下不难得出结论。 <BR><BR>3、建立控制器组件：CertificateAction.java <BR><BR><BR>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><B>java代码: </B></TD></TR>
<TR>
<TD class=code>
<DIV><BR>package com.xindeco.presentation; <BR><BR>import javax.sql.* ; <BR>import java.util.* ; <BR><BR>import javax.servlet.http.* ; <BR>import javax.servlet.* ; <BR><BR>import org.apache.struts.action.* ; <BR>import org.apache.struts.util.* ; <BR><BR>import com.xindeco.common.Pager; <BR>import com.xindeco.business.graduatedata.CertificateDAO ; <BR><BR>public class CertificateAction <BR>        extends Action <BR>{ <BR>        private static final int PAGE_LENGTH = 5 ; //每页显示5条记录 <BR>        public ActionForward execute (ActionMapping mapping, ActionForm form, <BR>                                                                  HttpServletRequest request, <BR>                                                                  HttpServletResponse response) <BR>        { <BR>                ActionForward myforward = null ; <BR>                String myaction = mapping.getParameter () ; <BR><BR>                if (isCancelled (request)) <BR>                { <BR>                        return mapping.findForward ("failure") ; <BR>                } <BR>                if ("".equalsIgnoreCase (myaction)) <BR>                { <BR>                        myforward = mapping.findForward ("failure") ; <BR>                } <BR>                else if        ("LIST".equalsIgnoreCase (myaction)) <BR>                { <BR>                        myforward = performList (mapping, form, request, response) ; <BR>                } <BR>                else <BR>                { <BR>                        myforward = mapping.findForward ("failure") ; <BR>                } <BR>                return myforward ; <BR>        } <BR><BR>        private ActionForward performList (ActionMapping mapping, <BR>                                                                           ActionForm actionForm, <BR>                                                                           HttpServletRequest request, <BR>                                                                           HttpServletResponse response) <BR>        { <BR>                     try <BR>                { <BR>        DataSource ds = (DataSource) servlet.getServletContext().getAttribute(Action.DATA_SOURCE_KEY); <BR><BR>                CertificateDAO   certificateDAO  = new CertificateDAO  (ds) ; <BR><BR>                        int offset = 0;   //翻页时的起始记录所在游标 <BR>                        int length = PAGE_LENGTH;  <BR>                        String pageOffset = request.getParameter("pager.offset"); <BR>                if (pageOffset == null || pageOffset.equals("")) { <BR>        offset = 0; <BR>      } else { <BR>        offset = Integer.parseInt(pageOffset); <BR>      } <BR>                        List certificateList = certificateDAO .findCertificateList (offset,length) ; <BR>                        int size = certificateDAO.getRows(); //  取得总记录数 <BR>                        String url = request.getContextPath()+"/"+mapping.getPath()+".do"; <BR>                        String pagerHeader = Pager.generate(offset, size, length, url); //分页处理 <BR><BR>                        request.setAttribute ("pager", pagerHeader) ; <BR>                        request.setAttribute ("list", certificateList) ; <BR>                } <BR>                catch (Exception e) <BR>                { <BR>                        e.printStackTrace(); <BR>                        return mapping.findForward ("error") ; <BR>                } <BR>                return mapping.findForward ("success") ; <BR>        } <BR>}</DIV></TD></TR></TBODY></TABLE><BR><BR>CertificateAction.java主要是把数据从DAO中取出，并放入一个ArrayList 中，然后通过配置文件再软件View的JSP页。 <BR><BR>5、建立视图listcertificate.jsp文件。 <BR><BR>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><B>java代码: </B></TD></TR>
<TR>
<TD class=code>
<DIV><BR><%@ page contentType="text/html; charset=GBK" %> <BR><%@ taglib uri="/WEB-INF/struts-template.tld" prefix="template" %> <BR><%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %> <BR><%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %> <BR><%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %> <BR><BR><table bgcolor="#666666" cellpadding="1" cellspacing="0" border="0" width="500"> <BR><tr> <BR><td> <BR><table cellpadding="0" cellspacing="0" border="0" width="500"> <BR><tr> <BR><td bgcolor="#fecc51">&</td> <BR></tr> <BR></table> <BR></td> <BR></tr> <BR><tr> <BR><td> <BR><table cellpadding="0" cellspacing="0" border="0" width="500"> <BR>  <tr> <BR><td bgcolor="#d6e0ed"> <BR>    &&<bean:message key="label.list4certificate"/> <BR>  </td> <BR></tr> <BR><tr bgcolor="#FFFFFF"> <BR><td width="5%"></td><td width="19%"></td><td width="76%"></td> <BR></tr> <BR>    <tr> <BR><td> <BR><table bgcolor="#f2f2f2" width="500" cellspacing="0" border="0"> <BR>      <tr bgcolor="#bacce1"> <BR>        <td><b><bean:message key="Certificate.select"/> </b></td> <BR>        <td><b><bean:message key="Certificate.certificateID"/> </b></td> <BR>        <td><b><bean:message key="Certificate.certificateCode"/></b></td> <BR>        <td><b><bean:message key="Certificate.certificateName"/></b></td> <BR>        <td><b><bean:message key="Certificate.view"/></b></td> <BR>    ?/tr> <BR><BR><bean:write name="pager" property="description"/> <BR>  <logic:equal name="pager" property="hasPrevious" value="true"> <BR>              <a href="/graduatedata/list.do?viewPage=<bean:write name="pager" property="previousPage"/>" class="a02"> <BR>           Previous <BR>        </a> <BR>  </logic:equal> <BR>  <logic:equal name="pager" property="hasNext" value="true"> <BR>    ?a href="/graduatedata/list.do?viewPage=<bean:write name="pager" property="nextPage"/>" class="a02"> <BR>     Next <BR>    ?/a> <BR>  </logic:equal> <BR><BR><logic:notEmpty name="list" scope="request"> <BR><logic:iterate id="certificate" name="list" type="com.xindeco.business.graduatedata.CertificateVO"scope="request"> <BR><tr bgcolor="#FFFFFF"> <BR>    ?td><html:text property="name" value="<bean:write name="certificate" property="certificateID" scope="page"/>"/> <BR>                </td> <BR>    ?td> <bean:write name="certificate" property="certificateID" scope="page"/></td> <BR>    ?td> <bean:write name="certificate" property="certificateCode" scope="page"/></td> <BR>    ?td> <bean:write name="certificate" property="certificateName" scope="page"/></td> <BR>    ?td> <bean:write name="certificate" property="photoURL" scope="page"/></td> <BR></tr> <BR></logic:iterate> <BR></logic:notEmpty> <BR></table> <BR></td> <BR></tr> <BR></table> <BR></td> <BR></tr> <BR></table></DIV></TD></TR></TBODY></TABLE><BR>6、对应的配置文件struts-config.xml。 <BR><BR>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><B>java代码: </B></TD></TR>
<TR>
<TD class=code>
<DIV><BR><?xml version="1.0" encoding="UTF-8"?> <BR><!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN" "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd"> <BR><struts-config> <BR>  <form-beans> <BR>    <form-bean name="certificateForm" type="com.xindeco.presentation.graduatedata.CertificateForm" /> <BR>  </form-beans> <BR>  <global-forwards> <BR>    <forward name="error" path="/error/error.jsp" /> <BR>  </global-forwards> <BR>  <action-mappings> <BR>      <action name="certificateForm" parameter="LIST" path="/graduatedata/list" scope="request" type="com.xindeco.presentation.graduatedata.CertificateAction" validate="true"> <BR>      <forward name="success" path="/graduatedata/listcertificate.jsp" /> <BR>    </action> <BR>  </action-mappings> <BR>…… <BR></struts-config></DIV></TD></TR></TBODY></TABLE><BR>7、最后当然是最重要的分页代码了：Pager.java <BR><BR>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><B>java代码: </B></TD></TR>
<TR>
<TD class=code>
<DIV><BR>package com.xindeco.common; <BR><BR>import java.util.* ; <BR>public class Pager { <BR>  private static int MAX_PAGE_INDEX = 10; //页脚显示多少页 <BR>  private static String HEADER = "Result page"; <BR>  <BR>  public static String generate(int offset, int length, int size, String url) { <BR>        if (length > size) { <BR>          String pref; <BR>          if (url.indexOf("?") > -1) { <BR>                pref = "&"; <BR>          } else { <BR>                pref = "?"; <BR>          } <BR>          String header = "<font face='Helvetica' size='-1'>"+HEADER+": "; <BR>          if (offset > 0) { <BR>                header += "&<a href=\""+url+pref+"pager.offset="+(offset-size)+"\">[<< Prev]</a>\n"; <BR>          } <BR>          int start; <BR>          int radius = MAX_PAGE_INDEX/2*size; <BR>          if (offset < radius) { <BR>                start = 0; <BR>          } else if(offset < length-radius) { <BR>                start = offset - radius; <BR>          } else { <BR>                start = (length/size-MAX_PAGE_INDEX)*size; <BR>          } <BR>          for(int i=start;i<length && i < start + MAX_PAGE_INDEX*size;i+=size) { <BR>                if (i == offset) { <BR>                  header += "<b>"+(i/size+1)+"</b>\n"; <BR>                } else { <BR>                  header += "&<a href=\""+url+pref+"pager.offset="+i+"\">"+(i/size+1)+"</a>\n"; <BR>                } <BR>          } <BR>          if(offset < length - size) { <BR>                header += "&<a href=\""+url+pref+"pager.offset="+((int)offset+(int)size)+"\">[Next >>]</a>\n"; <BR>          } <BR>          header += "</font>"; <BR>          return header; <BR>        } else { <BR>          return ""; <BR>        } <BR>  } <BR>}</DIV></TD></TR></TBODY></TABLE><BR>这部分代码的实现相当简洁，但已经足够完成所需了。<![CDATA[在网上看了几个Structs分页，感觉不是很完善，于是根据自己的经验，写了一个相对高效简洁的分页方法。由于本人水平有限，如果大家有什么更好的想法，欢迎不吝赐教。 <BR><BR>一、 开发环境 <BR>我的开发环境是：JBuilder x + Weblogic 8.1 + Oracle 9i + Windows 2003 ，如果朋友们的开发环境不一样亦无妨。 <BR><BR>二、开发思路 <BR>既然讲的是Struts，那自然离不了MVC，分页显示也是如此。 <BR>1、 建立数据库和对应的表，本例的表是TCertificate。 <BR>2、 建立适当的模型组件，对应你要查询数据库中的表。这部分由DAO数据访问层来实现，如果有的朋友对DAO不熟悉可以查询一下相关资料。本例由CertificateDAO.java来实现。 <BR>3 、建立分页所需要的模型组件，由javaBean来充当，并与CertificateDAO实现分离。网上介绍的很多方法，都存在着数据与分页组件藕合的现象，这也是本方法与其它分页方法的主要不同之处。 <BR><BR>4、建立控制器组件，这部分由Struts 中的Action来实现。主要负责将实例化CertificateDAO，只取要显示的数据记录，存入ArrayList对象然后返回，并放到request中。而分页部分则根据分页条件，单独进行构造，避免了与DAO混在一起的情况发生。网上其它介绍的一些分页方法中，基本上都是一次性读出所有查询的数据，然后再由分页相关组件进行构造。这样，如果数据量大的话，很容易形成瓶颈。在本例中由于不是一次性地读出查询的所有数据，而只是读出一个页面要显示的数据记录，这就节省了很多不必要的数据传输，提高了效率。本例中为CertificateAction.java。 <BR><BR>5、建立视图组件，这部分由jsp来充当，为了不出现java 代码，我们使用Struts提供的标签库，主要负责从request中取出刚刚放入的对象，通过反复调用CertificateAction以及action参数，而实现分页显示。本例中为listcertificate.jsp。 <BR>6、 建立并配置struts-config.xml。 <BR><BR>三、实例代码 <BR>确定好上面的开发思路后，代码的实现就有单可循了。 <BR>1、建数据库和相应的表。 <BR>2、数据逻辑层的相关代码。 <BR>1）、通用的DAO类：CommonDAO.java <BR>这是一个很多DAO都要继承到的通用DAO类，是我根据实践总结出来的，为了减少篇幅，这里只显示和本例相关的代码。 <BR><BR><BR>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><B>java代码: </B></TD></TR>
<TR>
<TD class=code>
<DIV><BR>package com.xindeco.business ; <BR>import java.io.*; <BR>import java.sql.*; <BR>import java.util.*; <BR>import javax.sql.*; <BR>import java.lang.IllegalAccessException; <BR>import java.lang.reflect.InvocationTargetException; <BR>import org.apache.commons.beanutils.BeanUtils; <BR>public class DAO <BR>{ <BR>  protected DataSource ds; <BR>/** <BR>  * 说明:取得当前查询的总记录数 <BR>  */ <BR>public int getRows () <BR>{ <BR>  return this.count; <BR>} <BR>  public void rsHandler (ResultSet rs, int offset, int limit) <BR>  { <BR>   try <BR>   { <BR>    count = 0; <BR>    rs.absolute ( -1) ; <BR>    count = rs.getRow () ; <BR>    if (offset <= 0) <BR>    { <BR>     rs.beforeFirst () ; <BR>    } <BR>    else <BR>    { <BR>     rs.absolute (offset) ; <BR>    } <BR>   } <BR>   catch (Exception e) <BR>   { <BR>    e.printStackTrace () ; <BR>   } <BR>  } <BR>  public DAO(DataSource ds) { <BR>          this.ds = ds; <BR>  } <BR><BR>  public void setDataSource(DataSource ds) { <BR>    this.ds = ds; <BR>  } <BR><BR>  protected void close(ResultSet rs) { <BR>    if (rs != null) { <BR>            try { <BR>                    rs.close(); <BR>            } catch (SQLException e) { <BR>            } <BR>            rs = null; <BR>    } <BR>  } <BR><BR>  protected void close(PreparedStatement pstmt) { <BR>    if (pstmt != null) { <BR>            try { <BR>                    pstmt.close(); <BR>            } catch (SQLException e) { <BR>            } <BR>            pstmt = null; <BR>    } <BR>  } <BR>  protected void close(Connection conn) { <BR>    if (conn != null) { <BR>            try { <BR>                    conn.close(); <BR>            } catch (SQLException e) { <BR>                    e.printStackTrace(); <BR>            } <BR>            conn = null; <BR>    } <BR>  } <BR><BR>  protected void rollback(Connection conn) { <BR>    if (conn != null) { <BR>            try { <BR>                    conn.rollback(); <BR>            } catch (SQLException e) { <BR>                    e.printStackTrace(); <BR>            } <BR>            conn = null; <BR>    } <BR>  } <BR>}</DIV></TD></TR></TBODY></TABLE><BR><BR>这个类主要是通过子类传进来的先进结果集，取得查询的记录总数，并对数据库连接进行简单的管理。 <BR>2）、对数据库进行访问：CertificateDAO.java <BR><BR><BR>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><B>java代码: </B></TD></TR>
<TR>
<TD class=code>
<DIV><BR>package com.xindeco.business; <BR><BR>import java.io.*; <BR>import java.sql.*; <BR>import java.util.*; <BR>import javax.sql.*; <BR><BR>import com.xindeco.common.dbconn.DbConn; <BR><BR>public class CertificateDAO extends DAO <BR>{ <BR><BR>  public NationDAO(DataSource ds) { <BR>    super(ds); <BR>  } <BR><BR>public List findCertificateList(int offset,int limit) throws SQLException <BR>        { <BR>        int countRows = 0 ; <BR>        ArrayList list = null ; <BR>    Connection conn = null; <BR>    PreparedStatement pstmt = null; <BR>ResultSet rs = null; <BR>try <BR>        { <BR>             conn = ds.getConnection(); <BR>                String sql = <BR>                                "SELECT certificateID, certificateCode,certificateName,photoURL," <BR>                                + "description,graduateID FROM TCertificate " ; <BR>      pstmt = conn.prepareStatement(sql); <BR>      rs = pstmt.executeQuery(); <BR>                        /*对游标进行处理，rsHandler 方法在父类DAO中*/ <BR>                        this.rsHandler(rs,offset,limit); <BR>                        if (rs != null && rs.next ()) <BR>                        { <BR>                                list = new ArrayList () ; <BR>                                do <BR>                                { <BR>                                        countRows++ ; <BR>                                        list.add (rs2VO (rs)) ; <BR>                                } <BR>                                while ( (countRows++ < limit) && rs.next ()) ; <BR>                        } <BR>      close(rs); <BR>      close(pstmt); <BR>          } catch (SQLException e) { <BR>      close(rs); <BR>      close(pstmt); <BR>      rollback(conn); <BR>                e.printStackTrace(); <BR>                  } <BR>finally { <BR>            close(conn); <BR>    } <BR>        return list ; <BR>        } <BR><BR>        private CertificateVO rs2VO (ResultSet rs) <BR>        { <BR>                try <BR>                { <BR>                        CertificateVO certificateVO = new CertificateVO () ; <BR>                        certificateVO.setCertificateID (rs.getInt ("certificateID")) ; <BR>                        certificateVO.setCertificateCode (rs.getString ("certificateCode")) ; <BR>                        certificateVO.setCertificateName (rs.getString ("certificateName")) ; <BR>                        certificateVO.setPhotoURL (rs.getString ("photoURL")) ; <BR>                        certificateVO.setDescription (rs.getString ("description")) ; <BR>                        certificateVO.setGraduateID (rs.getInt ("graduateID")) ; <BR>                        return certificateVO ; <BR>                } <BR>                catch (Exception ex) <BR>                { <BR>                        ex.printStackTrace () ; <BR>                        return null ; <BR>                } <BR>        } <BR>}</DIV></TD></TR></TBODY></TABLE><BR>findCertificateList(int offset,int limit)是查得所有要显示的数据，并放入ArrayList中。看过网上有些例子，把数据记录放入ArrayList的动作过程直接在while循环体里完成，如果字段多的话，会造成方法过于宠大，又不美观。 这里，数据记录放入ArrayList的动作过程由rs2VO方法完成，就比较整洁了。另外，if (rs != null && rs.next ()) 配合while ( (countRows++ < limit) && rs.next ()) 是为了程序的健壮性考虑的，稍分析一下不难得出结论。 <BR><BR>3、建立控制器组件：CertificateAction.java <BR><BR><BR>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><B>java代码: </B></TD></TR>
<TR>
<TD class=code>
<DIV><BR>package com.xindeco.presentation; <BR><BR>import javax.sql.* ; <BR>import java.util.* ; <BR><BR>import javax.servlet.http.* ; <BR>import javax.servlet.* ; <BR><BR>import org.apache.struts.action.* ; <BR>import org.apache.struts.util.* ; <BR><BR>import com.xindeco.common.Pager; <BR>import com.xindeco.business.graduatedata.CertificateDAO ; <BR><BR>public class CertificateAction <BR>        extends Action <BR>{ <BR>        private static final int PAGE_LENGTH = 5 ; //每页显示5条记录 <BR>        public ActionForward execute (ActionMapping mapping, ActionForm form, <BR>                                                                  HttpServletRequest request, <BR>                                                                  HttpServletResponse response) <BR>        { <BR>                ActionForward myforward = null ; <BR>                String myaction = mapping.getParameter () ; <BR><BR>                if (isCancelled (request)) <BR>                { <BR>                        return mapping.findForward ("failure") ; <BR>                } <BR>                if ("".equalsIgnoreCase (myaction)) <BR>                { <BR>                        myforward = mapping.findForward ("failure") ; <BR>                } <BR>                else if        ("LIST".equalsIgnoreCase (myaction)) <BR>                { <BR>                        myforward = performList (mapping, form, request, response) ; <BR>                } <BR>                else <BR>                { <BR>                        myforward = mapping.findForward ("failure") ; <BR>                } <BR>                return myforward ; <BR>        } <BR><BR>        private ActionForward performList (ActionMapping mapping, <BR>                                                                           ActionForm actionForm, <BR>                                                                           HttpServletRequest request, <BR>                                                                           HttpServletResponse response) <BR>        { <BR>                     try <BR>                { <BR>        DataSource ds = (DataSource) servlet.getServletContext().getAttribute(Action.DATA_SOURCE_KEY); <BR><BR>                CertificateDAO   certificateDAO  = new CertificateDAO  (ds) ; <BR><BR>                        int offset = 0;   //翻页时的起始记录所在游标 <BR>                        int length = PAGE_LENGTH;  <BR>                        String pageOffset = request.getParameter("pager.offset"); <BR>                if (pageOffset == null || pageOffset.equals("")) { <BR>        offset = 0; <BR>      } else { <BR>        offset = Integer.parseInt(pageOffset); <BR>      } <BR>                        List certificateList = certificateDAO .findCertificateList (offset,length) ; <BR>                        int size = certificateDAO.getRows(); //  取得总记录数 <BR>                        String url = request.getContextPath()+"/"+mapping.getPath()+".do"; <BR>                        String pagerHeader = Pager.generate(offset, size, length, url); //分页处理 <BR><BR>                        request.setAttribute ("pager", pagerHeader) ; <BR>                        request.setAttribute ("list", certificateList) ; <BR>                } <BR>                catch (Exception e) <BR>                { <BR>                        e.printStackTrace(); <BR>                        return mapping.findForward ("error") ; <BR>                } <BR>                return mapping.findForward ("success") ; <BR>        } <BR>}</DIV></TD></TR></TBODY></TABLE><BR><BR>CertificateAction.java主要是把数据从DAO中取出，并放入一个ArrayList 中，然后通过配置文件再软件View的JSP页。 <BR><BR>5、建立视图listcertificate.jsp文件。 <BR><BR>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><B>java代码: </B></TD></TR>
<TR>
<TD class=code>
<DIV><BR><%@ page contentType="text/html; charset=GBK" %> <BR><%@ taglib uri="/WEB-INF/struts-template.tld" prefix="template" %> <BR><%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %> <BR><%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %> <BR><%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %> <BR><BR><table bgcolor="#666666" cellpadding="1" cellspacing="0" border="0" width="500"> <BR><tr> <BR><td> <BR><table cellpadding="0" cellspacing="0" border="0" width="500"> <BR><tr> <BR><td bgcolor="#fecc51">&</td> <BR></tr> <BR></table> <BR></td> <BR></tr> <BR><tr> <BR><td> <BR><table cellpadding="0" cellspacing="0" border="0" width="500"> <BR>  <tr> <BR><td bgcolor="#d6e0ed"> <BR>    &&<bean:message key="label.list4certificate"/> <BR>  </td> <BR></tr> <BR><tr bgcolor="#FFFFFF"> <BR><td width="5%"></td><td width="19%"></td><td width="76%"></td> <BR></tr> <BR>    <tr> <BR><td> <BR><table bgcolor="#f2f2f2" width="500" cellspacing="0" border="0"> <BR>      <tr bgcolor="#bacce1"> <BR>        <td><b><bean:message key="Certificate.select"/> </b></td> <BR>        <td><b><bean:message key="Certificate.certificateID"/> </b></td> <BR>        <td><b><bean:message key="Certificate.certificateCode"/></b></td> <BR>        <td><b><bean:message key="Certificate.certificateName"/></b></td> <BR>        <td><b><bean:message key="Certificate.view"/></b></td> <BR>    ?/tr> <BR><BR><bean:write name="pager" property="description"/> <BR>  <logic:equal name="pager" property="hasPrevious" value="true"> <BR>              <a href="/graduatedata/list.do?viewPage=<bean:write name="pager" property="previousPage"/>" class="a02"> <BR>           Previous <BR>        </a> <BR>  </logic:equal> <BR>  <logic:equal name="pager" property="hasNext" value="true"> <BR>    ?a href="/graduatedata/list.do?viewPage=<bean:write name="pager" property="nextPage"/>" class="a02"> <BR>     Next <BR>    ?/a> <BR>  </logic:equal> <BR><BR><logic:notEmpty name="list" scope="request"> <BR><logic:iterate id="certificate" name="list" type="com.xindeco.business.graduatedata.CertificateVO"scope="request"> <BR><tr bgcolor="#FFFFFF"> <BR>    ?td><html:text property="name" value="<bean:write name="certificate" property="certificateID" scope="page"/>"/> <BR>                </td> <BR>    ?td> <bean:write name="certificate" property="certificateID" scope="page"/></td> <BR>    ?td> <bean:write name="certificate" property="certificateCode" scope="page"/></td> <BR>    ?td> <bean:write name="certificate" property="certificateName" scope="page"/></td> <BR>    ?td> <bean:write name="certificate" property="photoURL" scope="page"/></td> <BR></tr> <BR></logic:iterate> <BR></logic:notEmpty> <BR></table> <BR></td> <BR></tr> <BR></table> <BR></td> <BR></tr> <BR></table></DIV></TD></TR></TBODY></TABLE><BR>6、对应的配置文件struts-config.xml。 <BR><BR>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><B>java代码: </B></TD></TR>
<TR>
<TD class=code>
<DIV><BR><?xml version="1.0" encoding="UTF-8"?> <BR><!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN" "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd"> <BR><struts-config> <BR>  <form-beans> <BR>    <form-bean name="certificateForm" type="com.xindeco.presentation.graduatedata.CertificateForm" /> <BR>  </form-beans> <BR>  <global-forwards> <BR>    <forward name="error" path="/error/error.jsp" /> <BR>  </global-forwards> <BR>  <action-mappings> <BR>      <action name="certificateForm" parameter="LIST" path="/graduatedata/list" scope="request" type="com.xindeco.presentation.graduatedata.CertificateAction" validate="true"> <BR>      <forward name="success" path="/graduatedata/listcertificate.jsp" /> <BR>    </action> <BR>  </action-mappings> <BR>…… <BR></struts-config></DIV></TD></TR></TBODY></TABLE><BR>7、最后当然是最重要的分页代码了：Pager.java <BR><BR>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><B>java代码: </B></TD></TR>
<TR>
<TD class=code>
<DIV><BR>package com.xindeco.common; <BR><BR>import java.util.* ; <BR>public class Pager { <BR>  private static int MAX_PAGE_INDEX = 10; //页脚显示多少页 <BR>  private static String HEADER = "Result page"; <BR>  <BR>  public static String generate(int offset, int length, int size, String url) { <BR>        if (length > size) { <BR>          String pref; <BR>          if (url.indexOf("?") > -1) { <BR>                pref = "&"; <BR>          } else { <BR>                pref = "?"; <BR>          } <BR>          String header = "<font face='Helvetica' size='-1'>"+HEADER+": "; <BR>          if (offset > 0) { <BR>                header += "&<a href=\""+url+pref+"pager.offset="+(offset-size)+"\">[<< Prev]</a>\n"; <BR>          } <BR>          int start; <BR>          int radius = MAX_PAGE_INDEX/2*size; <BR>          if (offset < radius) { <BR>                start = 0; <BR>          } else if(offset < length-radius) { <BR>                start = offset - radius; <BR>          } else { <BR>                start = (length/size-MAX_PAGE_INDEX)*size; <BR>          } <BR>          for(int i=start;i<length && i < start + MAX_PAGE_INDEX*size;i+=size) { <BR>                if (i == offset) { <BR>                  header += "<b>"+(i/size+1)+"</b>\n"; <BR>                } else { <BR>                  header += "&<a href=\""+url+pref+"pager.offset="+i+"\">"+(i/size+1)+"</a>\n"; <BR>                } <BR>          } <BR>          if(offset < length - size) { <BR>                header += "&<a href=\""+url+pref+"pager.offset="+((int)offset+(int)size)+"\">[Next >>]</a>\n"; <BR>          } <BR>          header += "</font>"; <BR>          return header; <BR>        } else { <BR>          return ""; <BR>        } <BR>  } <BR>}</DIV></TD></TR></TBODY></TABLE><BR>这部分代码的实现相当简洁，但已经足够完成所需了。]]&gt;<img src ="http://www.blogjava.net/qq13367612/aggbug/16259.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qq13367612/" target="_blank">Sung</a> 2005-09-02 13:56 <a href="http://www.blogjava.net/qq13367612/articles/16259.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>