﻿<?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-呓语的博客-随笔分类-Struts</title><link>http://www.blogjava.net/xieyunlong/category/5622.html</link><description>不管前面的路有多艰辛多长，只要怀着一颗执着的心。成功就离你不远了!</description><language>zh-cn</language><lastBuildDate>Sat, 03 Mar 2007 09:01:14 GMT</lastBuildDate><pubDate>Sat, 03 Mar 2007 09:01:14 GMT</pubDate><ttl>60</ttl><item><title>关于struts几个常用类的解释</title><link>http://www.blogjava.net/xieyunlong/archive/2005/12/06/22717.html</link><dc:creator>呓语的博客</dc:creator><author>呓语的博客</author><pubDate>Tue, 06 Dec 2005 06:55:00 GMT</pubDate><guid>http://www.blogjava.net/xieyunlong/archive/2005/12/06/22717.html</guid><wfw:comment>http://www.blogjava.net/xieyunlong/comments/22717.html</wfw:comment><comments>http://www.blogjava.net/xieyunlong/archive/2005/12/06/22717.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xieyunlong/comments/commentRss/22717.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xieyunlong/services/trackbacks/22717.html</trackback:ping><description><![CDATA[<P style="LINE-HEIGHT: 16pt"><SPAN class=bt>ActionMapping类 <BR>将特定请求映射到特定Action的相关信息存储在ActionMapping中，ActionServelt将ActionMapping传送到Action类的execute()方法，Action将使用ActionMapping的findForward()方法，此方法返回一个指定名称的ActionForward，这样Action就完成了本地转发。若没有找到具体的ActionForward，就返回一个null. <BR>ActionMapping的方法: <BR>public ExceptionConfig findException(Class type) ,查找异常对象 <BR>public ActionForward findForward(String name) 可在映射中动态添加ActionForward: <BR>public String[] findForwards()找到一个Action可以使用的actionForward列表 <BR>public ActionForward getInputForward() 得到本action的输入ActionForard. <BR>ActionMapping继承于org.apache.struts.config.ActionConfig <BR>Action类 <BR>Action类真正实现应用程序的事务逻辑，它们负责处理请求。在收到请求后，ActionServlet会： <BR>1.为这个请求选择适当的Action <BR>2.如果需要，创建Action的一个实例 <BR>3.调用Action的execute()方法 <BR>如果ActionServlet不能找到有效的映射，它会调用默认的Action类(在配置文件中定义)。如果找到了ActionServlet将适当的ActionMapping类转发给Action，这个Action使用ActionMapping找到本地转发，然后获得并设置ActionMapping属性。根据servlet的环境和被覆盖的execute ()方法的签名，ActionServlet也会传送ServletRequest对象或HttpServletRequest对象。 <BR>所有Action类都扩展org.apache.struts.action.Action类，并且覆盖类中定义的某一个execute ()方法。有两个execute ()方法： <BR>处理非HTTP（一般的）请求： <BR>public ActionForward execute (ActionMapping action, <BR>Acionform form, <BR>ServletRequest request, <BR>ServletResponse response) <BR>throws java.lang.Exception <BR>处理HTTP请求： <BR>public ActionForward execute (ActionMapping action, <BR>Acionform form, <BR>HttpServletRequest request, <BR>HttpServletResponse response) <BR>throws java.lang.Exception <BR>Action类必须以”线程安全”的方式进行编程，因为控制器会令多个同时发生的请求共享同一个实例，相应的，在设计Action类时就需要注意以下几点： <BR>不能使用实例或静态变量存储特定请求的状态信息，它们会在同一个操作中 共享跨越请求的全局资源 <BR>如果要访问的资源（如JavaBeans和会话变量）在并行访问时需要进行保护，那么访问就要进行同步 <BR>Action类的方法 <BR>除了execute ()方法外，还有以下方法： <BR>可以获得或设置与请求相关联的区域： <BR>public Locale getLocale(HttpServletRequest request) <BR>public void setLocale(HttpServletRequest request,Locale locale) <BR>为应用程序获得消息资源： <BR>protected MessageResources getResources(HttpServletRequest request) <BR>protected MessageResources getResources(HttpServletRequest request,String key) <BR>检查用户是否点击表单上的”取消”键，如果是，将返回true: <BR>public Boolean isCancelled(HttpServletRequest request) <BR>当应用程序发生错误时，Action类能够使用下面方法存储错误信息： <BR>public void saveErrors(HttpServletRequest request,ActionErrors errors) <BR>public void saveMessages(HttpServletRequest request,ActionMessages messages) <BR>ActionError实例被用来存储错误信息，这个方法在错误关键字下的请求属性列表中存储ActionError对象。通过使用在struts标记库中定义的自定义标记，JSP页能够显示这些错误信息。ActionMessages 用来存储一些提示信息，不是错误，在jsp页面可以使用标记现实这些提示信息。 <BR>请求有效性处理,使用令牌可以有效的防止重复提交。 <BR>protected String generateToken(HttpServletRequest request) 创建一个令牌. <BR>protected boolean isTokenValid(HttpServletRequest request) 检查令牌是否有效 <BR>protected boolean isTokenValid(HttpServletRequest request,Boolean reset) 检查令牌是否有效，并且重置令牌（如果reset 是true） <BR>protected void resetToken(HttpServletRequest request) 重置令牌 <BR>protected void saveToken(HttpServletRequest request) 添加令牌 <BR>获取数据库连接 <BR>protected DataSource getDataSource(HttpServletRequest request) <BR>protected DataSource getDataSource(HttpServletRequest request, String key) <BR>其他的 <BR>ActionServlet getServlet() 可以获得本action的配置信息. <BR><BR>DispatchAction类 <BR>DispatchAction是Action的子类，主要功能可以实现，动态的方法调用。例如action中有一个方法update（ActionMapping mapping, Actionform form, HttpServletRequest request, HttpServletResponse response）, 可以通过 saveSubs cription.do?method=update来调用update方法。这个类不需要我们实现其他方法，我们只要实现 XXX（ActionMapping mapping, Actionform form, HttpServletRequest request, HttpServletResponse response）就可以了。 <BR>在http://www.chinajavaworld.net/forum/topic.cgi?forum=48&amp;topic=1166&amp;show=150和 <BR>http://www.chinajavaworld.net/forum/topic.cgi?forum=48&amp;topic=1129有对DispatchAction和LookupDispatchAction的详细介绍 <BR><BR><BR>SwitchAction类 <BR>SwitchAction是Action的子类，主要功能是将请求在不同的模块之间转发。对于大的项目很有用。具体看http://www.chinajavaworld.net/forum/topic.cgi?forum=48&amp;topic=1029&amp;show=0 <BR><BR>Actionform类 <BR>假设用户在应用程序中为每个表单都创建了一个Actionform bean，对于每个在struts-config.xml文件中定义的bean，框架在调用Action类的execute()方法之前会进行以下操作： <BR>在相关联的关键字下，它检查用于适当类的bean实例的用户会话(或请求)，如果在会话(或请求)中没有可用的bean，它就会自动创建一个新的bean并添加到用户的会话(或请求)中。至于是在会话还是请求取决于struts-config.xml 中Action 的scope属性。在创建Actionform的时候，系统会将请求中的值，进行相应的类型转换以后对Actionform进行初始化。 <BR>对于请求中每个与bean属性名称对应的参数，Action调用相应的设置方法。 <BR>当Action execute()被调用时，最新的Actionform bean传送给它，参数值就可以立即使用了。 <BR>Actionform类扩展org.apache.struts.action.Actionform类，程序开发人员创建的bean能够包含额外的属性，而且ActionServlet可能使用反射（允许从已加载的对象中回收信息）访问它。 <BR>Actionform类提供了另一种处理错误的手段，提供两个方法： <BR>Public ActionErrors validate(ActionMappin mapping, ServletRequest request) <BR>Public ActionErrors validate(ActionMappin mapping, HttpServletRequest request) <BR>你应该在自己的bean里覆盖validate()方法，并在配置文件里设置&lt;action&gt;元素的validate为true。在ActionServlet调用Action类前，它会调用validate()，如果返回的ActionErrors不是null，则Actinform会根据错误关键字将ActionErrors存储在请求属性列表中。 <BR>如果返回的不是null，而且长度大于0，则根据错误关键字将实例存储在请求的属性列表中，然后ActionServlet将响应转发到配置文件&lt;action&gt;元素的input属性所指向的目标。 <BR>如果需要执行特定的数据有效性检查，最好在Action类中进行这个操作，而不是在Actionform类中进行。 <BR>方法reset()可将bean的属性恢复到默认值： <BR>public void reset(ActionMapping mapping,HttpServletRequest request) <BR>public void reset(ActionMapping mapping,ServletRequest request) <BR>典型的ActionFrom bean只有属性的设置与读取方法（getXXX）,而没有实现事务逻辑的方法。只有简单的输入检查逻辑，使用的目的是为了存储用户在相关表单中输入的最新数据，以便可以将同一网页进行再生，同时提供一组错误信息，这样就可以让用户修改不正确的输入数据。而真正对数据有效性进行检查的是Action类或适当的事务逻辑bean。 <BR>Actionform中属性允许的类型boolean,byte,short,char,int,long,float,double,Boolean,Btye,Short, Character,Integer,Long,Float,Double,String,Date,Time,Timestamp，Object，以及以上类型的数组。 <BR>如果Actionform bean 的属性是一个数组则相应的设置和读取方法要做部分修改。对于数组setXXX(…),和getXXX()在jsp页面中意义不大。应该将添加setXXX( int index , …. ) 方法和getXXX ( int index )方法。这两个方法对于jsp页面来说更有意义。jsp中的property应该是XXX[0]。 <BR>如果Actionform bean的属性是一个 Map则应该提供方法setXXX( String key , … )和getXXX(String key)，使得jsp页面可以访问Map属性。jsp中的properry应该是XXX(keyname)。 <BR>通过getXXX(int index),setXXX (int index,…),getXXX(String key),setXXX(String key,…)可以方便的实现重复html输入框。 <BR>例如： <BR>public class Fooform extends Actionform { <BR>private String yourName; <BR>public String getYourName() { <BR>return yourName; <BR>} <BR>public void setYourName(String yourName) { <BR>this.yourName = yourName; <BR>} <BR>private final Map values = new HashMap(); <BR>public void setvalue(String key, Object value) { <BR>values.put(key, value); <BR>} <BR>public Object getvalue(String key) { <BR>if ( values.containsKey(key)){ <BR>return values.get(key); <BR>}else{ <BR>return ""; <BR>} <BR>} <BR>… <BR>} <BR><BR><BR>Validatorform类 <BR>org.apache.struts.validator.Validatorform类继承了Actionform类。使用本类可以方便的实现表单参数的校验。在校验的时候，使用在struts-config.xml中action元素中的name属性,确定要在validation.xml中取得校验规则的依据。 <BR>使用本类可以方便的解决同一个form在不同的Action中使用不同的校验规则的问题。在继承了Validatorform的类中不再需要我们去写validate方法。而是由Validatorform中的validate方法通过读取validation.xml中的描述信息来进行数据的校验。使用Validatorform也可以方便的实现在浏览器端实现利用脚本的校验。 <BR>Validatorform中的新增加的方法： <BR>int getPage() <BR>java.util.Map getResultvalueMap() <BR>ValidatorResults getValidatorResults() <BR>void setPage(int page) <BR>void setValidatorResults() <BR>使用本类可以大大提高我们的编程效率。 <BR>ValidatorActionform类 <BR>org.apache.struts.validator.ValidatorActionform类继承了Validatorform类。使用本类可以方便的实现表单参数的校验。在校验的时候，使用在struts-config.xml中action元素中的path属性,确定要在validation.xml中取得校验规则的依据。 <BR><BR>DynaActionform类 <BR>org.apache.struts.action.DynaActionform类继承了Actionform类。使用本类可以方便的实现动态表单。创建不确定的表单，如果jsp发生了变化只需要修改jsp页面和struts-config.xml文件中的form-bean元素就可以了。我们的程序中完全可以不用手工书写actionform的类了。 <BR>DynaActionform中的方法： <BR>boolean contains(String name, String key) 检测name（key）在actionform中是否存在。 <BR>Object get(String name) 从actionform中取得name的值。 <BR>Object get(String name,int index) 从actionform中取得 name对象的index个值。 <BR>Object get(String name,String key)从actionform中取得name对象的key对应的值。 <BR>Map getMap() 返回对象中包含的对象属性名列表。 <BR>void remove(String name, String key) 删除一个元素。 <BR>void set(String name, int index,Object value) 对actionform中的属性进行赋值。 <BR>void set(String name,Object value) <BR>void set(String name, Strign key ,Object value) <BR><BR>DynaValidatorform类 <BR>org.apache.struts.validator.DynaValidatorform类继承了DynaActionform类。使用本类可以方便的实现表单参数的校验。在校验的时候，使用在struts-config.xml中action元素中的name属性,确定要在validation.xml中取得校验规则的依据。 <BR>至于校验，同Validatorform。 <BR>DynaValidatorform中的新增加的方法： <BR>int getPage() <BR>java.util.Map getResultvalueMap() <BR>ValidatorResults getValidatorResults() <BR>void setPage(int page) <BR>void setValidatorResults() <BR><BR>DynaValidatorActionform类 <BR>org.apache.struts.validator.DynaValidatorActionform类继承了DynaValidatorform类。使用本类可以方便的实现表单参数的校验。在校验的时候，使用在struts-config.xml中action元素中的path属性,确定要在validation.xml中取得校验规则的依据。 <BR>至于校验，同Validatorform。 <BR><BR>ActionForward类 <BR>ActionForward类继承了org.apache.struts.config.ForwardConfig。 <BR>ForwardConfig的方法: <BR>String getName() 虚名字 <BR>String getPath() 实际路径 <BR>boolean getRedirect() 是否重定向 <BR>void setName(String name) <BR>void setPath(String path) <BR>void setRedirect(boolean redirect) <BR><BR>ActionForward目的是控制器将Action类的处理结果转发至目的地。 <BR>Action类获得ActionForward实例的句柄，然后可用两种方法返回到ActionServlet， <BR>ActionMapping实例被传送到execute()方法，使用actionMapping的findForward(String name)根据名称获取一个全局转发或本地转发。 <BR>另一种是调用下面的一个构造器来创建它们自己的一个实例： <BR>public ActionForward() <BR>public ActionForward(String path) <BR>public ActionForward(String path,Boolean redirect) <BR>public ActionForward(String name,String path,Boolean redirect) <BR>public ActionForward(String name,String path,Boolean redirect, boolean contextRelative) <BR>或下面的构造方法(下面是ActionForward的子类) <BR>ForwardingActionForward() <BR>ForwardingActionForward(String path) <BR>RedirectingActionForward() <BR>RedirectingActionForward(String path)</SPAN></P><img src ="http://www.blogjava.net/xieyunlong/aggbug/22717.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xieyunlong/" target="_blank">呓语的博客</a> 2005-12-06 14:55 <a href="http://www.blogjava.net/xieyunlong/archive/2005/12/06/22717.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入Struts 1.1</title><link>http://www.blogjava.net/xieyunlong/archive/2005/12/05/22615.html</link><dc:creator>呓语的博客</dc:creator><author>呓语的博客</author><pubDate>Mon, 05 Dec 2005 09:22:00 GMT</pubDate><guid>http://www.blogjava.net/xieyunlong/archive/2005/12/05/22615.html</guid><wfw:comment>http://www.blogjava.net/xieyunlong/comments/22615.html</wfw:comment><comments>http://www.blogjava.net/xieyunlong/archive/2005/12/05/22615.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xieyunlong/comments/commentRss/22615.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xieyunlong/services/trackbacks/22615.html</trackback:ping><description><![CDATA[<P align=center>作者：王和全 &nbsp;&nbsp;&nbsp;&nbsp;来自：IBM</P>
<P>　　作为基于MVC模式的Web应用最经典框架，Struts已经正式推出了1.1版本，该版本在以往版本的基础上，提供了许多激动人心的新功能。本文就将带你走进Struts 1.1去深入地了解这些功能。<BR>　　说明：希望本文的读者能有一定的Struts使用基础。</P>
<P>　　<STRONG>1、Model 2</STRONG></P>
<P>　　Struts是基于Model 2之上的，而Model 2是经典的MVC（模型－视图－控制器）模型的Web应用变体，这个改变主要是由于网络应用的特性--HTTP协议的无状态性引起的。Model 2的目的和MVC一样，也是利用控制器来分离模型和视图，达到一种层间松散耦合的效果，提高系统灵活性、复用性和可维护性。在多数情况下，你可以将Model 2与MVC等同起来。</P>
<P>　　下图表示一个基于Java技术的典型网络应用，从中可以看出Model 2中的各个部分是如何对应于Java中各种现有技术的。</P>
<P align=center><IMG height=237 alt="" src="http://www.javafan.net/uploadfiles/20041210100421100.gif" width=521 border=0></P>
<P>　　在利用Model 2之前，我们是把所有的表示逻辑和业务逻辑都集中在一起（比如大杂烩似的JSP），有时也称这种应用模式为Model 1，Model 1的主要缺点就是紧耦合，复用性差以及维护成本高。 </P>
<P>　　<STRONG>2、Struts 1.1 和Model 2</STRONG> </P>
<P>　　既然Struts 1.1是基于Model 2之上，那它的底层机制也就是MVC，下面是Struts 1.1中的MVC实现示意图：</P>
<P align=center><IMG height=263 alt="" src="http://www.javafan.net/uploadfiles/20041210100421200.jpg" width=553 border=0><BR>图解说明：其中不同颜色代表MVC的不同部分：红色（控制器）、紫色（模型）和绿色（视图）</P>
<P>　　首先，控制器（ActionServlet）进行初始化工作，读取配置文件（struts-config.xml），为不同的Struts模块初始化相应的ModuleConfig对象。比如配置文件中的Action映射定义都保存在ActionConfig集合中。相应地有ControlConfig集合、FormBeanConfig集合、ForwardConfig集合和MessageResourcesConfig集合等。</P>
<P>　　提示：模块是在Struts 1.1中新提出的概念，在稍后的内容中我们将详细介绍，你现在可以简单地把模块看作是一个子系统，它们共同组成整个应用，同时又各自独立。Struts 1.1中所有的处理都是在特定模块环境中进行的。模块的提出主要是为了解决Struts 1.0中单配置文件的问题。</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>　　提示：其实在Struts 1.1中，ActionMapping的作用完全可以由ActionConfig来替代，只不过由于它是公共API的一部分以及兼容性的问题得以保留。ActionMapping通过继承ActionConfig来获得与其一致的功能，你可以等同地看待它们。同理，其它例如ActionForward与ForwardConfig的关系也是如此。</P>
<P>　　下图给出了客户端从发出请求到获得响应整个过程的图解说明。</P>
<P align=center><IMG height=520 alt="" src="http://www.javafan.net/uploadfiles/20041210100421300.jpg" width=595 border=0></P>
<P>　　下面我们就来详细地讨论一下其中的每个部分，在这之前，先来了解一下模块的概念。</P>
<P>　　<STRONG>3、模块</STRONG></P>
<P>　　我们知道，在Struts 1.0中，我们只能在web.xml中为ActionServlet指定一个配置文件，这对于我们这些网上的教学例子来说当然没什么问题，但是在实际的应用开发过程中，可能会有些麻烦。因为许多开发人员都可能同时需要修改配置文件，但是配置文件只能同时被一个人修改，这样肯定会造成一定程度上的资源争夺，势必会影响开发效率和引起开发人员的抱怨。</P>
<P>　　在Struts 1.1中，为了解决这个并行开发的问题，提出了两种解决方案：</P>
<P>　　1. 多个配置文件的支持 <BR>　　2. 模块的支持 </P>
<P>　　支持多个配置文件，是指你能够为ActionServlet同时指定多个xml配置文件，文件之间以逗号分隔，比如Struts提供的MailReader演示例子中就采用该种方法。</P>
<P style="BACKGROUND: #eeeeee">&lt;!-- Action Servlet Configuration --&gt;<BR>&lt;servlet&gt;<BR>&nbsp;&lt;servlet-name&gt;action&lt;/servlet-name&gt;<BR>&nbsp;&lt;servlet-class&gt;org.apache.struts.action.ActionServlet&lt;/servlet-class&gt;<BR>&nbsp;&lt;init-param&gt;<BR>&nbsp;&nbsp;&lt;param-name&gt;config&lt;/param-name&gt;<BR>&nbsp;&nbsp;&lt;param-value&gt;/WEB-INF/struts-config.xml, /WEB-INF/struts-config-registration.xml&lt;/param-value&gt;<BR>&nbsp;&lt;/init-param&gt; <BR>&nbsp;&lt;load-on-startup&gt;1&lt;/load-on-startup&gt;<BR>&lt;/servlet&gt;</P>
<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、为每个模块准备一个配置文件<BR>　　2、配置web.xml文件，通知控制器</P>
<P>　　决定采用多个模块以后，你需要将这些信息告诉控制器，这需要在web.xml文件进行配置。下面是一个典型的多模块配置：</P>
<P style="BACKGROUND: #eeeeee">&lt;init-param&gt;<BR>&nbsp;&lt;param-name&gt;config&lt;/param-name&gt;<BR>&nbsp;&lt;param-value&gt;/WEB-INF/struts-config.xml&lt;/param-value&gt;<BR>&lt;/init-param&gt;<BR>&lt;init-param&gt;<BR>&nbsp;&lt;param-name&gt;config/customer&lt;/param-name&gt; <BR>&nbsp;&lt;param-value&gt;/WEB-INF/struts-config-customer.xml&lt;/param-value&gt;<BR>&lt;/init-param&gt;<BR>&lt;init-param&gt; <BR>&nbsp;&lt;param-name&gt;config/order&lt;/param-name&gt;<BR>&nbsp;&lt;param-value&gt;/WEB-INF/struts-config-order.xml&lt;/param-value&gt;<BR>&lt;/init-param&gt;</P>
<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>
<P style="BACKGROUND: #eeeeee">... <BR>&lt;struts-config&gt;<BR>&nbsp;... <BR>&nbsp;&lt;global-forwards&gt;<BR>&nbsp;&nbsp;&lt;forward name="toModuleB"<BR>&nbsp;&nbsp;&nbsp;contextRelative="true"&nbsp; <BR>&nbsp;&nbsp;&nbsp;path="/moduleB/index.do" <BR>&nbsp;&nbsp;redirect="true"/&gt;&nbsp;&nbsp; <BR>&nbsp;... <BR>&nbsp;&lt;/global-forwards&gt;&nbsp; <BR>&nbsp;...&nbsp;&nbsp; <BR>&lt;/struts-config&gt;</P>
<P>　　可以看出，只需要在原有的path属性前加上模块名，同时将contextRelative属性置为true即可。此外，你也可以在&lt;action&gt;中定义一个类似的本地&lt;forward&gt;。</P>
<P style="BACKGROUND: #eeeeee">&lt;action-mappings&gt;<BR>&nbsp;&lt;!-- Action mapping for profile form --&gt;<BR>&nbsp;&lt;action path="/login" <BR>&nbsp;type="com.ncu.test.LoginAction"&nbsp; <BR>&nbsp;name="loginForm"&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;scope="request"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;input="tile.userLogin"<BR>&nbsp;validate="true"&gt;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&lt;forward name="success" contextRelative="true" path="/moduleA/login.do"/&gt; <BR>&nbsp;&lt;/action&gt; <BR>&lt;/action-mappings&gt;</P>
<P>　　如果你已经处在其他模块，需要转回到缺省模块，那应该类似下面这样定义，即模块名为空。</P>
<P>　　&lt;forward name="success" contextRelative="true" path="/login.do"/&gt;</P>
<P>　　此外，你也可以使用org.apache.struts.actions.SwitchAction，例如：</P>
<P style="BACKGROUND: #eeeeee">...<BR>&lt;action-mappings&gt; <BR>&nbsp;&lt;action path="/toModule" <BR>&nbsp;type="org.apache.struts.actions.SwitchAction"/&gt;&nbsp; <BR>&nbsp;...&nbsp;&nbsp;&nbsp; <BR>&lt;/action-mappings&gt;&nbsp; <BR>...</P>
<P>　　<STRONG>4、ActionServlet</STRONG></P>
<P>　　我们首先来了解MVC中的控制器。在Struts 1.1中缺省采用ActionServlet类来充当控制器。当然如果ActionServlet不能满足你的需求，你也可以通过继承它来实现自己的类。这可以在/WEB-INF/web.xml中来具体指定。</P>
<P>　　要掌握ActionServlet，就必须了解它所扮演的角色。首先，ActionServlet表示MVC结构中的控制器部分，它需要完成控制器所需的前端控制及转发请求等职责。其次，ActionServlet被实现为一个专门处理HTTP请求的Servlet，它同时具有servlet的特点。在Struts 1.1中它主要完成以下功能：</P>
<P>　　□ 接收客户端请求<BR>　　□ 根据客户端的URI将请求映射到一个相应的Action类<BR>　　□ 从请求中获取数据填充Form Bean（如果需要）<BR>　　□ 调用Action类的execute()方法获取数据或者执行业务逻辑<BR>　　□ 选择正确的视图响应客户</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>
<P>　　□ application <BR>　　□ bufferSize <BR>　　□ content <BR>　　□ debug <BR>　　□ factory <BR>　　□ formBean <BR>　　□ forward <BR>　　□ locale <BR>　　□ mapping <BR>　　□ maxFileSize <BR>　　□ multipartClass <BR>　　□ nocache <BR>　　□ null <BR>　　□ tempDir </P>
<P>　　ActionServlet根据不同的模块来初始化ModuleConfig类，并在其中以XXXconfig集合的方式保存该模块的各种配置信息，比如ActionConfig，FormBeanConfig等。</P>
<P>　　初始化工作完成之后，ActionServlet准备接收客户请求。针对每个请求，方法process(HttpServletRequest request, HttpServletResponse response)将被调用。该方法指定具体的模块，然后调用该模块的RequestProcessor的process方法。</P>
<P style="BACKGROUND: #eeeeee">protected void process(HttpServletRequest request, <BR>&nbsp;&nbsp;HttpServletResponse response) <BR>&nbsp;&nbsp;throws IOException, ServletException {<BR><BR>&nbsp;RequestUtils.selectModule(request, getServletContext());&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;getRequestProcessor(getModuleConfig(request)).process(request, response);<BR>}</P>
<P>　　RequestProcessor包含了Struts控制器的所有处理逻辑，它调用不同的processXXX方法来完成不同的处理。下表列出其中几个主要的方法：</P>
<TABLE cellSpacing=1 cellPadding=1 width=600 align=center bgColor=#999999 border=0>
<TBODY>
<TR bgColor=#ffffff>
<TD align=middle width=200 height=23>方法</TD>
<TD align=middle width=400>功能</TD></TR>
<TR bgColor=#ffffff>
<TD height=23>processPath</TD>
<TD>获取客户端的请求路径</TD></TR>
<TR bgColor=#ffffff>
<TD height=23>processMapping </TD>
<TD>利用路径来获得相应的ActionMapping</TD></TR>
<TR bgColor=#ffffff>
<TD height=23>processActionForm</TD>
<TD>初始化ActionForm（如果需要）并存入正确的scope中</TD></TR>
<TR bgColor=#ffffff>
<TD height=23>processActionCreate</TD>
<TD>初始化Action</TD></TR>
<TR bgColor=#ffffff>
<TD height=23>processActionPerform</TD>
<TD>调用Action的execute方法</TD></TR>
<TR bgColor=#ffffff>
<TD height=23>processForwardConfig</TD>
<TD>处理Action返回的ActionForward</TD></TR></TBODY></TABLE>
<P>　　<STRONG>5、ActionForm</STRONG></P>
<P>　　对于ActionForm你可以从以下几个方面来理解它：</P>
<P>　　1. ActionForm表示HTTP窗体中的数据，可以将其看作是模型和视图的中介，它负责保存视图中的数据供模型或者视图使用。Struts 1.1文档中把它比作HTTP和Action之间的防火墙，这体现了ActionForm具有的过滤保护的作用，只有通过ActionForm验证的数据才能够发送到Action处理。 <BR>　　2. ActionForm是与一个或多个ActionConfig关联的JavaBean，在相应的action的execute方法被调用之前，ActionForm会自动利用请求参数来填充自己（初始化属性）。 <BR>　　3. ActionForm是一个抽象类，你必须通过继承来实现自己的类。</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>　　DynaActionForm类</P>
<P>　　DynaActionForm的目的就是减少ActionForm的数目，利用它你不必创建一个个具体的ActionForm类，而是在配置文件中配置出所需的虚拟ActionForm。例如，在下表中通过指定&lt;form-bean&gt;的type为"org.apache.struts.action.DynaActionForm"来创建一个动态的ActionForm--loginForm。</P>
<P style="BACKGROUND: #eeeeee">&lt;form-beans&gt;<BR>&nbsp;&lt;form-bean name="loginForm" type="org.apache.struts.action.DynaActionForm"&gt;&nbsp; <BR>&nbsp;&nbsp;&lt;form-property name="actionClass" type="java.lang.String"/&gt;<BR>&nbsp;&nbsp;&lt;form-property name="username" type="java.lang.String"/&gt;<BR>&nbsp;&nbsp;&lt;form-property name="password" type="java.lang.String"/&gt; <BR>&nbsp;&lt;/form-bean&gt; <BR>&lt;/form-beans&gt;</P>
<P>　　动态的ActionForm的使用方法跟普通的ActionForm相同，但是要注意一点。普通的ActionForm对象需要为每个属性提供getter和setter方法，以上面的例子而言，我们需要提供getUsername() 和 setUsername()方法取得和设置username属性，同样地有一对方法用于取得和设置password属性和actionClass属性。</P>
<P>　　如果使用DynaActionForm，它将属性保存在一个HashMap类对象中，同时提供相应的get(name) 和 set(name)方法，其中参数name是要访问的属性名。例如要访问DynaActionForm中username的值，可以采用类似的代码：</P>
<P>　　String username = (String)form.get("username")；</P>
<P>　　由于值存放于一个HashMap对象，所以要记得对get()方法返回的Object对象做强制性类型转换。正是由于这点区别，如果你在Action中非常频繁地使用ActionForm对象，建议还是使用普通的ActionForm对象。</P>
<P>　　在Struts 1.1中，除了DynaActionForm以外，还提供了表单输入自动验证的功能，在包org.apache.struts.validator中提供了许多有用的类，其中最常见的就是DynaValidatorForm类。</P>
<P>　　DynaValidatorForm类</P>
<P>　　DynaValidatorForm是DynaActionForm的子类，它能够提供动态ActionForm和自动表单输入验证的功能。和使用DynaActionForm类似，你必须首先在配置文件中进行配置：</P>
<P style="BACKGROUND: #eeeeee">&lt;form-beans&gt;<BR>&nbsp;&lt;form-bean name="loginForm" type="org.apache.struts.validator.DynaValidatorForm"&gt; <BR>&nbsp;&nbsp;&lt;form-property name="actionClass" type="java.lang.String"/&gt;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&lt;form-property name="username" type="java.lang.String"/&gt; <BR>&nbsp;&nbsp;&lt;form-property name="password" type="java.lang.String"/&gt;&nbsp; <BR>&nbsp;&lt;/form-bean&gt;<BR>&lt;/form-beans&gt;</P>
<P>　　同时要定义验证的插件：</P>
<P style="BACKGROUND: #eeeeee">&lt;plug-in className="org.apache.struts.validator.ValidatorPlugIn"&gt;<BR>&nbsp;&lt;set-property property="pathnames"&nbsp; <BR>&nbsp;value="/WEB-INF/validator-rules.xml,&nbsp; <BR>&nbsp;/WEB-INF/validation.xml"/&gt;<BR>&lt;/plug-in&gt;</P>
<P>　　其中的validator.xml和validator-rules.xml分别表示验证定义和验证规则的内容（可以合并在一起），比如针对上例中的DynaValidatorForm，我们有如下验证定义（validator.xml）：</P>
<P style="BACKGROUND: #eeeeee">&lt;?xml version="1.0" encoding="ISO-8859-1" ?&gt;<BR>&lt;!DOCTYPE form-validation PUBLIC&nbsp; <BR>"-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.0//EN"&nbsp; <BR>"http://jakarta.apache.org/commons/dtds/validator_1_0.dtd"&gt;<BR>&lt;!--&nbsp;&nbsp;&nbsp; Validation Rules&nbsp;&nbsp;&nbsp; $Id: validation.xml--&gt; <BR><BR>&nbsp;&lt;form-validation&gt; <BR>&nbsp;&lt;!-- ========== Default Language Form Definitions ===================== --&gt;<BR>&nbsp;&lt;formset&gt;&nbsp; <BR>&nbsp;&lt;form name="loginForm"&gt;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&lt;field property="username" depends="required, minlength,maxlength"&gt; <BR>&nbsp;&nbsp;&nbsp;&lt;arg0&nbsp;&nbsp; key="prompt.username"/&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&lt;arg1&nbsp;&nbsp; key="${var:minlength}" name="minlength" resource="false"/&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&lt;arg2&nbsp;&nbsp; key="${var:maxlength}" name="maxlength" resource="false"/&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&lt;var&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;var-name&gt;maxlength&lt;/var-name&gt;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;var-value&gt;16&lt;/var-value&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&lt;/var&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&lt;var&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;var-name&gt;minlength&lt;/var-name&gt;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;var-value&gt;3&lt;/var-value&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&lt;/var&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&lt;/field&gt;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&lt;field property="password" depends="required, minlength,maxlength" bundle="alternate"&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&lt;arg0&nbsp;&nbsp; key="prompt.password"/&gt;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&lt;arg1&nbsp;&nbsp; key="${var:minlength}" name="minlength" resource="false"/&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&lt;arg2&nbsp;&nbsp; key="${var:maxlength}" name="maxlength" resource="false"/&gt;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&lt;var&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;var-name&gt;maxlength&lt;/var-name&gt;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;var-value&gt;16&lt;/var-value&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&lt;/var&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&lt;var&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;var-name&gt;minlength&lt;/var-name&gt; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;var-value&gt;3&lt;/var-value&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&lt;/var&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&lt;/field&gt;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&lt;/form&gt;&nbsp;&nbsp; <BR>&nbsp;&lt;/formset&gt;<BR>&nbsp;&lt;/form-validation&gt;</P>
<P>　　从上述定义中，我们可以看到对于字段username有三项验证：required, minlength, maxlength，意思是该字段不能为空，而且长度在3和16之间。而validator-rules.xml文件则可以采用Struts提供的缺省文件。注意在&lt;form-bean&gt;中定义的form是如何与validation.xml中的form关联起来的。最后，要启动自动验证功能，还需要将Action配置的validate属性设置为true。</P>
<P style="BACKGROUND: #eeeeee">　　&lt;action path="/login"&nbsp; <BR>　　type="com.ncu.test.LoginAction"<BR>　　name="loginForm"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>　　scope="request"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>　　input="tile.userLogin"validate="true"&gt;</P>
<P>　　此时，Struts将根据xml配置文件中的定义来检验表单输入，并将不符合要求的错误信息输出到页面。但是你可能会想：这个功能虽然好，可是什么检验都跑到服务器端执行，效率方面和用户易用性方面是不是有些问题？你可能会怀念起那简单的JavaScript客户端验证。</P>
<P>　　不用担心，在Struts 1.1中也支持JavaScript客户端验证。如果你选择了客户端验证，当某个表单被提交以后，Struts 1.1启动客户端验证，如果浏览器不支持JavaScript验证，则服务器端验证被启动，这种双重验证机制能够最大限度地满足各种开发者的需要。JavaScript验证代码也是在validator-rules.xml文件中定义的。要启动客户端验证，你必须在相应的JSP文件中做如下设置：</P>
<P>　　1. 为&lt;html:form&gt;增加onsubmit属性 <BR>　　2. 设置Javascript支持 </P>
<P>　　下表中列出了一JSP文件的示例代码，红字部分为Javascript验证所需代码。</P>
<P style="BACKGROUND: #eeeeee">&nbsp;&lt;%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %&gt;<BR>&nbsp;&lt;table bgcolor="#9AFF9A" cellspacing="0" cellpadding="10" border="1" width="100%"&gt;<BR>&nbsp;&lt;tr&gt;<BR>&nbsp;&lt;td&gt; <BR>&nbsp;&lt;table cellspacing="0" cellpadding="0" border="0" width="100%"&gt; <BR>&nbsp;&lt;tr bgcolor="#696969"&gt; <BR>&nbsp;&nbsp;&lt;td align="center"&gt;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&lt;font color="#FFFFFF"&gt;Panel 3: Profile&lt;/font&gt;&nbsp; <BR>&nbsp;&nbsp;&lt;/td&gt;<BR>&nbsp;&nbsp;&lt;/tr&gt; <BR>&nbsp;&lt;tr&gt;&nbsp; <BR>&nbsp;&nbsp;&lt;td&gt;&lt;br&gt; <BR>&nbsp;&nbsp;&lt;html:errors/&gt;&nbsp; <BR>&nbsp;&nbsp;&lt;html:form action="/login.do" focus="username"&nbsp; onsubmit="return validateLoginForm(this);"&gt;&nbsp; <BR>&nbsp;&nbsp;&lt;html:hidden property="actionClass"/&gt;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&lt;center&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&lt;table&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&lt;tr&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&lt;td&gt;UserName:&lt;/td&gt;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&lt;td&gt;&lt;html:text property="username" size="20"/&gt;&lt;/td&gt; <BR>&nbsp;&nbsp;&nbsp;&lt;/tr&gt; <BR>&nbsp;&nbsp;&nbsp;&lt;tr&gt;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&lt;td&gt;Password:&lt;/td&gt;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&lt;td&gt;&lt;html:password property="password" size="20"/&gt;&lt;/td&gt;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&lt;/tr&gt;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&lt;tr&gt;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&lt;td colspan=2&gt;&lt;html:submit property="submitProperty" value="Submit"/&gt;&lt;/td&gt;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&lt;/table&gt;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&lt;/center&gt;&nbsp; <BR>&nbsp;&nbsp;&lt;/html:form&gt; <BR>&nbsp;&nbsp;&lt;html:javascript formName="loginForm" dynamicJavascript="true" staticJavascript="false"/&gt;&nbsp; <BR>&nbsp;<BR>&nbsp;<FONT color=#ff0000>&lt;script language="Javascript1.1" src="staticJavascript.jsp"&gt;&lt;/script&gt;</FONT>&nbsp; <BR>&nbsp;&lt;/td&gt; <BR>&nbsp;&lt;/tr&gt; <BR>&nbsp;&lt;/table&gt;<BR>&nbsp;&lt;/td&gt;<BR>&nbsp;&lt;/tr&gt;<BR>&nbsp;&lt;/table&gt;</P>
<P>　　其中onsubmit的值为"return validateLoginForm(this);"，它的语法为：</P>
<P>　　return validate + struts-config.xml中定义的form-bean名称 + (this);</P>
<P>　　staticJavascript.jsp的内容为：</P>
<P style="BACKGROUND: #eeeeee">　　&lt;%@ page language="java" %&gt;<BR>　　&lt;%-- set document type to Javascript (addresses a bug in Netscape according to a web resource --%&gt;<BR>　　&lt;%@ page contentType="application/x-javascript" %&gt;<BR>　　&lt;%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %&gt;<BR>　　&lt;html:javascript dynamicJavascript="false" staticJavascript="true"/&gt;</P>
<P>　　如果validator-rules.xml中定义的基本验证功能不能满足你的需求，你可以自己添加所需的验证类型。</P>
<P>　　<STRONG>6、Action</STRONG></P>
<P>　　我们通过继承Action类来实现具体的执行类。具体Action类的功能一般都在execute（以前是perform方法）方法中完成，其中主要涉及到以下几个方面：</P>
<P>　　1. 辅助ActionForm进行一些表单数据的检查。 <BR>　　2. 执行必要的业务逻辑，比如存取数据库，调用实体bean等。 <BR>　　3. 更新服务器端的bean数据，后续对象中可能会用到这些数据，比如在JSP中利用bean:write来获得这些数据。 <BR>　　4. 根据处理结果决定程序的去处，并以ActionForward对象的形式返回给ActionServlet。 </P>
<P>　　提示：由于在Action和ActionForm中都可以实现验证方法，那么如何来安排它们之间的分工呢？一般来说，我们秉着MVC分离的原则，也就是视图级的验证工作放在ActionForm来完成，比如输入不能为空，email格式是否正确，利用ValidatorForm可以很轻松地完成这些工作。而与具体业务相关的验证则放入Action中，这样就可以获得最大ActionForm重用性的可能。</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>　　<STRONG>7、宣称式异常处理</STRONG></P>
<P>　　和EJB中的宣称式事务处理概念类似，宣称式异常处理其实就是可配置的异常处理，你可以在配置文件中指定由谁来处理Action类中掷出的某种异常。你可以按照以下步骤来完成该功能：</P>
<P>　　1. 实现org.apache.struts.action.ExceptionHandler的子类，覆盖execute方法，在该方法中处理异常并且返回一个ActionForward对象 <BR>　　2. 在配置文件中配置异常处理对象，你可以配置一个全局的处理类或者单独为每个Action配置处理类 </P>
<P>　　下表就定义了一个全局的处理类CustomizedExceptionHandler，它被用来处理所有的异常。</P>
<P style="BACKGROUND: #eeeeee">&lt;global-exceptions&gt; <BR>&lt;exception <BR>&nbsp;handler="com.yourcorp.CustomizedExceptionHandler" <BR>&nbsp;key="global.error.message" <BR>&nbsp;path="/error.jsp"&nbsp;&nbsp;&nbsp; <BR>&nbsp;scope="request"&nbsp;&nbsp;&nbsp; <BR>&nbsp;type="java.lang.Exception"/&gt;<BR>&lt;/global-exceptions&gt; </P>
<P>　　其中具体的参数含义，可以参考ExceptionHandler.java源文件。</P>
<P>　　<STRONG>8、taglib</STRONG></P>
<P>　　讲完了模型和控制器，接下来我们要涉及的是视图。视图的角色主要是由JSP来完成，从JSP的规范中可以看出，在视图层可以"折腾"的技术不是很多，主要的就是自定义标记库的应用。Struts 1.1在原有的四个标记库的基础上新增了两个标记库--Tiles和Nested。</P>
<P>　　其中Tiles除了替代Template的基本模板功能外，还增加了布局定义、虚拟页面定义和动态页面生成等功能。Tiles强大的模板功能能够使页面获得最大的重用性和灵活性，此外可以结合Tiles配置文件中的页面定义和Action的转发逻辑，即你可以将一个Action转发到一个在Tiles配置文件中定义的虚拟页面，从而减少页面的数量。比如，下表中的Action定义了一个转发路径，它的终点是tile.userMain，而后者是你在Tiles配置文件中定义的一个页面。</P>
<P style="BACKGROUND: #eeeeee">&lt;!-- ========== Action Mapping Definitions ============================== --&gt;<BR>&lt;action-mappings&gt;&nbsp; <BR>&lt;!-- Action mapping for profile form --&gt; <BR>&nbsp;&lt;action path="/login"&nbsp;&nbsp; <BR>&nbsp;&nbsp;type="com.ncu.test.LoginAction"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;name="loginForm"&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;scope="request"&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;input="tile.userLogin"<BR>&nbsp;&nbsp;validate="true"&gt;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&lt;forward name="success" path="tile.userMain"/&gt;&nbsp;&nbsp; <BR>&nbsp;&lt;/action&gt; <BR>&lt;/action-mappings&gt;</P>
<P>　　Tiles配置文件：tiles-defs.xml</P>
<P style="BACKGROUND: #eeeeee">&lt;!DOCTYPE tiles-definitions PUBLIC <BR>"-//Apache Software Foundation//DTD Tiles Configuration//EN"<BR>&nbsp;&nbsp;"http://jakarta.apache.org/struts/dtds/tiles-config.dtd"&gt;<BR>&lt;tiles-definitions&gt;&nbsp; <BR>&lt;!-- =======================================================&nbsp; --&gt; <BR>&lt;!-- Master definitions&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --&gt;<BR>&lt;!-- =======================================================&nbsp; --&gt; <BR>&lt;!-- Page layout used as root for all pages. --&gt; <BR><BR>&lt;definition name="rootLayout" path="/tiles-layouts/rootLayout.jsp"&gt; <BR>&nbsp;&lt;put name="titleString" value="CHANGE-ME"/&gt;&nbsp;&nbsp; <BR>&nbsp;&lt;put name="topMenu" value="/tiles-components/topMenu.jsp"/&gt; <BR>&nbsp;&lt;put name="leftMenu" value="/tiles-components/panel1.jsp"/&gt;&nbsp; <BR>&nbsp;&lt;put name="body" value="CHANGE-ME"/&gt;&nbsp;&nbsp; <BR>&nbsp;&lt;put name="footer" value="/tiles-components/footer.jsp"/&gt; <BR>&lt;/definition&gt; <BR><BR>&lt;!-- =======================================================&nbsp; --&gt; <BR>&lt;!-- Page definitions &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--&gt;&nbsp; <BR>&lt;!-- =======================================================&nbsp; --&gt; <BR><BR>&lt;!-- User Login page --&gt; <BR>&lt;definition name="tile.userLogin" extends="rootLayout"&gt; <BR>&nbsp;&lt;put name="titleString" value="User Login"/&gt;&nbsp; <BR>&nbsp;&lt;put name="body" value="/src/userLogin.jsp"/&gt; <BR>&lt;/definition&gt;&nbsp; <BR>&lt;!-- User Main page --&gt; <BR>&lt;definition name="tile.userMain" extends="rootLayout"&gt; <BR>&nbsp;&lt;put name="titleString" value="User Main"/&gt;&nbsp; <BR>&nbsp;&lt;put name="body" value="/src/userMain.jsp"/&gt; <BR>&lt;/definition&gt;<BR>&lt;/tiles-definitions&gt;</P>
<P>　　而Nested标记库的作用是让以上这些基本标记库能够嵌套使用，发挥更大的作用。</P>
<P>　　<STRONG>9、Commons Logging 接口</STRONG></P>
<P>　　所谓的Commons Logging接口，是指将日志功能的使用与日志具体实现分开，通过配置文件来指定具体使用的日志实现。这样你就可以在Struts 1.1中通过统一的接口来使用日志功能，而不去管具体是利用的哪种日志实现，有点于类似JDBC的功能。Struts 1.1中支持的日志实现包括：Log4J，JDK Logging API， LogKit，NoOpLog和SimpleLog。</P>
<P>　　你可以按照如下的方式来使用Commons Logging接口（可以参照Struts源文中的许多类实现）：</P>
<P style="BACKGROUND: #eeeeee">package com.foo;<BR>// ...<BR>import org.apache.commons.logging.Log;<BR>import org.apache.commons.logging.LogFactory;<BR>//...<BR>&nbsp;public class Foo {&nbsp;&nbsp;&nbsp; <BR>&nbsp;// ...&nbsp;&nbsp;&nbsp; <BR>&nbsp;private static Log log = LogFactory.getLog(Foo.class);<BR>&nbsp;// ...&nbsp;&nbsp;&nbsp; <BR>&nbsp;public void setBar(Bar bar) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;if (log.isTraceEnabled()) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;log.trace("Setting bar to " + bar);&nbsp;&nbsp; <BR>&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;this.bar = bar;&nbsp;&nbsp; <BR>&nbsp;}<BR>// ...<BR>}</P>
<P>　　而开启日志功能最简单的办法就是在WEB-INF/classes目录下添加以下两个文件：</P>
<P>　　commns-logging.properties文件：</P>
<P style="BACKGROUND: #eeeeee">　　# Note: The Tiles framework now uses the commons-logging package to output different information or debug statements. <BR>　　Please refer to this package documentation to enable it. The simplest way to enable logging is to create two files in <BR>　　WEB-INF/classes:<BR>　　# commons-logging.properties<BR>　　# org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog<BR>　　# simplelog.properties<BR>　　# # Logging detail level,<BR>　　# # Must be one of ("trace", "debug", "info", "warn", "error", or "fatal").<BR>　　#org.apache.commons.logging.simplelog.defaultlog=trace<BR>　　org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog</P>
<P>　　simplelog.properties文件：</P>
<P style="BACKGROUND: #eeeeee">　　# Logging detail level,<BR>　　# Must be one of ("trace", "debug", "info", "warn", "error", or "fatal").<BR>　　org.apache.commons.logging.simplelog.defaultlog=fatal</P>
<P>　　这里我们采用的日志实现是SimpleLog，你可以在simplelog.properties文件指定日志明细的级别：trace，debug，info，warn，error和fatal，从trace到fatal错误级别越来越高，同时输出的日志信息也越来越少。而这些级别是和org.apache.commons.logging.log接口中的方法一一对应的。这些级别是向后包含的，也就是前面的级别包含后面级别的信息。</P><img src ="http://www.blogjava.net/xieyunlong/aggbug/22615.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xieyunlong/" target="_blank">呓语的博客</a> 2005-12-05 17:22 <a href="http://www.blogjava.net/xieyunlong/archive/2005/12/05/22615.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>