﻿<?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-辰o(^o^)o的专栏[除非注释原创，其它文章基本来源于网络]-文章分类-Struts</title><link>http://www.blogjava.net/jackybu/category/1614.html</link><description>&lt;a href="http://www.fastonlineusers.com"&gt;&lt;b&gt;&lt;font color=red&gt;共有&lt;script src=http://fastonlineusers.com/online.php?d=jackybu.blogjava.net&gt;&lt;/script&gt;人在同时阅读此Blog&lt;/font&gt;&lt;/b&gt;&lt;/a&gt;</description><language>zh-cn</language><lastBuildDate>Tue, 27 Feb 2007 23:04:23 GMT</lastBuildDate><pubDate>Tue, 27 Feb 2007 23:04:23 GMT</pubDate><ttl>60</ttl><item><title>Dreamweaver和Struts的整合 </title><link>http://www.blogjava.net/jackybu/articles/10313.html</link><dc:creator>辰</dc:creator><author>辰</author><pubDate>Wed, 17 Aug 2005 02:46:00 GMT</pubDate><guid>http://www.blogjava.net/jackybu/articles/10313.html</guid><wfw:comment>http://www.blogjava.net/jackybu/comments/10313.html</wfw:comment><comments>http://www.blogjava.net/jackybu/articles/10313.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jackybu/comments/commentRss/10313.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jackybu/services/trackbacks/10313.html</trackback:ping><description><![CDATA[<TABLE height=20 cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD class=ContentParaTitle>Dreamweaver和Struts的整合</TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=0 width=700 border=0>
<TBODY>
<TR>
<TD class=ContentPara>
<P>使用Struts开发web应用是非常有吸引力的，在显示层我们通常采用jsp，当然我们编辑网页是首选工具就是Dreamweaver，而Dreamweaver确不能识别Struts的标记库，在做网页设计时通常带来不小麻烦，没有代码提示和所见即所得的界面。下面我们将提供一个方案来解决这个问题。</P>
<P>1 首先在Dreamweaver中导入Struts的标签库，这样在编写代码时可以出现动态代码提示。点击“编辑|标签库…”，在“标签库编辑器”导入Struts的taglib文件，在这些标签用于在JSP文件上。</P></TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=0 bgColor=#999999 border=0>
<TBODY>
<TR>
<TD class=imageTable><IMG height=476 src="http://www.jetmaven.net/documents/p_image/j_dw_struts_combination_1.jpg" width=611></TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=0 width=700 border=0>
<TBODY>
<TR>
<TD class=ContentPara>
<P>2 下载“Animalsgroup Struts taglibs Translator”，该插件可以将以Struts的一些标记以图形方式显示出来，当前支持html和bean标签。</P>
<P><A href="http://www.jetmaven.net/documents/j_files/ast-03.mxp" target=_blank>点击此处</A>下载插件。</P>
<P>下载后使用“Macromedia扩展管理器”安装该插件。</P></TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=0 bgColor=#999999 border=0>
<TBODY>
<TR>
<TD class=imageTable><IMG height=424 src="http://www.jetmaven.net/documents/p_image/j_dw_struts_combination_2.jpg" width=565></TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=0 width=700 border=0>
<TBODY>
<TR>
<TD class=ContentPara>
<P>3 创一个jsp文件，导入相应的Struts的taglib声明，进行设计吧。html的标签可以显示啦，和普通的设计完全一样，不过没有属性栏，你需要通过更改代码来达到显示的效果。</P></TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=0 bgColor=#999999 border=0>
<TBODY>
<TR>
<TD class=imageTable><IMG height=367 src="http://www.jetmaven.net/documents/p_image/j_dw_struts_combination_3.jpg" width=611></TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=0 width=700 border=0>
<TBODY>
<TR>
<TD class=ContentPara>
<P>总结：使用以上方法，确实可以给网页设计者带来不少便利，组件可以直接显示，方便我们的修改。其实有一款Dreamweaver的Struts插件，功能更强大，你可在http://www.fwasi.com 查找到该插件的信息，不过是收费的。</P></TD></TR></TBODY></TABLE><img src ="http://www.blogjava.net/jackybu/aggbug/10313.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jackybu/" target="_blank">辰</a> 2005-08-17 10:46 <a href="http://www.blogjava.net/jackybu/articles/10313.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> Struts常见异常信息和解决方法</title><link>http://www.blogjava.net/jackybu/articles/9766.html</link><dc:creator>辰</dc:creator><author>辰</author><pubDate>Thu, 11 Aug 2005 01:05:00 GMT</pubDate><guid>http://www.blogjava.net/jackybu/articles/9766.html</guid><wfw:comment>http://www.blogjava.net/jackybu/comments/9766.html</wfw:comment><comments>http://www.blogjava.net/jackybu/articles/9766.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jackybu/comments/commentRss/9766.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jackybu/services/trackbacks/9766.html</trackback:ping><description><![CDATA[以下所说的struts-config.xml和ApplicationResources.properties等文件名是缺省时使用的，如果你使用了多模块，或指定了不同的资源文件名称，这些名字要做相应的修改。
<P>1、“No bean found under attribute key XXX”<BR>在struts-config.xml里定义了一个ActionForm，但type属性指定的类不存在，type属性的值应该是Form类的全名。或者是，在Action的定义中，name或attribute属性指定的ActionForm不存在。</P>
<P><BR>2、“Cannot find bean XXX in any scope”<BR>在Action里一般会request.setAttribute()一些对象，然后在转向的jsp文件里（用tag或request.getAttribute()方法）得到这些对象并显示出来。这个异常是说jsp要得到一个对象，但前面的Action里并没有将对象设置到request（也可以是session、servletContext）里。<BR>可能是名字错了，请检查jsp里的tag的一般是name属性，或getAttribute()方法的参数值；或者是Action逻辑有问题没有执行setAttribute()方法就先转向了。<BR>还有另外一个可能，纯粹是jsp文件的问题，例如&lt;logic:iterate&gt;会指定一个id值，然后在循环里&lt;bean:write&gt;使用这个值作为name的值，如果这两个值不同，也会出现此异常。（都是一个道理，request里没有对应的对象。）</P>
<P><BR>3、“Missing message for key "XXX"”<BR>缺少所需的资源，检查ApplicationResources.properties文件里是否有jsp文件里需要的资源，例如：</P>
<P><BR>&lt;bean:message key="msg.name.prompt"/&gt;</P>
<P>这行代码会找msg.name.prompt资源，如果AppliationResources.properties里没有这个资源就会出现本异常。在使用多模块时，要注意在模块的struts-config-xxx.xml里指定要使用的资源文件名称，否则当然什么资源也找不到，这也是一个很容易犯的错误。</P>
<P>4、“No getter method for property XXX of bean teacher”<BR>这条异常信息说得很明白，jsp里要取一个bean的属性出来，但这个bean并没有这个属性。你应该检查jsp中某个标签的property属性的值。例如下面代码中的cade应该改为code才对：</P>
<P>&lt;bean:write name="teacher" property="cade" filter="true"/&gt;</P>
<P><BR>5、“Cannot find ActionMappings or ActionFormBeans collection”<BR>待解决。</P>
<P>6、“Cannot retrieve mapping for action XXX”<BR>在.jsp的&lt;form&gt;标签里指定action='/XXX'，但这个Action并未在struts-config.xml里设置过。</P>
<P>7、HTTP Status 404 - /xxx/xxx.jsp<BR>Forward的path属性指向的jsp页面不存在，请检查路径和模块，对于同一模块中的Action转向，path中不应包含模块名；模块间转向，记住使用contextRelative="true"。</P>
<P>8、没有任何异常信息，显示空白页面<BR>可能是Action里使用的forward与struts-config.xml里定义的forward名称不匹配。</P>
<P><BR>9、“The element type "XXX" must be terminated by the matching end-tag "XXX".”<BR>这个是struts-config.xml文件的格式错误，仔细检查它是否是良构的xml文件，关于xml文件的格式这里就不赘述了。</P>
<P>10、“Servlet.init() for servlet action threw exception”<BR>一般出现这种异常在后面会显示一个关于ActionServlet的异常堆栈信息，其中指出了异常具体出现在代码的哪一行。我曾经遇到的一次提示如下：</P>
<P>java.lang.NullPointerException<BR>&nbsp;&nbsp;&nbsp; at org.apache.struts.action.ActionServlet.parseModuleConfigFile(ActionServlet.java:1003)<BR>&nbsp;&nbsp;&nbsp; at org.apache.struts.action.ActionServlet.initModuleConfig(ActionServlet.java:955)</P>
<P><BR>为解决问题，先下载struts的源码包，然后在ActionServlet.java的第1003行插入断点，并对各变量进行监视。很丢人，我竟然把struts-config.xml文件弄丢了，因此出现了上面的异常，应该是和CVS同步时不小心删除的。</P>
<P>11、“Resources not defined for Validator”<BR>这个是利用Validator插件做验证时可能出现的异常，这时你要检查validation.xml文件，看里面使用的资源是否确实有定义，form的名称是否正确，等等。</P>
<P>上面这些是我在用Struts做项目时遇到过的问题，其中一些曾困绕我不少时间，其实大部分都是自己不细心造成的。希望这篇文章能对你的开发有所帮助，并欢迎继续补充。</P><img src ="http://www.blogjava.net/jackybu/aggbug/9766.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jackybu/" target="_blank">辰</a> 2005-08-11 09:05 <a href="http://www.blogjava.net/jackybu/articles/9766.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Struts 中bean:present使用方法     选择自 techyang 的 Blog </title><link>http://www.blogjava.net/jackybu/articles/9764.html</link><dc:creator>辰</dc:creator><author>辰</author><pubDate>Thu, 11 Aug 2005 01:04:00 GMT</pubDate><guid>http://www.blogjava.net/jackybu/articles/9764.html</guid><wfw:comment>http://www.blogjava.net/jackybu/comments/9764.html</wfw:comment><comments>http://www.blogjava.net/jackybu/articles/9764.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jackybu/comments/commentRss/9764.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jackybu/services/trackbacks/9764.html</trackback:ping><description><![CDATA[在做一个用Struts做的电子商务项目时,遇到了一个这样的问题：未登陆用户购买商品时，要显示用户登陆画面；而登陆用户购买商品时，则不显示登陆画面而显示用户信息。可以用struts 1.1 的bean:present实现：
<P>&nbsp;&nbsp;&nbsp; 在JSP页面头部一定要加上相应的&lt;%@ taglib 等标记，否则无法实现。我开始时就是忘了加&lt;%@ taglib uri="http://jakarta.apache.org/struts/tags-logic" prefix="logic" %&gt; ，而导致无论是使用 present 还是 notPresent ，网页中都显示用户登陆页面。：）。在jsp页面实现代码：</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;%@ page language="java"%&gt;<BR>&lt;%@ taglib uri="http://jakarta.apache.org/struts/tags-bean" prefix="bean"%&gt;<BR>&lt;%@ taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html"%&gt;<BR>&lt;%@ taglib uri="http://jakarta.apache.org/struts/tags-logic" prefix="logic" %&gt;</P>
<P>&lt;logic:notPresent name="userid" scope="session"&gt;</P>
<P>&nbsp;&nbsp;// 这里是登陆表单代码</P>
<P>&lt;/logic:notPresent&gt;</P>
<P>&lt;logic:present name="userid" scope="session"&gt;</P>
<P>&nbsp; &lt;bean:write key="userid" /&gt;&nbsp; //显示session中的用户id （userid）</P>
<P>&lt;/logic:present&gt;</P>
<P>在Struts的action的 execute 方法里面可以这样定义session变量：</P>
<P>String userId="123456";</P>
<P>request.getSession(true).setAttribute("userid",userId); </P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; （注：request.getSeesion(boolean），这个方法里面传了一个boolean值，这个值如果是true，那么如果当前的request的session不可用，那么就创建新的会话，如果存在就返回当前的会话。如果参数是false，那么在request的当前会话不存在的时候就返回null。）</P><img src ="http://www.blogjava.net/jackybu/aggbug/9764.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jackybu/" target="_blank">辰</a> 2005-08-11 09:04 <a href="http://www.blogjava.net/jackybu/articles/9764.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入Struts 1.1</title><link>http://www.blogjava.net/jackybu/articles/9765.html</link><dc:creator>辰</dc:creator><author>辰</author><pubDate>Thu, 11 Aug 2005 01:04:00 GMT</pubDate><guid>http://www.blogjava.net/jackybu/articles/9765.html</guid><wfw:comment>http://www.blogjava.net/jackybu/comments/9765.html</wfw:comment><comments>http://www.blogjava.net/jackybu/articles/9765.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jackybu/comments/commentRss/9765.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jackybu/services/trackbacks/9765.html</trackback:ping><description><![CDATA[<SPAN id=ArticleContent1_ArticleContent1_lblContent>&nbsp;
<P><A href="http://www-128.ibm.com/developerworks/cn/java/l-struts1-1/#author1"><NAME></NAME><FONT color=#002c99>王和全</FONT></A></P>
<P>2003 年 8 月 02 日</P>
<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中，为了解决这个并行开发的问题，提出了两种解决方案： </P>
<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中它主要完成以下功能： </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>接收客户端请求 
<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你可以从以下几个方面来理解它： </P>
<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文件中做如下设置： </P>
<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方法）方法中完成，其中主要涉及到以下几个方面： </P>
<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类中掷出的某种异常。你可以按照以下步骤来完成该功能： </P>
<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>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD><A name=author1></A><SPAN class=atitle2>关于作者</SPAN><BR>王和全,邮件地址： <A href="mailto:ok_winnerboy@sina.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:h="http://www.w3.org/1999/xhtml" xmlns:dw="http://www.ibm.com/developerworks/"><FONT color=#002c99>ok_winnerboy@sina.com</FONT></A> </TD></TR></TBODY></TABLE></SPAN><img src ="http://www.blogjava.net/jackybu/aggbug/9765.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jackybu/" target="_blank">辰</a> 2005-08-11 09:04 <a href="http://www.blogjava.net/jackybu/articles/9765.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用Struts上传多个文件的方法     选择自 techyang 的 Blog </title><link>http://www.blogjava.net/jackybu/articles/9763.html</link><dc:creator>辰</dc:creator><author>辰</author><pubDate>Thu, 11 Aug 2005 01:03:00 GMT</pubDate><guid>http://www.blogjava.net/jackybu/articles/9763.html</guid><wfw:comment>http://www.blogjava.net/jackybu/comments/9763.html</wfw:comment><comments>http://www.blogjava.net/jackybu/articles/9763.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jackybu/comments/commentRss/9763.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jackybu/services/trackbacks/9763.html</trackback:ping><description><![CDATA[最近在做Struts项目时遇到了上传多个文件的问题。在网上查了不少资料，也没有找到用Struts上传多个文件的例子。我经过几天的研究，实现了用Struts上传多个文件的功能。现在贴出来让大家共享！
<P>&nbsp;&nbsp;&nbsp; 一。建立ActionForm</P>
<P>package com.cnehu.struts.form;<BR>import javax.servlet.http.HttpServletRequest;</P>
<P>import org.apache.struts.action.ActionError;<BR>import org.apache.struts.action.ActionErrors;<BR>import org.apache.struts.action.ActionForm;<BR>import org.apache.struts.action.ActionMapping;<BR>import org.apache.struts.upload.FormFile;<BR>import org.apache.struts.upload.MultipartRequestHandler;</P>
<P>/**<BR>&nbsp;* &lt;p&gt;<BR>&nbsp;* Title:UpLoadForm<BR>&nbsp;* &lt;/p&gt;<BR>&nbsp;* &lt;p&gt;<BR>&nbsp;* Copyright: Copyright (c) 2005 techyang http://blog.csdn.net/techyang<BR>&nbsp;* &lt;/p&gt;<BR>&nbsp;* @author techyang<BR>&nbsp;* @version 1.0<BR>&nbsp;*/</P>
<P>public class UpLoadForm extends ActionForm<BR>{<BR>&nbsp;&nbsp;&nbsp; public static final String ERROR_PROPERTY_MAX_LENGTH_EXCEEDED = "org.apache.struts.webapp.upload.MaxLengthExceeded";</P>
<P>&nbsp;&nbsp;&nbsp; protected FormFile theFile;<BR>&nbsp;&nbsp;&nbsp; protected FormFile theFile2;<BR>&nbsp;&nbsp;&nbsp; public FormFile getTheFile()<BR>&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return theFile;<BR>&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;&nbsp;&nbsp; public void setTheFile(FormFile theFile)<BR>&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.theFile = theFile;<BR>&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;&nbsp;&nbsp; public ActionErrors validate(ActionMapping mapping,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HttpServletRequest request)<BR>&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ActionErrors errors = null;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //has the maximum length been exceeded?<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Boolean maxLengthExceeded = (Boolean) request<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .getAttribute(MultipartRequestHandler.ATTRIBUTE_MAX_LENGTH_EXCEEDED);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ((maxLengthExceeded != null) &amp;&amp; (maxLengthExceeded.booleanValue()))<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; errors = new ActionErrors();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; errors.add(ERROR_PROPERTY_MAX_LENGTH_EXCEEDED, new ActionError(<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "maxLengthExceeded"));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return errors;</P>
<P>&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; /**<BR>&nbsp;&nbsp;&nbsp;&nbsp; * @return Returns the theFile2.<BR>&nbsp;&nbsp;&nbsp;&nbsp; */<BR>&nbsp;&nbsp;&nbsp; public FormFile getTheFile2()<BR>&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return theFile2;<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; /**<BR>&nbsp;&nbsp;&nbsp;&nbsp; * @param theFile2 The theFile2 to set.<BR>&nbsp;&nbsp;&nbsp;&nbsp; */<BR>&nbsp;&nbsp;&nbsp; public void setTheFile2(FormFile theFile2)<BR>&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.theFile2 = theFile2;<BR>&nbsp;&nbsp;&nbsp; }<BR>}<BR></P>
<P>二。建立ActionServlet</P>
<P>package com.cnehu.struts.action;</P>
<P>import java.io.*;<BR>import javax.servlet.http.*;<BR>import org.apache.struts.action.*;<BR>import org.apache.struts.upload.FormFile;</P>
<P>import com.cnehu.struts.form.UpLoadForm;</P>
<P>/**<BR>&nbsp;* &lt;p&gt;<BR>&nbsp;* Title:UpLoadAction<BR>&nbsp;* &lt;/p&gt;<BR>&nbsp;* &lt;p&gt;<BR>&nbsp;* Copyright: Copyright (c) 2005 techyang http://blog.csdn.net/techyang<BR>&nbsp;* &lt;/p&gt;<BR>&nbsp;* @author techyang<BR>&nbsp;* @version 1.0<BR>&nbsp;*/</P>
<P>public class UpLoadAction extends Action<BR>{<BR>&nbsp;&nbsp;&nbsp; public ActionForward execute(ActionMapping mapping, ActionForm form,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HttpServletRequest request, HttpServletResponse response)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws Exception<BR>&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String encoding = request.getCharacterEncoding();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ((encoding != null) &amp;&amp; (encoding.equalsIgnoreCase("utf-8")))<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; response.setContentType("text/html; charset=gb2312");//如果没有指定编码，编码格式为gb2312<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UpLoadForm theForm = (UpLoadForm) form;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FormFile file = theForm.getTheFile();//取得上传的文件<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FormFile file2=theForm.getTheFile2();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try<BR>&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; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 取当前系统路径D:\Tomcat5\webapps\coka\ 其中coka 为当前context<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String filePath = this.getServlet().getServletContext()<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .getRealPath("/");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; InputStream stream = file.getInputStream();//把文件读入<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ByteArrayOutputStream baos = new ByteArrayOutputStream();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 建立一个上传文件的输出流 如果是linux系统请把UploadFiles后的"\\"换成"/"<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OutputStream bos = new FileOutputStream(filePath +<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "UploadFiles\\"+file.getFileName());<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //D:\Tomcat5\webapps\coka\UploadFiles\DSC01508.JPG<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*&nbsp; System.out.println(filePath +<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "UploadFiles\\"+file.getFileName());<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(filePath);*/<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; request.setAttribute("fileName",filePath + "/"<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; + file.getFileName());<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int bytesRead = 0;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; byte[] buffer = new byte[8192];<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while ((bytesRead = stream.read(buffer, 0, 8192)) != -1)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bos.write(buffer, 0, bytesRead);//将文件写入服务器<BR>&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; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bos.close();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; stream.close();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; InputStream stream2 = file2.getInputStream();//把文件读入<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ByteArrayOutputStream baos2 = new ByteArrayOutputStream();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OutputStream bos2 =&nbsp; new FileOutputStream(filePath +<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "UploadFiles\\"+file2.getFileName());//建立一个上传文件的输出流<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int bytesRead2 = 0;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; byte[] buffer2 = new byte[8192];<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i=0;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while ((bytesRead2 = stream2.read(buffer2, 0, 8192)) != -1)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bos2.write(buffer2, 0, bytesRead2);//将文件写入服务器<BR>&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; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bos2.close();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; stream2.close();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (Exception e)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.err.print(e);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return mapping.findForward("display");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp; }<BR>}<BR></P>
<P>三。建立上传用的JSP文件 upload.jsp</P>
<P>&lt;%@ taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html" %&gt;<BR>&lt;html:html&gt;<BR>&lt;head&gt;<BR>&lt;title&gt;用Struts上传文件&lt;/title&gt;<BR>&lt;/head&gt;<BR>&lt;body&gt;<BR>&lt;html:form action="/uploadsAction" enctype="multipart/form-data"&gt;<BR>&lt;html:file property="theFile"/&gt;<BR>&lt;html:file property="theFile2"/&gt;</P>
<P>&lt;html:submit/&gt;<BR>&lt;/html:form&gt;<BR>&lt;/body&gt;<BR>&lt;/html:html&gt;</P>
<P>四。配置struts-config.xml文件</P>
<P>&lt;?xml version="1.0" encoding="UTF-8"?&gt;<BR>&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;<BR>&lt;struts-config&gt;<BR>&nbsp;&nbsp; &lt;data-sources /&gt;<BR>&nbsp;&nbsp; &lt;form-beans &gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp; &lt;form-bean name="uploadsForm" type="com.cnehu.struts.form.UpLoadForm" /&gt;&nbsp;<BR>&nbsp;&nbsp; &lt;/form-beans&gt;</P>
<P>&nbsp;&nbsp; &lt;global-exceptions /&gt;<BR>&nbsp;&nbsp; &lt;global-forwards &gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp; &lt;/global-forwards&gt;</P>
<P>&nbsp;&nbsp; &lt;action-mappings &gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;action name="uploadsForm" type="com.cnehu.struts.action.UpLoadAction" path="/uploadsAction"&gt;<BR>&nbsp;&lt;forward name="display" path="/display.jsp" /&gt;<BR>&nbsp;&lt;/action&gt;<BR>&nbsp;&nbsp; &nbsp;&lt;/action-mappings&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&lt;/struts-config&gt;</P>
<P><BR>全文完！</P><img src ="http://www.blogjava.net/jackybu/aggbug/9763.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jackybu/" target="_blank">辰</a> 2005-08-11 09:03 <a href="http://www.blogjava.net/jackybu/articles/9763.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>struts 数据源的配置</title><link>http://www.blogjava.net/jackybu/articles/9579.html</link><dc:creator>辰</dc:creator><author>辰</author><pubDate>Mon, 08 Aug 2005 08:26:00 GMT</pubDate><guid>http://www.blogjava.net/jackybu/articles/9579.html</guid><wfw:comment>http://www.blogjava.net/jackybu/comments/9579.html</wfw:comment><comments>http://www.blogjava.net/jackybu/articles/9579.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jackybu/comments/commentRss/9579.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jackybu/services/trackbacks/9579.html</trackback:ping><description><![CDATA[<P><FONT color=#008000><STRONG>三个需要的程序包：</STRONG></FONT></P>
<P><FONT color=#808080>commons-dbcp-1.2.1.jar</FONT></P><FONT color=#808080>
<P><FONT color=#000000><A href="http://apache.linuxforum.net/dist/jakarta/commons/dbcp/binaries/">http://apache.linuxforum.net/dist/jakarta/commons/dbcp/binaries/</A> </FONT></P><FONT color=#000000></FONT>
<P>struts-legacy.jar</P>
<P><FONT color=#000000><A href="http://apache.linuxforum.net/dist/jakarta/struts/struts-legacy/">http://apache.linuxforum.net/dist/jakarta/struts/struts-legacy/</A> </FONT></P><FONT color=#000000></FONT>
<P>commons-pool-1.2.jar</P>
<P></FONT><FONT color=#000000><A href="http://apache.linuxforum.net/dist/jakarta/commons/pool/binaries/">http://apache.linuxforum.net/dist/jakarta/commons/pool/binaries/</A> <BR><BR><BR>&lt;?xml version="1.0" encoding="UTF-8"?&gt;<BR>&lt;!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN" "<A href="http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd</A>"&gt;<BR>&lt;struts-config&gt;<BR>&nbsp;&nbsp; &lt;data-sources&gt;<BR>&nbsp;&nbsp; &nbsp;&lt;data-source type="org.apache.commons.dbcp.BasicDataSource"&gt;<BR>&nbsp;&nbsp; &nbsp;&nbsp;&lt;set-property property="autoCommit" value="ture"/&gt;<BR>&nbsp;&nbsp; &nbsp;&nbsp;&lt;set-property property="description" value="MySQL Data Source"/&gt;<BR>&nbsp;&nbsp; &nbsp;&nbsp;&lt;set-property property="driverClassName" value="com.mysql.jdbc.Driver"/&gt;<BR>&nbsp;&nbsp; &nbsp;&nbsp;&lt;set-property property="maxCount" value="20"/&gt;<BR>&nbsp;&nbsp; &nbsp;&nbsp;&lt;set-property property="mixCount" value="5"/&gt;<BR>&nbsp;&nbsp; &nbsp;&nbsp;&lt;set-property property="username" value="root"/&gt;<BR>&nbsp;&nbsp; &nbsp;&nbsp;&lt;set-property property="password" value="jacky"/&gt;<BR>&nbsp;&nbsp; &nbsp;&nbsp;&lt;set-property property="url" value="jdbc:mysql://localhost:3306/ebooklib"/&gt;<BR>&nbsp;&nbsp; &nbsp;&lt;/data-source&gt;<BR>&nbsp;&nbsp; &lt;/data-sources&gt;<BR>&nbsp;&nbsp; &lt;form-beans &gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;form-bean name="logonForm" type="org.apache.struts.action.DynaActionForm"&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;form-property name="password" type="java.lang.String" /&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;form-property name="username" type="java.lang.String" /&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/form-bean&gt;</FONT></P>
<P><FONT color=#000000>&nbsp;&nbsp; &lt;/form-beans&gt;</FONT></P>
<P><FONT color=#000000>&nbsp;&nbsp; &lt;global-exceptions /&gt;<BR>&nbsp;&nbsp; &lt;global-forwards /&gt;<BR>&nbsp;&nbsp; &lt;action-mappings &gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;action<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; attribute="logonForm"<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; input="/form/logon.jsp"<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; name="logonForm"<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; path="/logon"<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; scope="request"<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; type="com.yourcompany.struts.action.LogonAction" /&gt;</FONT></P>
<P><FONT color=#000000>&nbsp;&nbsp; &lt;/action-mappings&gt;</FONT></P>
<P><FONT color=#000000>&nbsp;&nbsp; &lt;message-resources parameter="com.yourcompany.struts.ApplicationResources" /&gt;<BR>&lt;/struts-config&gt;</FONT></P><img src ="http://www.blogjava.net/jackybu/aggbug/9579.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jackybu/" target="_blank">辰</a> 2005-08-08 16:26 <a href="http://www.blogjava.net/jackybu/articles/9579.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>struts下的乱码问题的解决办法</title><link>http://www.blogjava.net/jackybu/articles/8880.html</link><dc:creator>辰</dc:creator><author>辰</author><pubDate>Sun, 31 Jul 2005 15:55:00 GMT</pubDate><guid>http://www.blogjava.net/jackybu/articles/8880.html</guid><wfw:comment>http://www.blogjava.net/jackybu/comments/8880.html</wfw:comment><comments>http://www.blogjava.net/jackybu/articles/8880.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jackybu/comments/commentRss/8880.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jackybu/services/trackbacks/8880.html</trackback:ping><description><![CDATA[&nbsp;<FONT face=宋体><SPAN id=ArticleContent1_ArticleContent1_lblContent><FONT size=2>1、页面提示信息乱码<BR>页面的提示信息来自ApplicationResources_zh.properties<BR>解决方法：<BR>(1)所有jsp页面均要用<BR>&lt;%@ page language="java" contentType="text/html; charset=GBK" %&gt;<BR>指出当前页面的charset<BR>(2)用notepad等工具（而不是Eclipse Editor）编写中文资源文件，比如ApplicationResources_xx.properties。然后用工具native2ascii将资源文件中的中文字符转换为GBK，方法是在DOS下<BR></FONT><FONT style="BACKGROUND-COLOR: #000000" color=#ffffff><FONT size=2>native2ascii -encoding GBK ApplicationResources_xx.properties ApplicationResources_zh.properties<BR><BR></FONT><FONT style="BACKGROUND-COLOR: #ffffff" color=#000000><FONT size=2>2、提交的中文字符在服务器端(JBOSS)乱码<BR>解决办法：增加一个filter，里面将request中的中文转换为GBK<BR></FONT><FONT style="BACKGROUND-COLOR: #d3d3d3" size=2>&nbsp;public void doFilter(ServletRequest request, ServletResponse response,<BR>&nbsp;&nbsp;&nbsp;FilterChain chain) throws IOException, ServletException {<BR></FONT><FONT size=2><FONT style="BACKGROUND-COLOR: #d3d3d3"><FONT color=#ff0000>&nbsp;&nbsp;&nbsp;&nbsp; request.setCharacterEncoding("GBK");<BR>&nbsp;&nbsp;&nbsp;&nbsp; chain.doFilter(request,response);<BR></FONT>&nbsp;}<BR><BR>另：关于native2ascii<BR>使ApplicationResources.properties支持中文&nbsp;<BR>建立一个ApplicationResources_ISO.properties文件，把应用程序用的message都写进去，然后在dos&nbsp;<BR>下执行这个命令，&nbsp;<BR>native2ascii&nbsp;-encoding&nbsp;gb2312&nbsp;ApplicationResources_ISO.properties&nbsp;&nbsp;<BR>ApplicationResources.properties&nbsp;<BR>这样就会将ISO编码的ApplicationResources转换成GB2312编码的格式了，同时保存到&nbsp;<BR>ApplicationResources.properties.&nbsp;<BR>native2ascii这个工具是jdk自带的一个东东，所以如果path都设定正确就可以直接运行了，你可以在&nbsp;<BR>$java_home$/bin下找到他。&nbsp;<BR>转换后的中文类似于这个样子&nbsp;<BR>iso&nbsp;格式下&nbsp;：tj.type=商品车类型&nbsp;<BR>gb2312格式下&nbsp;：tj.type=\u5546\u54c1\u8f66\u7c7b\u578b&nbsp;<BR>然后在struts-config.xml中设置应用这个资源文件&nbsp;<BR>&lt;message-resources&nbsp;parameter="com.huahang.tj.ApplicationResources"&nbsp;&nbsp;<BR>key="org.apache.struts.action.MESSAGE"&nbsp;/&gt;&nbsp;<BR>开发jsp时在jsp的开头写上&lt;%@&nbsp;page&nbsp;contentType="text/html;&nbsp;charset=gb2312"&nbsp;%&gt;，将字符集设置&nbsp;<BR>成gb2312就可以了。<BR></FONT></FONT></FONT></FONT></SPAN></FONT><img src ="http://www.blogjava.net/jackybu/aggbug/8880.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jackybu/" target="_blank">辰</a> 2005-07-31 23:55 <a href="http://www.blogjava.net/jackybu/articles/8880.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MyEclipse注册机</title><link>http://www.blogjava.net/jackybu/articles/7984.html</link><dc:creator>辰</dc:creator><author>辰</author><pubDate>Tue, 19 Jul 2005 06:21:00 GMT</pubDate><guid>http://www.blogjava.net/jackybu/articles/7984.html</guid><wfw:comment>http://www.blogjava.net/jackybu/comments/7984.html</wfw:comment><comments>http://www.blogjava.net/jackybu/articles/7984.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jackybu/comments/commentRss/7984.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jackybu/services/trackbacks/7984.html</trackback:ping><description><![CDATA[<P><A href="http://www.blogjava.net/Files/jackybu/myeclipse_3_6_2_keygen.rar">下载</A></P><img src ="http://www.blogjava.net/jackybu/aggbug/7984.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jackybu/" target="_blank">辰</a> 2005-07-19 14:21 <a href="http://www.blogjava.net/jackybu/articles/7984.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(转载)struts中文问题struts国际化问题终极解决方案 </title><link>http://www.blogjava.net/jackybu/articles/7983.html</link><dc:creator>辰</dc:creator><author>辰</author><pubDate>Tue, 19 Jul 2005 04:50:00 GMT</pubDate><guid>http://www.blogjava.net/jackybu/articles/7983.html</guid><wfw:comment>http://www.blogjava.net/jackybu/comments/7983.html</wfw:comment><comments>http://www.blogjava.net/jackybu/articles/7983.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jackybu/comments/commentRss/7983.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jackybu/services/trackbacks/7983.html</trackback:ping><description><![CDATA[<SPAN class=bt><FONT face=Arial size=4>Java本身就支持多国语言编码，不需要写任何程序，可以很简单的实现,秘诀就是两点： <BR><BR>1、所有HTML/JSP页面全部采用UTF-8编码 <BR><BR>2、客户端浏览器完全支持UTF-8编码 <BR><BR>步骤： <BR>1、首先把所有的HTML/JSP的ContentType都设为UTF-8 <BR><BR>2、然后对于JSP程序中的非ASCII码提示信息都不应该写在程序里面，都应该放在 <BR>application.properties里面统一管理。 <BR><BR>3、对HTML用native2ascii工具统一做一次处理，把HTML中的非ASCII码都转换为Unicode编码。 <BR><BR>4、针对不同的语言，写不同的application.properties，比如说简体中文是 <BR>application_zh_CN.properties，繁体中文是application_zh_TW.properties这样，然后对这些配置信 <BR>息文件同样用native2ascii工具处理一次，把非ASCII码统统转为Unicode编码。 <BR><BR>5、在Servlet的request.getCharacterEncoding()获得客户端的操作系统默认编码，然后set到Struts <BR>的HTTPSession的Locale中。 <BR><BR>OK！现在不同的客户访问，就会显示不同的语言版本了。你可以看看此时你的浏览器的字符集，就是 <BR>UTF-8。现在你的网站和Google一样了，嘿嘿，其实你有心的话，看看你的浏览器访问Google的时候是 <BR>什么字符集吧 <BR><BR>切记：所有的HTML/JSP都要设为UTF-8编码，所有的文件中的非ASCII码字符都要用native2ascii工具转 <BR>为用ASCII表示的Unicode编码。 <BR>Struts的中文问题，并实现Struts的国际化，其实一切并不复杂，下面是具体步骤： <BR><BR>0.遇到的问题(这些问题也许不会同时出现) <BR>a.中文数据从数据库中到jsp中后就变成了"????" <BR>b.做好的中文properties文件，其中的中文value在页面显示乱码 <BR>c.jsp文件中的中文到浏览器后显示时也是乱码（建议不要在jsp文件中输入中文，尽量放在properties文件中） <BR>d.由jsp传给bean的中文值，再由bean传回页面又是乱码 <BR>e.当更换本地浏览器的语言选项时，Web应用程序不能自动根据你的locale选择合适的*.properties文件。导致Web应用程序不能国际化。 <BR>1.环境： <BR>Web服务器： Tomcat 5.0.19 <BR>操作系统： Win2000 Server <BR>JVM ： jdk 1.4 <BR>数 据 库： Oracle 8.1.7 <BR>开发工具： struts studio 5.2 pro for eclipse <BR>2.先将所有*.jsp 网页中开头处加入 <BR><BR>&lt;%@ page language="java" contentType="text/html; charset=utf-8" %&gt; <BR>再设置&lt;html:html locale = "true"&gt; <BR><BR>3.然后编辑好两个*.properties文件，放在classes文件夹下你指定的地方，这里是放在/web-inf/classes/com/wiley 下，它们分别是： <BR><BR>ApplicationResources.properties (英文资源文件) <BR>ApplicationResources_zh.properties (中文资源文件) <BR>随便用什么工具编写都行啊！ <BR>4.将ApplicationResources_zh.properties转码成gb2312。上面引文说要转成UTF-8，结果我试了，不行。转成gb2312就行了，操作是。 <BR>将ApplicationResources_zh.properties更名为ApplicationResources_xx.properties <BR>在DOS命令行进入ApplicationResources_xx.properties所在的文件夹 <BR>使用命令：native2ascii -encoding gb2312 ApplicationResources_xx.properties ApplicationResources_zh.properties(至于你为什么会出现“native2ascii不是内部命令”，，请查其它资料，可能你要设置环境变量，因为他是jdk的文件夹bin下的一个应用程序) <BR>5.接下来配置struts-config.xml,很简单，我们加入： <BR><BR>&lt;message-resources parameter="com.wiley.ApplicationResources"/&gt; 就行了； <BR><BR>到此已能解决大多数中文问题。如上面所说的a,b,e 现在打开浏览器，选择菜单：工具》internet选项》语言，将“中文－中国[zh-cn]”删掉，添加一个“英语－英国[zh-gb]”确定后，重启Tomcat,输入网址你就会发现，你的页面的文本信息就会用的是ApplicationResources.properties (英文资源文件)中的内容。如果换回“中文－中国[zh-cn]”，它就会显示ApplicationResources_zh.properties (中文资源文件)中的中文内容。 <BR><BR>至于问题“c.jsp文件中的中文到浏览器后显示时也是乱码” 你就要用与第4步类似的方法来重新对*.jsp 文件编码，这时-encoding的参数就要用UTF-8了，如果你用的也是struts studio 5.2 pro for eclipse工具，这一步就免了。它会自动用UTF-8的格式存储。 <BR>至于问题“d.由jsp传给bean的中文值，再由bean传回页面又是乱码”的解决，我只是加了个过滤器。 <BR>你可以现在web.xml中加入： <BR>&lt;filter&gt; <BR>&lt;filter-name&gt;Set Character Encoding&lt;/filter-name&gt; <BR>&lt;filter-class&gt;com.wiley.SetCharacterEncodingFilter&lt;/filter-class&gt; <BR>&lt;init-param&gt; <BR>&lt;param-name&gt;encoding&lt;/param-name&gt; <BR>&lt;param-value&gt;utf-8&lt;/param-value&gt; <BR>&lt;/init-param&gt; <BR>&lt;init-param&gt; <BR>&lt;param-name&gt;ignore&lt;/param-name&gt; <BR>&lt;param-value&gt;true&lt;/param-value&gt; <BR>&lt;/init-param&gt; <BR>&lt;/filter&gt; <BR>&lt;filter-mapping&gt; <BR>&lt;filter-name&gt;Set Character Encoding&lt;/filter-name&gt; <BR>&lt;servlet-name&gt;action&lt;/servlet-name&gt; <BR>&lt;/filter-mapping&gt; <BR><BR>然后在你指定的包内加个java文件 我放在了/web-inf/classes/com/wiley 里，下面是源代码： <BR>/* <BR>* XP Forum <BR>* <BR>* Copyright (c) 2002-2003 RedSoft Group. All rights reserved. <BR>* <BR>*/ <BR>package com.huahang.tj.struts.filters; <BR><BR>import javax.servlet.*; <BR>import java.io.IOException; <BR><BR>/** <BR>* &lt;p&gt;Filter that sets the character encoding to be used in parsing the <BR>* incoming request, either unconditionally or only if the client did not <BR>* specify a character encoding. Configuration of this filter is based on <BR>* the following initialization parameters:&lt;/p&gt; <BR>* &lt;ul&gt; <BR>* &lt;li&gt;&lt;strong&gt;encoding&lt;/strong&gt; - The character encoding to be configured <BR>* for this request, either conditionally or unconditionally based on <BR>* the &lt;code&gt;ignore&lt;/code&gt; initialization parameter. This parameter <BR>* is required, so there is no default.&lt;/li&gt; <BR>* &lt;li&gt;&lt;strong&gt;ignore&lt;/strong&gt; - If set to "true", any character encoding <BR>* specified by the client is ignored, and the value returned by the <BR>* &lt;code&gt;selectEncoding()&lt;/code&gt; method is set. If set to "false, <BR>* &lt;code&gt;selectEncoding()&lt;/code&gt; is called &lt;strong&gt;only&lt;/strong&gt; if the <BR>* client has not already specified an encoding. By default, this <BR>* parameter is set to "true".&lt;/li&gt; <BR>* &lt;/ul&gt; <BR>* <BR>* &lt;p&gt;Although this filter can be used unchanged, it is also easy to <BR>* subclass it and make the &lt;code&gt;selectEncoding()&lt;/code&gt; method more <BR>* intelligent about what encoding to choose, based on characteristics of <BR>* the incoming request (such as the values of the &lt;code&gt;Accept-Language&lt;/code&gt; <BR>* and &lt;code&gt;User-Agent&lt;/code&gt; headers, or a value stashed in the current <BR>* user's session.&lt;/p&gt; <BR>* <BR>* @author &lt;a href="mailto:jwtronics@yahoo.com"&gt;John Wong&lt;/a&gt; <BR>* <BR>* @version $Id: SetCharacterEncodingFilter.java,v 1.1 2002/04/10 13:59:27 johnwong Exp $ <BR>*/ <BR>public class SetCharacterEncodingFilter implements Filter { <BR><BR>// ----------------------------------------------------- Instance Variables <BR><BR><BR>/** <BR>* The default character encoding to set for requests that pass through <BR>* this filter. <BR>*/ <BR>protected String encoding = null; <BR><BR><BR>/** <BR>* The filter configuration object we are associated with. If this value <BR>* is null, this filter instance is not currently configured. <BR>*/ <BR>protected FilterConfig filterConfig = null; <BR><BR><BR>/** <BR>* Should a character encoding specified by the client be ignored? <BR>*/ <BR>protected boolean ignore = true; <BR><BR><BR>// --------------------------------------------------------- Public Methods <BR><BR><BR>/** <BR>* Take this filter out of service. <BR>*/ <BR>public void destroy() { <BR><BR>this.encoding = null; <BR>this.filterConfig = null; <BR><BR>} <BR><BR><BR>/** <BR>* Select and set (if specified) the character encoding to be used to <BR>* interpret request parameters for this request. <BR>* <BR>* @param request The servlet request we are processing <BR>* @param result The servlet response we are creating <BR>* @param chain The filter chain we are processing <BR>* <BR>* @exception IOException if an input/output error occurs <BR>* @exception ServletException if a servlet error occurs <BR>*/ <BR>public void doFilter(ServletRequest request, ServletResponse response, <BR>FilterChain chain) <BR>throws IOException, ServletException { <BR><BR>// Conditionally select and set the character encoding to be used <BR>if (ignore || (request.getCharacterEncoding() == null)) { <BR>String encoding = selectEncoding(request); <BR>if (encoding != null) <BR>request.setCharacterEncoding(encoding); <BR>} <BR><BR>// Pass control on to the next filter <BR>chain.doFilter(request, response); <BR><BR>} <BR><BR><BR>/** <BR>* Place this filter into service. <BR>* <BR>* @param filterConfig The filter configuration object <BR>*/ <BR>public void init(FilterConfig filterConfig) throws ServletException { <BR><BR>this.filterConfig = filterConfig; <BR>this.encoding = filterConfig.getInitParameter("encoding"); <BR>String value = filterConfig.getInitParameter("ignore"); <BR>if (value == null) <BR>this.ignore = true; <BR>else if (value.equalsIgnoreCase("true")) <BR>this.ignore = true; <BR>else if (value.equalsIgnoreCase("yes")) <BR>this.ignore = true; <BR>else <BR>this.ignore = false; <BR><BR>} <BR><BR><BR>// ------------------------------------------------------ Protected Methods <BR><BR><BR>/** <BR>* Select an appropriate character encoding to be used, based on the <BR>* characteristics of the current request and/or filter initialization <BR>* parameters. If no character encoding should be set, return <BR>* &lt;code&gt;null&lt;/code&gt;. <BR>* &lt;p&gt; <BR>* The default implementation unconditionally returns the value configured <BR>* by the &lt;strong&gt;encoding&lt;/strong&gt; initialization parameter for this <BR>* filter. <BR>* <BR>* @param request The servlet request we are processing <BR>*/ <BR>protected String selectEncoding(ServletRequest request) { <BR><BR>return (this.encoding); <BR><BR>} <BR><BR>}//EOC <BR>到此我遇到的中文问题已全部得到解决，并从中理解到struts的国际化的深刻含义。</FONT></SPAN><img src ="http://www.blogjava.net/jackybu/aggbug/7983.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jackybu/" target="_blank">辰</a> 2005-07-19 12:50 <a href="http://www.blogjava.net/jackybu/articles/7983.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>翻译-Jakarta Struts简介[from Matrix]</title><link>http://www.blogjava.net/jackybu/articles/4168.html</link><dc:creator>辰</dc:creator><author>辰</author><pubDate>Wed, 11 May 2005 06:45:00 GMT</pubDate><guid>http://www.blogjava.net/jackybu/articles/4168.html</guid><wfw:comment>http://www.blogjava.net/jackybu/comments/4168.html</wfw:comment><comments>http://www.blogjava.net/jackybu/articles/4168.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jackybu/comments/commentRss/4168.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jackybu/services/trackbacks/4168.html</trackback:ping><description><![CDATA[Jakarta&nbsp;Struts简介<BR>&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;翻译作者:-<A href="http://www.matrix.org.cn/" target=_blank>Matrix开源技术</A>-Wingc<BR><BR><BR><FONT color=red>翻译前的话</FONT><BR>&nbsp;&nbsp;呵呵，这是wingc第一次真正意义的翻译技术文章，自己看E文文档和把E文翻译成能读的中文那真是两回事啊，翻译得不好再所难免，您可别骂wingc哦:)若有什么地方不通、不爽或不妥，请见<A href="http://www.onjava.com/pub/a/onjava/2001/09/11/jsp_servlets.html" target=_blank>http://www.onjava.com/pub/a/onjava/2001/09/11/jsp_servlets.html</A>看原文吧。<BR><BR>&nbsp;Web应用开发早期曾经是那么的“简单”，那个时候还只是纯HTML页面和浏览器特效而已。由于还涉及不到动态数据操作和商业应用，也就省去了很多麻烦。但是这样的“简单”只是过眼云烟，如今我们不得不为复杂的基于Web的商业应用开发采用诸多技术。<BR>&nbsp;本文将介绍如何利用Struts进行应用开发的前台整合的开发过程。Struts是一个为开发基于模型(Model)－视图(View)－控制器(Controller)(MVC)模式的应用架构的开源框架(译注1)，是利用Java&nbsp;Servlet和JSP构建Web应用的一项非常有用的技术。<BR>&nbsp;阅读本文需要读者具有以下几方面的开发经验：JSP、Servlet、自定义标签库(custom&nbsp;tag&nbsp;library)和XML。如果读者想补一补自定义标签库的知识，可以参考作者以前关于这方面的文章。而本文也是关于介绍如何使用Struts系列文章的上半部分，本系列暂定分为上下两部分。<BR><BR><FONT color=red>新手上路注意事项</FONT><BR><BR>&nbsp;Struts是一个基于Sun&nbsp;J2EE平台的MVC框架，主要是采用Servlet和JSP技术来实现的。其最初萌芽于Craig&nbsp;McClanahan的构思，诞生至今也一年有余了(译注2)。现在，Struts是Apache软件基金会旗下Jakarta项目组的一部分，其官方网站是<IMG src="http://www.matrix.org.cn/images/small/url.gif" align=absMiddle><A href="http://jakarta.apache.org/struts" target=_blank>http://jakarta.apache.org/struts</A>。由于Struts能充分满足应用开发的需求，简单易用，敏捷迅速，在过去的一年中颇受关注。Struts把Servlet、JSP、自定义标签和信息资源(message&nbsp;resources)整合到一个统一的框架中，开发人员利用其进行开发时不用再自己编码实现全套MVC模式，极大的节省了时间，所以说Struts是一个非常不错的应用框架。<BR>&nbsp;目前的Struts&nbsp;1.0修正版包括完整的文档，既可以说是用户文档又是开发指导文档。如果读者是JSP新手，或者对MVC设计模式不是太熟的话，可能刚上路时会比较慢，不过不用担心，要相信自己会尽快赶上的:)<BR>&nbsp;此外，应该注意到尽管当前Struts只是1.0版，但已经相当稳定了，作者从Struts&nbsp;0.9版就在一个大规模的项目中应用了(最近升级到1.0版)，至今还没有遇到什么麻烦问题。实际上，Struts在这个要开发复杂用户界面的项目中，为我们团队大大的缩短了开发时间，在此衷心的感谢Struts项目团队的所有开发人员。<BR>&nbsp;哦，还有，如果读者开始上路了，要知道Struts的邮件列表可是有相当分量的，在这里混混才可保证能及时跟上Jakarta项目的最新动态哦&nbsp;<IMG src="http://www.matrix.org.cn/images/small/url.gif" align=absMiddle><A href="http://jakarta.apache.org/site/mail.html" target=_blank>http://jakarta.apache.org/site/mail.html</A>。<BR><BR><FONT color=red>开始上路!</FONT><BR><BR>&nbsp;Struts框架可分为以下四个主要部分，其中三个就和MVC模式紧密相关：<BR>&nbsp;1、模型(Model)，本质上来说在Struts中Model是一个Action类(这个会在后面详细讨论)，开发者通过其实现商业逻辑，同时用户请求通过控制器(Controller)向Action的转发过程是基于由struts-config.xml文件描述的配置信息的。<BR>&nbsp;2、视图(View)，View是由与控制器Servlet配合工作的一整套JSP定制标签库构成，利用她们我们可以快速建立应用系统的界面。<BR>&nbsp;3、控制器(Controller)，本质上是一个Servlet，将客户端请求转发到相应的Action类。<BR>&nbsp;4、一堆用来做XML文件解析的工具包，Struts是用XML来描述如何自动产生一些JavaBean的属性的，此外Struts还利用XML来描述在国际化应用的用户提示信息的(这样一来就了应用系统的实现多语言支持)。<BR>&nbsp;好，下一步咱们来看看构成这个框架的各个部分以及相互之间是怎样运作的吧！<BR><FONT color=red><BR>搞定配置先</FONT><BR><BR>&nbsp;在使用Struts之前，咱们必先设置好JSP服务器，以便让服务器在用户请求时，知道该如何将指定后缀的请求转到相应的Controller－Struts&nbsp;ActionServlet处理，当然，这些配置信息都一般在服务器启动时通过web.xml文件读入的。我们可以在web.xml定义多个Controlloer，为每一个应用定义一个。一个典型的web.xml文件配置如下，其中有相应的注释，很好懂的，在后面讨论Action的时候，我们将主要分析strutc-config.xml。<BR>&lt;web-app&gt;<BR>&nbsp;&nbsp;&lt;servlet&gt;<BR>&lt;!--&nbsp;<BR>以下配置信息声明了Struts中的ActionServlet，即一个名为OreillyAction的Servlet，其具体实现为org.apache.struts.action.ActionServlet。在这个配置中还有这个Servlet的两个参数：debug&nbsp;level和detail，此处这两个参数的值都设为了2，此外还设置了在启动载入时创建两个实例。<BR>--&gt;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;servlet-name&gt;OreillyActionServlet&lt;/servlet-name&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;servlet-class&gt;org.apache.struts.action.ActionServlet&lt;/servlet-class&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;init-param&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;param-name&gt;config&lt;/param-name&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;param-value&gt;/WEB-INF/struts-config.xml&lt;/param-value&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/init-param&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;init-param&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;param-name&gt;debug&lt;/param-name&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;param-value&gt;2&lt;/param-value&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/init-param&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;init-param&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;param-name&gt;detail&lt;/param-name&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;param-value&gt;2&lt;/param-value&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/init-param&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;load-on-startup&gt;2&lt;/load-on-startup&gt;<BR>&nbsp;&nbsp;&lt;/servlet&gt;<BR>&lt;!--&nbsp;&nbsp;&nbsp;<BR>设置所有后缀为.action的请求，都转发到OreillyActionServlet<BR>--&gt;<BR>&lt;servlet-mapping&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;servlet-name&gt;&nbsp;OreillyActionServlet&nbsp;&lt;/servlet-name&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;url-pattern&gt;*.action&lt;/url-pattern&gt;<BR>&nbsp;&nbsp;&lt;/servlet-mapping&gt;<BR>&lt;!--&nbsp;&nbsp;&nbsp;<BR>将初始请求页面设置为login.jsp<BR>--&gt;&nbsp;&nbsp;<BR>&lt;welcome-file-list&gt;&lt;welcome-file&gt;login.jsp&lt;/welcome-file&gt;&lt;/welcome-file-list&gt;<BR>&lt;!--&nbsp;&nbsp;&nbsp;<BR>设置Struts的JSP页面要用到的标签库和她们的路径<BR>--&gt;<BR>&nbsp;&nbsp;&lt;taglib&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;taglib-uri&gt;/WEB-INF/struts-bean.tld&lt;/taglib-uri&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;taglib-location&gt;/WEB-INF/struts-bean.tld&lt;/taglib-location&gt;<BR>&nbsp;&nbsp;&lt;/taglib&gt;<BR>&nbsp;&nbsp;&lt;taglib&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;taglib-uri&gt;/WEB-INF/struts-html.tld&lt;/taglib-uri&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;taglib-location&gt;/WEB-INF/struts-html.tld&lt;/taglib-location&gt;<BR>&nbsp;&nbsp;&lt;/taglib&gt;<BR>&nbsp;&nbsp;&lt;taglib&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;taglib-uri&gt;/WEB-INF/struts-logic.tld&lt;/taglib-uri&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;taglib-location&gt;/WEB-INF/struts-logic.tld&lt;/taglib-location&gt;<BR>&nbsp;&nbsp;&lt;/taglib&gt;<BR>&lt;/web-app&gt;<BR><BR><FONT color=red>控制器(Controller)</FONT><BR><BR>&nbsp;Controller是这个框架中扮演“交通警察”的角色，当客户端与服务器有交互动作时，都由她来控制。Controller将HTTP请求封包并转发到框架中相应的对象，这些对象可能是一个JSP页面或一个Action。<BR>&nbsp;Controller在web.xml中设置为org.apache.struts.action.ActionServlet的一个实例，在本例中，这个实例就是OreillyActionServlet。在一个完整的控制过程中，也就是处理一个HTTP请求时，在控制过程之初，这个Servlet会从一个配置文件struts-config.xml中获取请求与控制动作向对应的配置信息，这个我们会在后面详细讨论，Controller通过这些配置信息来决定HTTP请求该往何处转发，而这些Action在接收到转发来的请求后，实现真正的商业逻辑。我们要注意的非常重要的一点是Action对象要能够调用这个ActionServlet的若干方法，通过这个有力的特性，当Action对象在控制过程中将请求再向别的Action对象转发时(最初的请求是由ActionServlet获取，向Action对象转发，而Action对象还可以再转发到别的对象)，我们可以将一些需要共享的数据对象通过调用一些方法放入这个Servlet相关的一些标准容器中捎带过去。<BR><BR><FONT color=red>模型(Model)</FONT><BR><BR>&nbsp;所谓Model就是在对用户请求的整个控制过程中，真正处理用户请求并保存处理结果的对象，在整个过程中，我们一般利用JavaBean来把一些信息保存起来以便在各个对象之间传递。因为在框架中，Model对象是真正处理商业逻辑功能的对象，因此也就是框架中应用需求实现相关性最大的部分。在Struts的实现里，Model的具体表现形式就是ActionForm对象和与其对应的Action对象了。对用户提交表单的数据进行校验，甚至对数据进行预处理都能在ActionForm中完成。通常的应用中，一般是一个Model对象和一个请求页面对应的关系，但也可以一个Model对象对应多个页面请求。如果struts-config.xml配置文件没有指定一个Model对象对应的Action，那么控制器将直接把(通过模型对象完成数据封装的)请求转到一个View对象。<BR><BR><FONT color=red>struts-config.xml</FONT><BR><BR>&nbsp;前面多次提到的struts-config.xml配置文件是整个框架的主心骨。web.xml文件定义了一个请求到来应向何处转发后，后面的工作就全权由struts-config.xml管理控制了。可以说struts-config.xml就是整个Struts框架的“扛把子”(译注3)，只有这位“老大”清楚所有请求与动作的映射关系，要是他哪里没有搞定或不爽的话，整个“社团”就什么也摆不平了:)如今的应用系统，XML形式的配置文件越来越多，如果整个系统只使用一个这样的配置文件的话，那么保持整个系统的模块化和可维护性都非常的轻松。使用配置文件来描述请求-动作的控制过程和相互关系，而不是在代码中将对象之间的调用关系写死，那么都应用系统有变动时，我们只用修改配置文件就行了，而不是再重新编译发布程序了。<BR>&nbsp;Controller通过struts-config.xml文件的配置信息确定当有请求时应该调用那个对象来处理，从效率的角度出发，这些信息都是在系统启动时读入并存在内存中的。下面我们将讲解一个极短小的struts-config.xml文件，文件中定义了一个与登录请求对应的登录动作，请求到达后将被转发到com.oreilly.ui.authentication.actions.LoginAction这个Action对象，该对象处理的结果决定向用户返回的页面。这个例子同时还示范了一个Action对象将请求转发到别的Action对象，而例子中另一个返回的对象则是一个View对象，即我们看到的login.jsp页面。<BR>&lt;?xml&nbsp;version="1.0"&nbsp;encoding="UTF-8"&nbsp;?&gt;<BR>&lt;!DOCTYPE&nbsp;struts-config&nbsp;PUBLIC<BR>&nbsp;&nbsp;"-//Apache&nbsp;Software&nbsp;Foundation//DTD&nbsp;Struts&nbsp;Configuration&nbsp;1.0//EN"<BR>&nbsp;&nbsp;"<IMG src="http://www.matrix.org.cn/images/small/url.gif" align=absMiddle><A href='http://jakarta.apache.org/struts/dtds/struts-config_1_0.dtd"' target=_blank>http://jakarta.apache.org/struts/dtds/struts-config_1_0.dtd"</A>;&gt;<BR><BR>&lt;struts-config&gt;<BR>&nbsp;&nbsp;&lt;!--&nbsp;==========&nbsp;Action&nbsp;映射定义&nbsp;===================&nbsp;--&gt;<BR>&nbsp;&nbsp;&lt;action-mappings&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;!--&nbsp;&lt;action&gt;&nbsp;属性的说明&nbsp;--&gt;<BR>&lt;!-<BR>type&nbsp;-&nbsp;完整的Action实现类名<BR>name&nbsp;-&nbsp;该Action要用到的ActionForm名<BR>path&nbsp;-&nbsp;请求该Action的URI<BR>validate&nbsp;-&nbsp;如果本属性为true则在Action动作之前其对应的ActionForm的validate方法会自动被调用，一般用以校验用户输入的数据<BR>--&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;!--&nbsp;~~~~~~~~~~~~~~~~~~~~~&nbsp;--&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;!--&nbsp;O'Reilly&nbsp;Main&nbsp;Actions&nbsp;&nbsp;&nbsp;&nbsp;--&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;!--&nbsp;~~~~~~~~~~~~~~~~~~~~~&nbsp;--&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;action&nbsp;path="/Login"<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;type="com.oreilly.ui.authentication.actions.LoginAction"&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;forward&nbsp;name="success"&nbsp;path="/DisplayMainPage.action"/&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;forward&nbsp;name="failure"&nbsp;path="/login.jsp"/&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/action&gt;<BR>&nbsp;&nbsp;&lt;/action-mappings&gt;<BR>&lt;/struts-config&gt;<BR><BR><FONT color=red>视图(View)</FONT><BR><BR>&nbsp;View对象通常来说都是指的JSP页面。Struts框架实际上并没有真正的JSP的要求规范，而是提供了大量的标签库来为开发者更简便的将JSP整合到Struts框架中。在Struts中通过标签定义方式的JSP页面能够将用户通过表单输入的数据存入一个JavaBean中，也就是我们前面提到的ActionForm&nbsp;bean。通过Action类调用(自动或手动)ActionForm的校验方法来检查用户输入的数据，如果发现不合法的数据，再通过Struts的一个通用机制将错误信息返回给用户显示。<BR>&nbsp;Struts框架提供了若干个标签库，它们有各自不同的用途。由于这些库还可以脱离Struts框架单独使用，这样我们也可以在其他系统中尝试使用这些标签库，它们包括：<BR><BR>*&nbsp;struts-html&nbsp;-&nbsp;这个标签库用来创建动态的HTML页面和表单。<BR><BR>*&nbsp;struts-bean&nbsp;-&nbsp;提供了类似甚至更强于&lt;jsp:useBean&gt;中的功能。<BR><BR>*&nbsp;struts-logic&nbsp;-&nbsp;用于在页面输出文本信息时的条件、循环等流程的控制。<BR><BR>*&nbsp;struts-template&nbsp;-&nbsp;用于产生有共同风格的动态JSP页面模板。<BR><BR>此外，可定制标签库在Struts中还有一大用处是，通过资源文件的方式来实现应用系统的多语言特性，应用Struts的系统若想将系统中的用户交互信息换一种语言的会很简单，更换一个不同的资源文件就可以了。<BR><BR><FONT color=red>大家都开始应用Struts吧!</FONT><BR><BR>&nbsp;Struts框架可能对于大多数开发人员来说，是一门比较新的技术。但我们现在已经可以在不少的应用系统中看到Struts的身影了，而我们大可在新的应用或正在开发的JSP项目中使用Struts框架。<BR>&nbsp;例如，在作者现在正在为客户开发的一个大型数据库应用系统中，商业逻辑都是通过EJB来实现的，用户界面则是JSP页面。在struts-config.xml文件中定义了用户输入表单和对应的Action类，当一个请求发生时，即用户数据以ActionForm的形式封装提交到Action时，Action先调用ActionForm的校验方法，数据检查校验通过后，Action再调用相应的EJB中的方法来完成数据操作，操作的结果以XML的形式返回，XML解析后再放入我们数据的封装传递JavaBean&nbsp;－&nbsp;ActionForm中显示到JSP页面里返回用户。<BR>&nbsp;整个的控制流程(包括Action调用后的不同的返回结果)都尽在struts-config.xml中所掌握，这种“中央集权”的方式非常便于应用流程的调整。而不管是Servlet还是JSP页面中(甚至在一些n层的应用架构)都无需撰写如何获取显示数据的代码。<BR>&nbsp;由于目前作者所开发的是一个较大型的系统，有很多的JSP页面和用户要提交的ActionForm类型，因此发现Struts的一个麻烦的地方，那就是：我们要为如此多页面和ActionForm开发对应的Action类来完成控制，因为我们目前JSP和ActionForm与Action是一对一的关系。不过我认为如果在项目前期分析和设计时多下些功夫，做出更完美一些的设计方案的话，这样的情况是可以避免的，当然，在新产品的开发过程中，想一步就把所有需求弄清楚明白那也是不可能的。我们不是都有这样的经历吗？在开发中的应用系统正一步一步走向成熟的时候，更新和更明确的需求才会被提出来。不过，像我们手里这个利用Struts开发了六个月的系统也确实少见了，呵呵。除去这些非技术因素不谈，Struts框架为我们实现MVC模式节省了大量的时间，并且开发出的系统相当的稳定，可以说是很成熟的产品了。<BR>&nbsp;在本系列文章的第二部分，我们将把各小段代码集成起来，完成一个完整的Struts应用的实例，希望大家继续和作者一起学习Struts!<BR><BR>Sue&nbsp;Spielman是ONJava.com的副编辑，主要擅长于JSP和Servlet技术，她还是Switchback&nbsp;Software&nbsp;LLC公司的总裁和高级技术咨询专家。<BR><BR><BR>译注1：虽然常见将Controller、Model和View这三个翻译为对应的“控制器”、“模型”和“视图”，但总感觉在表达上还是有欠本意，所以译文中只在需要名词定义的地方将三个中文词汇写上，文中其他的发还是保留E文“真身”。<BR>译注2：这是2001年9月11日(没错，就是“911”当天哦)发的文章啦，要知道文章里的“那时”也是现在的好久之前的时候了。<BR>译注3：原文中此处是用“Vito&nbsp;Corleone”来形容struts-config.xml的，知道唯托.科尼奥尼是谁吗？呵呵，经典电影《教父I》和《教父II》里的教父啊，马龙.白兰度和罗伯特.德尼罗先后塑造的经典形象，所以wingc在这里也用了一点江湖词汇，请勿见怪。<BR><BR>学习Jakarta&nbsp;Struts（第二篇）<BR>&nbsp;本文是三篇学习Struts框架系列文章的第二篇（原文请见<A href="http://www.onjava.com/pub/a/onjava/2001/10/31/struts2.html" target=_blank>http://www.onjava.com/pub/a/onjava/2001/10/31/struts2.html</A>）。在本系列的的第一篇中，我们大致浏览了Struts框架，框架的功能以及框架中应用到的各个模块。而本文，我将利用Struts&nbsp;1.0为大家演示建立一个简单的应用；在第三篇文章中将介绍如何利用Struts的标签在JSP中访问ApplicationResource文件中的信息。<BR>&nbsp;我们在这篇文章将会一步一步的讲解Struts的应用，以这样的形式打开Struts一道道神秘的大门，通过这样的过程，相信也能激起你在应用开发中如何应用Struts的灵感。如果你对Struts的一些术语不是很清楚的话，可以参考本系列前一篇对Struts作大体介绍的文章。<BR>&nbsp;再次重复一遍，本文需要读者有如下几方面的知识和经验：JSP，Servlets，自定义标签库（Custom&nbsp;Tag&nbsp;libraries）和XML。此外，在本文中，我还会用到Jakarta项目组其他一些好东东，比如Tomcat<A href="http://jakarta.apache.org/tomcat/index.html" target=_blank>http://jakarta.apache.org/tomcat/index.html</A>（实现Java&nbsp;Servlet和JSP官方标准的Servlet容器，通俗的讲就是一个JSP的Web&nbsp;Server啦）和Ant<A href="http://jakarta.apache.org/ant/index.html" target=_blank>http://jakarta.apache.org/ant/index.html</A>（基于Java的自动编译发布工具，这可是好东东啊）。<BR>&nbsp;作为一名一直使用前沿技术开发了诸多应用的技术人员，我一直坚信掌握新技术，理解该技术开发的逻辑是至关重要的。但这往往就是陷住我们学习步伐的泥潭，正因如此，我打算将利用Struts开发的一套完整流程作为我们教学的案例。该流程的这个案例可谓“麻雀虽小、五脏据全”，你完全可以将这个流程应用到你手头那些复杂庞大的项目中，至少在我们的大项目中应用这个流程效果不错。<BR>&nbsp;有开发复杂商业应用的开发人员都知道，客户的需求总是在不停变幻，所以如果有一套规范的开发流程来遵循，当客户提出新的需求时，我们至少可以明确哪些“无理”需求其实是合理可行的。好，接下里我将在我的这个例子中向各位展示和应用整个流程。<BR>&nbsp;本文中的示例代码是StrutsSample应用中的一部分，包括build.xml的完整代码可以到此处<A href="http://www.onjava.com/onjava/2001/10/31/examples/StrutsPartII.jar" target=_blank>http://www.onjava.com/onjava/2001/10/31/examples/StrutsPartII.jar</A>下载。<BR><BR><FONT color=red>Struts开发过程</FONT><BR>&nbsp;从Struts发布的版本号可以看出，Struts是个新玩意，她有好几个部分组成，明智的你如果搞清楚了何时该开发完成合适的部分，那将会更好的利用我们的开发时间。从我所开发的几个利用Struts应用中，我大致总结出如下这个比较有效的开发步骤：<BR>1，明确应用需求；<BR>2，由用户输入和获取数据的角度出发，明确和设计出每一个用户界面；<BR>3，确定用户界面的进入路径；<BR>4，由应用逻辑信息确定动作映射表(ActionMapping)；<BR>5，由设计完成的用户界面开发其所用到的类和应用函数；<BR>6，由用户界面中的数据信息开发ActionForm和相应的数据校验方法；<BR>7，ActionMapping中将会被调用相应的Action或转到相应的JSP页面，这一步我们先开发这些Action；<BR>8，开发商业应用逻辑，就是相应的JavaBean、EJB或其他东东；<BR>9，开发由ActionMapping定义的系统工作流程完成对应的JSP页面；<BR>10，完成系统配置文件：struts-config.xml和web.xml；<BR>11，编译/测试/发布。<BR><BR><FONT color=red>明确应用需求</FONT><BR>&nbsp;开发任何应用系统的第一步就是收集用户需求信息。不管一个用户逻辑初看上去多么合理，但总有可能在开发时才发现它比看上去要难得多。所以，建议拟一份明确的用户需求列表，这不只是出于开发的目的，还能通过该表分析用户需求以确定哪些地方可能需要花更多的精力。<BR>&nbsp;在我们这个StrutsSample项目中，应用需求就是：<BR>&nbsp;作为一个展示Struts框架应用的完整例子，本示例完成的功能是用户登录。目的只为明确Struts的应用，本示例将不会涉及到一般复杂应用系统中可能应用的安全、数据库、EJB开发等等相关技术。<BR><BR><FONT color=red>设计用户界面</FONT><BR>&nbsp;这个应用中，包括如下三个用户界面：<BR>1）登录界面，用于用户名和密码输入；<BR>2）当登录用户为合法用户时的欢迎界面；&nbsp;<BR>3）当登录失败时的错误提示界面。<BR>&nbsp;<BR><FONT color=red>确定用户界面的进入路径</FONT><BR>1）登录界面作为这个应用的默认页面；<BR>2）欢迎界面只有当成功登录后才能进入；<BR>3）任何可能发生错误的页面能可以进入错误提示界面；<BR><BR><FONT color=red>由应用逻辑信息确定ActionMapping</FONT><BR>&nbsp;ActionMapping为整个应用确定的“线路图”，在配置文件struts-config.xml对ActionMapping进行定义，通过转发请求（forward）来理顺应用的处理流程，确定应用中每个用户请求对应的动作。<BR>&nbsp;通常我们在开发过程中就逐步确定了ActionMapping所需的信息，开发代码的过程就是在由草稿开始一步步完善struts-config.xml的过程。当Action类处理完用户请求后，其返回的的forward就是在ActionMapping中定义的一个。一个Action返回的forward完全有多种可能，尽管一个Action一般只定义其相关的几个forward。那么，如果有多个Action都可能返回的同一个forward，那么就可以将其定义为全局转发（global&nbsp;forward）。这类似于C中的头文件中全局变量，如果在struts-config.xml描述信息中，某一个forward并不是在当前Action描述中定义的而是全局定义的，那么这个全局的将起作用，同样，一个Action中当前定义的forward将覆盖全局定义。在我们所给的这个简单实例中，我们定义了全局forward――“error”，当某Action返回的forward是“error”这个映射，那么Errorpage.jsp页面将会显示给用户，尽管当前Action并没有对其定义。<BR>&nbsp;我们继续不断的开发，项目日渐完善，项目相关的配置文件也会越来越详细。在下面的例子中，我们将以StrutsSample中用到的struts-confug.xml文件为例，学习global&nbsp;forward和一个Action中相关映射的定义。下面定义了一个名为“login”的Action，其为com.oreilly.actions.LoginAction的实例，当Action处理用户登录成功后将一个名为"success"的forward返回，用户也就会看到Welcome.jsp页面，如果登录失败，Action将返回对应的forward以再显示Login.jsp给用户，而如果处理过程中发生其他错误，Action将返回全局定义的forward――“error”，用户也就会看到错误提示页面Errorpage.jsp。<BR><BR>&lt;!--&nbsp;==========&nbsp;Global&nbsp;Forward&nbsp;定义&nbsp;--&gt;<BR>&lt;global-forwards&gt;<BR>&lt;forward&nbsp;name="login"&nbsp;path="/Login.jsp"/&gt;<BR>&lt;forward&nbsp;name="error"&nbsp;path="/Errorpage.jsp"/&gt;<BR>&lt;/global-forwards&gt;<BR><BR>&lt;!--&nbsp;==========&nbsp;Action&nbsp;Mapping&nbsp;定义&nbsp;--&gt;<BR>&lt;action-mappings&gt;<BR>&lt;!--&nbsp;&lt;action&gt;元素的相关属性&nbsp;--&gt;<BR>&lt;!--<BR>以下只列出常用属性，其他请参考org.apache.struts.action.ActionMapping的相关文档<BR><BR>path&nbsp;-&nbsp;当前Action对应的用户请求URI路径<BR><BR>type&nbsp;-&nbsp;实现当前Action的Java&nbsp;class的完整名字<BR><BR>name&nbsp;-&nbsp;当前Action中用到的ActionForm的名字，其具体信息在配置文件其他地方另有详细定义<BR><BR>unknown&nbsp;-&nbsp;如果将该属性设置为true，那么就是声明这个Action将处理整个应用中所有未找到相应处理Action的请求，当然，一个应用系统中也只会有一个Action的unknown属性可以设为true<BR><BR>scope&nbsp;-&nbsp;Action中所用到的ActionForm的生存期，可以为“request”或“session”，随着生存期的设置，该Action也会在相应的时间被创建<BR><BR>input&nbsp;-&nbsp;该Action中相关ActionForm获取用户输入的输入页面，当将ActionForm设为自动验证输入数据，发现不合法数据返回错误时，将返回该页面<BR><BR>validate&nbsp;-&nbsp;如果本属性为true则在Action动作之前其对应的ActionForm的validate方法会自动被调用，一般用以验证用户输入的数据<BR><BR>forward&nbsp;元素&nbsp;-&nbsp;定义当前Action相关的ActionForward<BR>--&gt;<BR><BR>&lt;!--&nbsp;===================&nbsp;--&gt;<BR>&lt;!--&nbsp;O'Reilly&nbsp;Struts&nbsp;Sample&nbsp;Main&nbsp;Actions&nbsp;--&gt;<BR>&lt;!--&nbsp;===================&nbsp;--&gt;&nbsp;<BR>&lt;action&nbsp;path="/login"<BR>type="com.oreilly.actions.LoginAction"<BR>name="loginForm"<BR>scope="request"<BR>input="/Login.jsp"&gt;<BR>&lt;forward&nbsp;name="success"&nbsp;path="/Welcome.jsp"/&gt;<BR>&lt;forward&nbsp;name="failure"&nbsp;path="/Login.jsp"/&gt;<BR>&lt;/action&gt;<BR>&lt;/action-mappings&gt;&nbsp;<BR><BR>&nbsp;在前一篇文章中，我们曾说过，struts-config.xml就是MVC模式的的Controller。在确定struts-config.xml中的配置信息时，应该多花些时间精力在上面，以保证每一个Action定义及其相关定义是符合应用的需求的。如果在项目开始没有详细的设计其定义，当将所有代码和配置集成到一起的时候，我们将不可避免的将各部分的代码和配置完全重新组织一遍。<BR>&nbsp;我们当前的例子StrusSample因为只是处理用户登录，所以只需要一个Action。一个应用系统中所要用到的Action的多少完全依应用的大小而定。一旦整套Action的映射完全的定义出来后，我们就可以一个一个开发其具体实现的Action和ActionForm类，并逐渐将完成的部分一点一点集成起来。<BR><BR><FONT color=red>由设计完成的用户界面开发其所用到的类和应用函数</FONT><BR>&nbsp;所有ActionForm的实现类都是org.apache.struts.ActionForm的子类。一个ActionForm是与页面上的输入表单相关联的，而且ActionForm的实现还可以对用户输入数据的合法性进行验证。作为一个Java&nbsp;Bean，ActionForm有Set和Get方法，当一个页面中表单被提交时，系统将自动调用Set方法将数据放入ActionForm中，而Get方法将为在Action中操作这些数据所提供。一般来说，处理表单中的所有数据，并进行合法性验证都完全可以交由ActionForm来完成。在应用中，就我个人而言，倾向于将ActionForm和Action划分到不同的包中，因为当一个页面中要用到几对ActionFrom和Action时，都放在一个包内会混淆的。下面的代码，就是实例中登录页面用到的ActionForm的代码。<BR><BR>/*<BR>*&nbsp;LoginForm.java<BR>*/<BR>package&nbsp;com.oreilly.forms;<BR>&nbsp;<BR>import&nbsp;javax.servlet.http.HttpServletRequest;<BR>import&nbsp;org.apache.struts.action.ActionError;<BR>import&nbsp;org.apache.struts.action.ActionErrors;<BR>import&nbsp;org.apache.struts.action.ActionForm;<BR>import&nbsp;org.apache.struts.action.ActionMapping;<BR>&nbsp;<BR>/**<BR>*&nbsp;验证用户要用到的两个数据<BR>*<BR>*&nbsp;username&nbsp;-&nbsp;登录用户名<BR>*&nbsp;password&nbsp;-&nbsp;用户密码<BR>*&nbsp;<BR>*/<BR>public&nbsp;final&nbsp;class&nbsp;LoginForm&nbsp;extends&nbsp;ActionForm&nbsp;{<BR>&nbsp;private&nbsp;String&nbsp;userName&nbsp;=&nbsp;null;<BR>&nbsp;private&nbsp;String&nbsp;password&nbsp;=&nbsp;null;<BR><BR>&nbsp;/**<BR>&nbsp;*&nbsp;userName的Get方法<BR>&nbsp;*&nbsp;@return&nbsp;String&nbsp;<BR>&nbsp;*/<BR>&nbsp;public&nbsp;String&nbsp;getUserName()&nbsp;{<BR>&nbsp;&nbsp;return&nbsp;(userName);<BR>&nbsp;}<BR><BR>&nbsp;/**<BR>&nbsp;*&nbsp;userName的Set方法<BR>&nbsp;*&nbsp;@param&nbsp;userName&nbsp;<BR>&nbsp;*/<BR>&nbsp;public&nbsp;void&nbsp;setUserName(String&nbsp;newUserName)&nbsp;{<BR>&nbsp;&nbsp;userName&nbsp;=&nbsp;newUserName;<BR>&nbsp;}<BR><BR>&nbsp;/**<BR>&nbsp;*&nbsp;password的Get方法<BR>&nbsp;*&nbsp;@return&nbsp;String&nbsp;<BR>&nbsp;*/<BR>&nbsp;public&nbsp;String&nbsp;getPassword()&nbsp;{<BR>&nbsp;&nbsp;return&nbsp;(password);<BR>&nbsp;}<BR><BR>&nbsp;/**<BR>&nbsp;*&nbsp;password的Set方法<BR>&nbsp;*&nbsp;@param&nbsp;password&nbsp;<BR>&nbsp;*/<BR>&nbsp;public&nbsp;void&nbsp;setPassword(String&nbsp;newPassword)&nbsp;{<BR>&nbsp;&nbsp;password&nbsp;=&nbsp;newPassword;<BR>&nbsp;}<BR>&nbsp;<BR>&nbsp;/**<BR>&nbsp;*&nbsp;重置所有数据<BR>&nbsp;*<BR>&nbsp;*&nbsp;@param&nbsp;mapping&nbsp;当前的ActionMapping<BR>&nbsp;*&nbsp;@param&nbsp;request&nbsp;当前Server正在处理的HttpServletRequest<BR>&nbsp;*/<BR>&nbsp;public&nbsp;void&nbsp;reset(ActionMapping&nbsp;mapping,&nbsp;HttpServletRequest&nbsp;request)&nbsp;{<BR>&nbsp;&nbsp;userName&nbsp;=&nbsp;null;<BR>&nbsp;&nbsp;password&nbsp;=&nbsp;null;<BR>&nbsp;}<BR><BR>&nbsp;/**<BR>&nbsp;*&nbsp;验证当前HTTP请求提交上来的数据<BR>&nbsp;*&nbsp;如果数据验证发现不合法数据，将返回一个封装<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;所有验证错误的ActionErrors对象<BR>&nbsp;*&nbsp;如果数据验证通过，该方法返回null或者一个<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;没有封装任何验证错误的ActionErrors对象<BR>&nbsp;*<BR>&nbsp;*&nbsp;@param&nbsp;mapping&nbsp;当前的ActionMapping<BR>&nbsp;*&nbsp;@param&nbsp;request&nbsp;当前Server正在处理的HttpServletRequest<BR>&nbsp;*/<BR>&nbsp;public&nbsp;ActionErrors&nbsp;validate(ActionMapping&nbsp;mapping,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HttpServletRequest&nbsp;request)&nbsp;{<BR>&nbsp;&nbsp;ActionErrors&nbsp;errors&nbsp;=&nbsp;new&nbsp;ActionErrors();&nbsp;<BR>&nbsp;&nbsp;//&nbsp;当前ActionForm中，只需要检查用户输入的用户名数据<BR>&nbsp;&nbsp;if(&nbsp;userName&nbsp;==&nbsp;null&nbsp;||&nbsp;userName.length()==0&nbsp;){<BR>&nbsp;&nbsp;&nbsp;errors.add("userName",new&nbsp;ActionError("error.userName.required"));<BR>&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;return&nbsp;(errors);<BR>&nbsp;}<BR>}<BR><BR>&nbsp;以上的代码，只有两点和一般的Java&nbsp;Bean有所不同。其一是reset方法，方法中设置的值将在表单被reset时反应到其对应的表单项上，即将表单项的数据恢复到默认值。其二是validate方法，是用来验证用户在表单中所输入数据的方法。在当前这个例子中，我们只验证用户输入的用户名。因为一个用户名其对应的密码可能为空，所以我们的逻辑就是验证时不去检查密码。验证用户名，当发现输入的用户名为空时，方法就会产生一个错误对象（ActionError）。<BR>&nbsp;在Struts中用ActionErrors来装载多个错误，从ActionErrors结尾的那个“s”就可以知道她是一个ActionError对象的集合。在验证用户输入时，可以验证完表单中所有数据后，再将可能发现的多个错误通过ActionErrors返回给用户，这样的逻辑应该是想当然的啦，不可能用户有五个不同的输入错误，却要分五次提示，让用户修改提交五遍吧，呵呵。<BR>&nbsp;同时，要知道在我们这个例子中，我们将错误信息提示给用户是通过ApplicationResource.properties文件。这个文件在Tomcat启动时通过web.xml中的定义为这个应用所使用。通常每一个应用都在其WEB-INF目录下都有web.xml文件来描述系统，而关于部署应用时具体的结构信息，请参考Tomcat<A href="http://jakarta.apache.org/tomcat/index.html" target=_blank>http://jakarta.apache.org/tomcat/index.html</A>等Server相关的用户手册。<BR>&nbsp;ApplicationResource.properties文件中可以定义应用中所要用到的提示信息的字符串，字符串都通过一个键值来唯一确定其位置。在我们这个例子中，键值error.userName.required所对应的字符串信息是“A&nbsp;username&nbsp;is&nbsp;required”，在给用户显示错误信息时，也就通过键值确定的错误提示显示该字符串。通过这样的机制，为我们在系统中实现多语言提供了便利，将该文件中的这些字符串翻译成相应的语言，我们的系统就可以实现西班牙语、德语、法语和汉语等等语言的版本了。<BR>&nbsp;下面这些ApplicationResource.properties中的信息对于我们这个简单的示例中已经够用了：<BR><BR>login.title=Login&nbsp;Struts&nbsp;Sample<BR>error.userName.required=A&nbsp;username&nbsp;is&nbsp;required<BR>error.login.authenticate=Invalid&nbsp;username/password<BR>errors.footer=&lt;/ul&gt;&lt;hr&gt;<BR>errors.header=&lt;h3&gt;&lt;font&nbsp;color="red"&gt;Page&nbsp;<BR>Validation&lt;/font&gt;&lt;/h3&gt;Please&nbsp;correct&nbsp;the&nbsp;<BR>following&nbsp;error(s)&nbsp;before&nbsp;contiuing:&lt;ul&gt;<BR>applicationResources=Cannot&nbsp;load&nbsp;application&nbsp;resources&nbsp;bundle&nbsp;<BR>{0}<BR><BR>&nbsp;页面的标题，按钮或其他什么需要文本提示的地方都可以通过这个文件来定义显示用字符串。我们将在该系列的最后一篇文章，也就是后续几个开发步骤中讲解如何通过Struts的标签从这个文件中获取显示用字符串。<BR><BR>学习Jakarta&nbsp;Struts（第三篇）<BR>本文是三篇学习Struts框架系列文章的最后一篇（原文请见<IMG src="http://www.matrix.org.cn/images/small/url.gif" align=absMiddle><A href="http://www.onjava.com/pub/a/onjava/2001/11/14/jsp_servlets.html" target=_blank>http://www.onjava.com/pub/a/onjava/2001/11/14/jsp_servlets.html</A>）。<BR>在第一篇文章《Jakarta&nbsp;Struts简介》中，我大致分析了Struts框架，讨论了它所能完成的功能，还浏览了组成Struts的各个组成部分。在第二篇文章《学习Jakarta&nbsp;Struts》中，我开始详细描述如何利用Struts来构建一个简单应用的过程步骤。而本篇文章将会向大家演示如何将ApplicationResource文件中的文本信息，通过Struts标签在JSP页面中显示出来。<BR>Action类是连接Struts架构和应用中业务逻辑代码的桥梁。所以你应该尽可能让Action类小巧简单，因为真实应用中的逻辑处理应该是由单独分离出来的逻辑层来完成的。如果你正在从事n层应用的开发，你当然希望层与层之间的接口越简单越好。而事实上，Action类中的主要方法"perform()"（1.1中为execute()）却有点暗示应该在本方法中做点什么的意思。我们知道，每个Action类都需要从&nbsp;org.apache.struts.action.Action&nbsp;继承而来。在小型应用中，我们的Action类很可能就只要继承org.apache.struts.action.Action就足够了；而在某些特定的复杂应用中，我就从我们所实现的Action类中总结出来了一些通用特性。因此，在我看来，构造一个基类将这些通用特性的代码实现出来，让应用中所用到的所有Action类不直接继承org.apache.struts.action.Action，而继承这个完成了一些通用特性的基类以实现代码重用，是一个相当不错的设计。我在StrutsSample中就应用了这种方法，构造了这样的一个基类，该基类的方法在完成复杂逻辑的和简单转发请求的Action类中都可以使用。<BR><BR>package&nbsp;com.oreilly.actions;<BR><BR>import&nbsp;java.io.IOException;<BR>import&nbsp;java.util.Properties;<BR>import&nbsp;java.util.ResourceBundle;<BR>import&nbsp;java.util.MissingResourceException;<BR>import&nbsp;java.util.Enumeration;<BR>import&nbsp;java.util.Properties;<BR>import&nbsp;java.rmi.RemoteException;<BR>import&nbsp;javax.ejb.EJBHome;<BR>import&nbsp;javax.ejb.CreateException;<BR>import&nbsp;javax.naming.Context;<BR>import&nbsp;javax.naming.InitialContext;<BR>import&nbsp;javax.naming.NamingException;<BR>import&nbsp;javax.servlet.ServletException;<BR>import&nbsp;javax.servlet.http.HttpServletRequest;<BR>import&nbsp;javax.servlet.http.HttpServletResponse;<BR>import&nbsp;org.apache.struts.action.Action;<BR>import&nbsp;org.apache.struts.action.ActionServlet;<BR>import&nbsp;org.apache.struts.action.ActionForm;<BR>import&nbsp;org.apache.struts.action.ActionForward;<BR>import&nbsp;org.apache.struts.action.ActionMapping;<BR><BR>这个类就是使用Struts开发时，所有Action类都要继承的基类。它把一些通常在实际应用中最有可能被用到的东西都考虑进来了。就这篇文章而言，&nbsp;类中一些与Struts并不是太紧密相关的方法将只做注释而不会完整的实现，而从事开发工作的你，有兴趣的话，请完成这些方法并应用这个类，将为你在实际项目中的开发快马加鞭。注意，因为所有的Action类都要从org.apache.struts.action.Action&nbsp;继承而来，所以我们的这个类同样。<BR>public&nbsp;abstract&nbsp;class&nbsp;AbstStrutsActionBase&nbsp;extends&nbsp;Action&nbsp;{<BR>&nbsp;&nbsp;/**<BR>&nbsp;&nbsp;&nbsp;*&nbsp;定义一些在struts-config.xml中记录在案的<BR>&nbsp;&nbsp;&nbsp;*&nbsp;全局应用中皆可可通用的forward标识<BR>&nbsp;&nbsp;&nbsp;*/<BR><BR>&nbsp;&nbsp;protected&nbsp;static&nbsp;final&nbsp;String&nbsp;SUCCESS&nbsp;=&nbsp;"success";<BR>&nbsp;&nbsp;protected&nbsp;static&nbsp;final&nbsp;String&nbsp;FAILURE&nbsp;=&nbsp;"failure";<BR>&nbsp;&nbsp;protected&nbsp;static&nbsp;final&nbsp;String&nbsp;ERROR&nbsp;=&nbsp;"error";<BR>&nbsp;&nbsp;protected&nbsp;static&nbsp;final&nbsp;String&nbsp;LOGIN&nbsp;=&nbsp;"login";<BR>&nbsp;&nbsp;protected&nbsp;static&nbsp;final&nbsp;String&nbsp;CONFIRM&nbsp;=&nbsp;"confirm";<BR>&nbsp;&nbsp;protected&nbsp;Context&nbsp;jndiContext&nbsp;=&nbsp;null;<BR><BR>&nbsp;&nbsp;/**<BR>&nbsp;&nbsp;&nbsp;*&nbsp;默认构造方法<BR>&nbsp;&nbsp;&nbsp;*/<BR><BR>&nbsp;&nbsp;public&nbsp;AbstStrutsActionBase()&nbsp;{<BR>}<BR><BR>/**<BR>下面这个查找EJB实例的方法将不会完整实现。<BR>一般来说，Action类应该调用实现了应用的商务逻辑的EJB会话bean（或仅仅普通JavaBean）。在大型项目中，开发人员必须划清层与层之间的界限。在Action类中，我们应该拿到获取含有JNDI信息的环境的实例，然后通过EJB的JNDI名字去查询获取它的home接口。过程并不简单，所以下面这个代码片断只是个给出了必要实现的小例子。<BR>&nbsp;参数类型String，传入的要查询JNDI的名字<BR>&nbsp;返回类型Object，即查找到的home接口<BR>&nbsp;如果查找失败，抛出NamingException异常<BR>&nbsp;如果获取资源信息失败，抛出MissingResourceException异常<BR>*/<BR><BR>public&nbsp;Object&nbsp;lookup(String&nbsp;jndiName)<BR>&nbsp;&nbsp;&nbsp;&nbsp;throws&nbsp;NamingException,&nbsp;MissingResourceException&nbsp;{<BR>&nbsp;&nbsp;//&nbsp;为调用EJB对象，通过构建记录JNDI信息的Properties对象<BR>&nbsp;&nbsp;//&nbsp;来获得初始环境信息<BR>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(jndiContext&nbsp;==&nbsp;null)&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ResourceBundle&nbsp;resource&nbsp;=<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ResourceBundle.getBundle("strutssample.properties");<BR>&nbsp;&nbsp;&nbsp;&nbsp;Properties&nbsp;properties&nbsp;=&nbsp;new&nbsp;Properties();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;properties.setProperty(<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Context.INITIAL_CONTEXT_FACTORY,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;resource.getString(Context.INITIAL_CONTEXT_FACTORY));<BR>&nbsp;&nbsp;&nbsp;&nbsp;properties.setProperty(<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Context.PROVIDER_URL,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;resource.getString(Context.PROVIDER_URL));<BR>&nbsp;&nbsp;&nbsp;&nbsp;properties.setProperty(<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Context.SECURITY_PRINCIPAL,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;resource.getString(Context.SECURITY_PRINCIPAL));<BR>&nbsp;&nbsp;&nbsp;&nbsp;properties.setProperty(<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Context.SECURITY_CREDENTIALS,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;resource.getString(Context.SECURITY_CREDENTIALS));<BR>&nbsp;&nbsp;&nbsp;&nbsp;jndiContext&nbsp;=&nbsp;new&nbsp;InitialContext(properties);<BR>}<BR><BR>注意：在真正的产品中，我们应该在此处考虑代码的健壮性，将代码加入到try/catch块内，并记录所有错误或重要信息到系统log中。而本例中，我们仅仅把异常往外抛，并假定一定会找到EJB对象的home接口并返回。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(jndiContext.lookup(jndiName));<BR>}<BR><BR>由于Action类将是由Struts来调用的。所以它的主要方法应该是一个抽象方法，而由每个继承的子类来具体实现，或者在其中做一些所有Action都会做的通用机制，例如记录log信息。在本例中，我们一切从简，将其抽象之。<BR>&nbsp;参数mapping：其类型为ActionMapping，将在本Action做跳转选择用<BR>&nbsp;参数actionForm：由Struts根据本次HTTP请求数据填充完成的ActionForm对象（可选，如果存在请求数据的话）<BR>&nbsp;参数request：此Action所有处理的本次HTTP请求（对象）<BR>&nbsp;参数response：此Action输出数据所要用到的HTTP响应（对象）<BR>&nbsp;如果有I/O错误出现，则本方法抛出IOException异常<BR>&nbsp;如果处理时发生servlet异常，则本方法抛出ServletException异常<BR>&nbsp;本方法处理完请求后按照处理逻辑返回相应的页面导向（对象）<BR><BR>&nbsp;&nbsp;public&nbsp;abstract&nbsp;ActionForward&nbsp;perform(<BR>&nbsp;&nbsp;&nbsp;&nbsp;ActionMapping&nbsp;mapping,<BR>&nbsp;&nbsp;&nbsp;&nbsp;ActionForm&nbsp;form,<BR>&nbsp;&nbsp;&nbsp;&nbsp;HttpServletRequest&nbsp;request,<BR>&nbsp;&nbsp;&nbsp;&nbsp;HttpServletResponse&nbsp;response)<BR>&nbsp;&nbsp;&nbsp;&nbsp;throws&nbsp;IOException,&nbsp;ServletException;<BR>}<BR><BR>或者让这个抽象方法更有用一点，那就在里面干点什么吧，比如像下面这样在其中记录log。<BR><BR>&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;ActionForward&nbsp;forward&nbsp;=&nbsp;null;<BR>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;&nbsp;只是简单的记录一些提示信息到servlet&nbsp;log<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;getServlet().log(<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"AbstStrutsActionBase.perform()&nbsp;[Action&nbsp;Class:&nbsp;"<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+&nbsp;this.getClass().getName()<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+&nbsp;"&nbsp;]");<BR>&nbsp;&nbsp;&nbsp;&nbsp;getServlet().log(<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"AbstStrutsActionBase.perform()&nbsp;[Form&nbsp;Class&nbsp;:&nbsp;"<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+&nbsp;(form&nbsp;==&nbsp;null&nbsp;?&nbsp;"null"&nbsp;:&nbsp;form.getClass().getName())<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+&nbsp;"&nbsp;]");<BR>&nbsp;&nbsp;}<BR><BR>然后，我们再编写的每个Action类都应该从AbstStrutsActionBase继承，并依照处理逻辑编写各自的perform方法。让我们用LoginAction为例，看看具体应该怎么应用吧。<BR><BR>package&nbsp;com.oreilly.actions;<BR><BR>import&nbsp;java.io.IOException;<BR>import&nbsp;java.rmi.RemoteException;<BR>import&nbsp;javax.ejb.CreateException;<BR>import&nbsp;javax.servlet.ServletException;<BR>import&nbsp;javax.servlet.http.HttpServletRequest;<BR>import&nbsp;javax.servlet.http.HttpServletResponse;<BR>import&nbsp;org.apache.struts.action.ActionError;<BR>import&nbsp;org.apache.struts.action.ActionErrors;<BR>import&nbsp;org.apache.struts.action.ActionForm;<BR>import&nbsp;org.apache.struts.action.ActionMapping;<BR>import&nbsp;org.apache.struts.action.ActionForward;<BR>import&nbsp;com.oreilly.forms.LoginForm;<BR><BR>/*<BR>LoginAction&nbsp;将演示一个Action将如何被Struts架构所调用<BR>在这个例子中，我们只是简单的演示perform方法是如何调用、执行并返回的<BR>*/<BR><BR>public&nbsp;class&nbsp;LoginAction&nbsp;extends&nbsp;AbstStrutsActionBase&nbsp;{<BR><BR>接下来这个是验证用户的方法，本例中没有具体实现。但一个典型的应用方案是调用JavaBean或者EJB来完成。用来查找EJB的lookup方法（在基类中完成的）应该在本方法中被调用，其返回一个依据后台数据库验证用户的接口。<BR>&nbsp;参数类型String，要验证的用户名<BR>&nbsp;参数类型String，密码<BR>&nbsp;返回类型boolean，如果验证通过为true，否则为false<BR><BR>public&nbsp;boolean&nbsp;authenticate(String&nbsp;username,&nbsp;String&nbsp;password)&nbsp;{<BR>/*&nbsp;本方法将先做一个查找动作，获得验证用户的EJB对象的接口并调用<BR>*&nbsp;由于本例只演示Action与商务逻辑层是如何交互的&nbsp;<BR>*&nbsp;所以具体实现代码本例中就不提供了:)<BR>&nbsp;&nbsp;&nbsp;*/<BR>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(true);<BR>}<BR><BR>接下来我们在LoginAction中重载基类的perform方法。<BR>&nbsp;参数mapping：其类型为ActionMapping，将在本Action做跳转选择用<BR>&nbsp;参数actionForm：由Struts根据本次HTTP请求数据填充完成的ActionForm对象（可选，如果存在请求数据的话）<BR>&nbsp;参数request：此Action所有处理的本次HTTP请求（对象）<BR>&nbsp;参数response：此Action输出数据所要用到的HTTP响应（对象）<BR>&nbsp;如果有I/O错误出现，则本方法抛出IOException异常<BR>&nbsp;如果处理时发生servlet异常，则本方法抛出ServletException异常<BR>&nbsp;本方法处理完请求后按照处理逻辑返回相应的页面导向（对象）<BR><BR>&nbsp;&nbsp;public&nbsp;ActionForward&nbsp;perform(<BR>&nbsp;&nbsp;&nbsp;&nbsp;ActionMapping&nbsp;mapping,<BR>&nbsp;&nbsp;&nbsp;&nbsp;ActionForm&nbsp;form,<BR>&nbsp;&nbsp;&nbsp;&nbsp;HttpServletRequest&nbsp;request,<BR>&nbsp;&nbsp;&nbsp;&nbsp;HttpServletResponse&nbsp;response)<BR>&nbsp;&nbsp;&nbsp;&nbsp;throws&nbsp;IOException,&nbsp;ServletException&nbsp;{<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;先假定验证失败，那么要导向的forward当然是LOGIN了（见基类定义的全局变量）<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;boolean&nbsp;validLogin&nbsp;=&nbsp;false;<BR>&nbsp;&nbsp;&nbsp;&nbsp;ActionForward&nbsp;actionForward&nbsp;=&nbsp;mapping.findForward(LOGIN);<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;构造出承载ActionError对象的容器——errors，以备错误出现时可用<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;ActionErrors&nbsp;errors&nbsp;=&nbsp;new&nbsp;ActionErrors();<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;从由本次请求构造的ActionForm中提取出所需要的数据<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;LoginForm&nbsp;loginForm&nbsp;=&nbsp;(LoginForm)form;<BR>&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;userName&nbsp;=&nbsp;null;<BR>&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;password&nbsp;=&nbsp;null;<BR>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(loginForm&nbsp;!=&nbsp;null)&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;userName&nbsp;=&nbsp;loginForm.getUserName();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;password&nbsp;=&nbsp;loginForm.getPassword();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;validLogin&nbsp;=&nbsp;authenticate(userName,&nbsp;password);<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(validLogin)&nbsp;{<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;验证成功了，导向到struts-config.xml中定义的SUCCESS<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;actionForward&nbsp;=&nbsp;mapping.findForward(SUCCESS);<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;存点必要的东东到session，以备后用<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;request.getSession(true).setAttribute("USERNAME",&nbsp;userName);<BR>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;errors.add("login",&nbsp;new&nbsp;ActionError("error.login.authenticate"));<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;系统如果用户界面友好一点，我们就应该将错误信息存入request对象中<BR>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;然后到页面，通过在Struts的标签显示出来<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(!errors.empty())&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;saveErrors(request,&nbsp;errors);<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;本Action处理完成，导向到合适的forward<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(actionForward);<BR>&nbsp;&nbsp;}<BR><BR>}<BR><BR>注意，这个LoginAction类就是在struts-config.xml中定义的用来处理登录事务的一个具体实现。当这个类被载入并有一个对象实例化后，Struts架构就会调用它的perform方法。这个方法是这样声明的：<BR><BR>&nbsp;&nbsp;public&nbsp;ActionForward&nbsp;perform(<BR>&nbsp;&nbsp;&nbsp;&nbsp;ActionMapping&nbsp;mapping,<BR>&nbsp;&nbsp;&nbsp;&nbsp;ActionForm&nbsp;form,<BR>&nbsp;&nbsp;&nbsp;&nbsp;HttpServletRequest&nbsp;request,<BR>&nbsp;&nbsp;&nbsp;&nbsp;HttpServletResponse&nbsp;response)<BR>throws&nbsp;IOException,&nbsp;ServletException&nbsp;<BR><BR>其中，mapping是一个记录与此Action对应的forward导向的对象，form对象封装由客户端提交的此Action要处理的数据，还有标准的HttpServletRequest对象和HttpServletResponse对象。<BR>有了这些对象的辅助，此Action就可以拿到需要的东东顺利开工了。我们的例子中，要处理的数据主要是用户名和密码，这些都由form对象提供。实现验证功能是本应用的主要业务逻辑，在方法中的具体实现应该是去取EJB的相应接口来操作或者直接去拿数据库数据来验证。前面那个AbstStrutsActionBase类中已经实现了一个简单的EJB接口查找动作，所以如果我们是在开发一个基于EJB实现的系统，它的可重用性就非常强了。<BR>由验证方法（authenticate()）的返回值，Action要接着做出合理的动作。如果验证通过，就要让用户进入正确的页面，那么我们就将一些后面可能会用到的信息存入request对象（译注：准确的讲，代码中是存到了session对象里，当然session对象是和当前request相关的），并向Struts返回success这个forward。这个forward是在struts-config.xml中定义的，然后由ActionMapping封装起来，在Action处理中可以从中拿出合适的forward做为返回值。如果回头去看看struts-config.xml中的定义，就会知道success这个forward会将用户导向至Welcome.jsp这个页面的。如果验证失败，则将一个错误信息存起来，然后导向到一个错误提示页面显示出来。<BR><BR>开发应用的业务逻辑<BR><BR>在一个真实的应用系统中，我们应该将业务逻辑层整合进来了。在我们这个例子里，我们就应该去开发LoginAction中的authenticae方法所调用到的EJB了。但是正如你所见的，我们完全可以把这一层暂时屏蔽掉，而利用Struts把前端部分构建并能够让它跑起来的。我其实相当推崇的是方法是先将应用框架搭建并运行起来，然后在开发后台实际的业务逻辑层。在应用框架完全恰当的构建起来的时候，后台的开发工作所有做的debug工作也少的多了。而且，业务逻辑的开发也不是本文所要函概的范围，所以此处我们略过，不过我相信你现在一定对应用的全局有了总体的把握了吧！<BR><BR>开发由ActionMapping定义的系统工作流程，完成对应的JSP页面<BR><BR>终于可以将所有这些东东整合在一起了。在struts-config.xml配置文件中定义的那些ActionMapping，我们要完成这些ActionMapping定义用到的JSP页面。本例中，包括Login.jsp、Welcome.jsp和Errorpage.jsp。还有，尽管我们在本例中都是将Action处理完成forward到JSP页面，这在这个简单的例子中是再恰当不过的逻辑流程了，而在实际利用Struts开发应用中呢，当然可以从Action&nbsp;forward到其他的Action。我们这个简单的Login.jsp页面内容是这样的：<BR>&lt;%@&nbsp;page&nbsp;language="java"&nbsp;%&gt;<BR>&lt;%@&nbsp;taglib&nbsp;uri="/WEB-INF/struts-html.tld"&nbsp;prefix="html"&nbsp;%&gt;<BR>&lt;%@&nbsp;taglib&nbsp;uri="/WEB-INF/struts-form.tld"&nbsp;prefix="form"&nbsp;%&gt;<BR>&lt;%@&nbsp;taglib&nbsp;uri="/WEB-INF/struts-bean.tld"&nbsp;prefix="bean"&nbsp;%&gt;<BR><BR>&lt;html&gt;<BR>&lt;head&gt;<BR>&lt;title&gt;&lt;bean:message&nbsp;key="login.title"/&gt;&lt;/title&gt;<BR>&lt;/head&gt;<BR>&lt;body&gt;<BR>&lt;html:errors/&gt;<BR>&lt;h3&gt;Enter&nbsp;your&nbsp;username&nbsp;and&nbsp;password&nbsp;to&nbsp;login:&lt;/h3&gt;<BR>&lt;html:form&nbsp;action="login.action"&nbsp;focus="userName"&nbsp;&gt;<BR>&lt;html:text&nbsp;property="userName"&nbsp;size="30"&nbsp;maxlength="30"/&gt;<BR>&lt;html:password&nbsp;property="password"&nbsp;size="16"&nbsp;maxlength="16"&nbsp;redisplay="false"/&gt;&nbsp;<BR>&lt;html:submit&nbsp;property="submit"&nbsp;value="Submit"/&gt;<BR>&lt;html:reset/&gt;<BR>&lt;/html:form&gt;<BR>&lt;/body&gt;<BR>&lt;/html&gt;<BR>Struts在JSP自定义标签库的基础上提供了一套综合各种功能的标签库。利用这些标签库很容易的构建用户界面了。使用这些标签库的好处之一就是可以利用其提供的很多附加功能。比如在一般的JSP页面的表单里我们可以看到这样常见的HTML片断：<BR>&lt;input&nbsp;type="text"&nbsp;name="userName"&nbsp;value=""&gt;<BR>如果我们使用Struts的标签库的话，就可以改成这样子：<BR>&lt;html:text&nbsp;property&nbsp;="userName"&gt;<BR>不过我们得现在页面中先声明Struts标签库的定义。<BR><BR>&lt;%@&nbsp;taglib&nbsp;uri="/WEB-INF/struts-html.tld"&nbsp;prefix="html"&nbsp;%&gt;<BR><BR>在这个例子中，我们会用到一些Struts标签，但我不准备在此详细讲解Struts各种标签库的用法。相信在你不断使用Struts搭建功能复杂的JSP页面的过程中，你将会对所使用过的标签越来越熟悉的。到那时，你也将更能体会到Struts标签的益处，利用它们大大的缩短你的开发时间。目前，你可以从Struts&nbsp;Developers&nbsp;Guides了解到更多的细节。<BR>在我们这个简单例子中，有两个重点。其一：<BR><BR>&lt;title&gt;&lt;bean:message&nbsp;key="login.title"/&gt;&lt;/title&gt;<BR><BR>这就是在利用我们前面提到的资源文件ApplicationResource来在页面显示信息，而不是将信息文本硬编码到我们的应用中。<BR>其二：<BR><BR>&lt;html:errors/&gt;<BR><BR>这就是在页面中显示出ActionErrors的信息，也就是我们在LoginForm的验证方法和LoginAction中产生的报错信息的集合对象。<BR>页面中的表单，利用Struts，我们将用如下的标签来定义：<BR><BR>&lt;html:form&nbsp;action="login.action"&nbsp;focus="userName"&gt;<BR><BR>这里的login.action，是和struts-config.xml中定义ActionMapping相匹配的。在页面标签中这样的定义，就将相关的Action、ActionForm和ActionForward完整的串了起来。当这个用标签定义的表单提交的时候，Struts中的ActionServlet就会将其交由login.action来处理。具体的过程我们下面慢慢深入。<BR>在Welcome.jsp中，我们只演示如何将Action中的信息传递到页面加以利用的一般机制：<BR><BR>&lt;html&gt;<BR>&lt;title&gt;Welcome&nbsp;to&nbsp;Struts&lt;/title&gt;<BR>&lt;body&gt;<BR>&lt;p&gt;Welcome&nbsp;&lt;%=&nbsp;(String)request.getSession().getAttribute("USERNAME")&nbsp;%&gt;&lt;/p&gt;<BR>&lt;/p&gt;You&nbsp;have&nbsp;logged&nbsp;in&nbsp;successfully!&lt;/p&gt;<BR>&lt;/body&gt;<BR>&lt;/html&gt;<BR><BR>还记得吗？我们在LoginAction中的perform()方法中将USERNAME放到了session中哦。<BR><BR>完成系统配置文件<BR><BR>我们已经就struts-config.xml谈了好多了。通常，这个文件中的信息会在开发过程中逐渐完善。但是到了开发过程的最后一部，我们更应该回头去检查这个至关重要的配置文件，以保证万无一失：Action、JSP页面还有ActionForm都应该在文件中正确的定义。此外，我们还不得不说到web.xml。这个文件是JSP容器（例如Tomcat）获取应用相关配置的重要文件。我们这个StrutsSample例子所用到的web.xml大致是这样的：<BR><BR>&lt;?xml&nbsp;version="1.0"&nbsp;encoding="ISO-8859-1"?&gt;<BR>&lt;!--<BR>This&nbsp;is&nbsp;the&nbsp;web-app&nbsp;configuration&nbsp;that&nbsp;allow&nbsp;the&nbsp;strutsSample&nbsp;to&nbsp;work&nbsp;under<BR>Apache&nbsp;Tomcat.&nbsp;<BR>--&gt;<BR><BR>&lt;!DOCTYPE&nbsp;web-app<BR>PUBLIC&nbsp;"-//Sun&nbsp;Microsystems,&nbsp;Inc.//DTD&nbsp;Web&nbsp;Application&nbsp;2.2//EN"<BR>"<IMG src="http://www.matrix.org.cn/images/small/url.gif" align=absMiddle><A href='http://java.sun.com/j2ee/dtds/web-app_2_2.dtd"' target=_blank>http://java.sun.com/j2ee/dtds/web-app_2_2.dtd"</A>;&gt;<BR>&lt;web-app&gt;<BR>&lt;servlet&gt;<BR>&lt;servlet-name&gt;oreilly&lt;/servlet-name&gt;<BR>&lt;servlet-class&gt;org.apache.struts.action.ActionServlet&lt;/servlet-class&gt;<BR>&lt;init-param&gt;<BR>&lt;param-name&gt;application&lt;/param-name&gt;<BR>&lt;param-value&gt;com.oreilly.ApplicationResources&lt;/param-value&gt;<BR>&lt;/init-param&gt;<BR>&lt;init-param&gt;<BR>&lt;param-name&gt;config&lt;/param-name&gt;<BR>&lt;param-value&gt;/WEB-INF/struts-config.xml&lt;/param-value&gt;<BR>&lt;/init-param&gt;<BR>&lt;init-param&gt;<BR>&lt;param-name&gt;debug&lt;/param-name&gt;<BR>&lt;param-value&gt;2&lt;/param-value&gt;<BR>&lt;/init-param&gt;<BR>&lt;init-param&gt;<BR>&lt;param-name&gt;detail&lt;/param-name&gt;<BR>&lt;param-value&gt;2&lt;/param-value&gt;<BR>&lt;/init-param&gt;<BR>&lt;init-param&gt;<BR>&lt;param-name&gt;validate&lt;/param-name&gt;<BR>&lt;param-value&gt;true&lt;/param-value&gt;<BR>&lt;/init-param&gt;<BR>&lt;load-on-startup&gt;2&lt;/load-on-startup&gt;<BR>&lt;/servlet&gt;<BR><BR>&lt;servlet-mapping&gt;<BR>&lt;servlet-name&gt;oreilly&lt;/servlet-name&gt;<BR>&lt;url-pattern&gt;*.action&lt;/url-pattern&gt;<BR>&lt;/servlet-mapping&gt;<BR><BR>&lt;welcome-file-list&gt;<BR>&lt;welcome-file&gt;Login.jsp&lt;/welcome-file&gt;<BR>&lt;/welcome-file-list&gt;<BR><BR>&lt;!--&nbsp;Struts&nbsp;Tag&nbsp;Library&nbsp;Descriptors&nbsp;--&gt;&nbsp;<BR>&lt;taglib&gt;<BR>&lt;taglib-uri&gt;/WEB-INF/struts.tld&lt;/taglib-uri&gt;<BR>&lt;taglib-location&gt;/WEB-INF/struts.tld&lt;/taglib-location&gt;<BR>&lt;/taglib&gt;<BR><BR>&lt;taglib&gt;<BR>&lt;taglib-uri&gt;/WEB-INF/struts-bean.tld&lt;/taglib-uri&gt;<BR>&lt;taglib-location&gt;/WEB-INF/struts-bean.tld&lt;/taglib-location&gt;<BR>&lt;/taglib&gt;<BR><BR>&lt;taglib&gt;<BR>&lt;taglib-uri&gt;/WEB-INF/struts-html.tld&lt;/taglib-uri&gt;<BR>&lt;taglib-location&gt;/WEB-INF/struts-html.tld&lt;/taglib-location&gt;<BR>&lt;/taglib&gt;<BR><BR>&lt;taglib&gt;<BR>&lt;taglib-uri&gt;/WEB-INF/struts-logic.tld&lt;/taglib-uri&gt;<BR>&lt;taglib-location&gt;/WEB-INF/struts-logic.tld&lt;/taglib-location&gt;<BR>&lt;/taglib&gt;<BR><BR>&lt;taglib&gt;<BR>&lt;taglib-uri&gt;/WEB-INF/struts-form.tld&lt;/taglib-uri&gt;<BR>&lt;taglib-location&gt;/WEB-INF/struts-form.tld&lt;/taglib-location&gt;<BR>&lt;/taglib&gt;<BR><BR>&lt;/web-app&gt;<BR><BR>这里的&lt;servlet&gt;标签定义了org.apache.struts.action.ActionServlet，而且在本例中，我们把这个定义的servlet叫作“oreilly”，并传了两个初始化参数给它：其一是我们为这个应用所需的显示字符串定义的资源文件，其二是指明struts-config.xml文件的位置。相信你也注意到了，在&lt;servlet-mapping&gt;中为这个Servlet指明的相应请求处理串是*.action，这是和我们在页面中的表单定义的提交的URL是吻合的。也就是说，我们通过&lt;servlet-mapping&gt;标签告诉Tomcat，所有后缀为.action的请求都交给“oreilly”这个Servlet来处理。你当然可以指定你喜欢的后缀。在Struts附带的例子中，你可能会看到通常以.do做为后缀，不过我认为.action更明确一些。&lt;welcome-file-list&gt;标签中定义了本应用初始显示页面。最后呢，我们还要把会用到的Struts标签库列在后面。<BR><BR>编译/测试/发布<BR><BR>到此为止，编译/测试/发布应用之前的所有工作都完成了。用Ant来编译整个应用是相当容易的。如果你以前没有接触过Ant，那最好把这个研究一下。其实学习和应用Ant来管理一个应用编译环境并不难。我把这个编译应用所要用到的build.xml和例子放到了一起，这篇文章所要用到的所有东东，你都可以点此下载，到时候你到build.xml所在目录简单执行ant命令就可以完成编译，并打包成strutsSample.war包。当然要执行ant，你得先去下载Ant。将Ant下载回来并搭建好环境可能得花十几分钟的时间哦。<BR>本应用的目录结构如下：<BR>StrutsSample根目录<BR>&nbsp;*.jsp<BR>&nbsp;WEB-INF目录<BR>&nbsp;&nbsp;Struts配置文件（struts-config.xml,&nbsp;web.xml）<BR>&nbsp;&nbsp;classes目录（还是以Java程序文件包结构为路径）<BR>&nbsp;&nbsp;lib目录（struts.jar）<BR><BR>拿到了应用的war包，我们就将它放到Tomcat的webapps路径下，然后启动Tomcat。war包会被自动展开，此应用的上下文环境也会由Tomcat自动建立起来。我们通过web.xml告知Tomcat这个应用所需的其他资源在哪里。现在，我们可以通过<IMG src="http://www.matrix.org.cn/images/small/url.gif" align=absMiddle><A href="http://localhost:8080/strutsSample" target=_blank>http://localhost:8080/strutsSample</A>来访问我们的应用了。如果没有特别指定的话，Tomcat默认的端口是8080，我们定义的默认初始页面Login.jsp也将显示出来，现在我们来试试吧。<BR><BR>结论<BR><BR>通过本系列的文章，我们利用Struts从应用需求开始，一步步将整个应用搭建起来。和普通的JSP技术相比，通过Struts开发的应用涉及到更多的与之相关的各类文件，也正是依靠各类文件，我们才可能构建一个适合开发复杂应用的MVC架构。我们的第一个Struts应用花了如此多的时间，是为了要弄清楚Struts的各个部分到底是如何工作的。<BR>希望本系列Struts文章，能够帮助你了解Struts是由哪些部分构成的，它们能够完成什么，也希望介绍一个比较好的开发流程可供你参考。Struts才诞生不久，我有信心它将成为我们构建J2EE应用的优秀工具。<BR><img src ="http://www.blogjava.net/jackybu/aggbug/4168.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jackybu/" target="_blank">辰</a> 2005-05-11 14:45 <a href="http://www.blogjava.net/jackybu/articles/4168.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>WebWork 2 : Comparison to Struts</title><link>http://www.blogjava.net/jackybu/articles/3109.html</link><dc:creator>辰</dc:creator><author>辰</author><pubDate>Mon, 11 Apr 2005 02:33:00 GMT</pubDate><guid>http://www.blogjava.net/jackybu/articles/3109.html</guid><wfw:comment>http://www.blogjava.net/jackybu/comments/3109.html</wfw:comment><comments>http://www.blogjava.net/jackybu/articles/3109.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jackybu/comments/commentRss/3109.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jackybu/services/trackbacks/3109.html</trackback:ping><description><![CDATA[<DIV class=pageheader><SPAN class=pagetitle>from:http://www.opensymphony.com/webwork/wikidocs/Comparison%20to%20Struts.html<BR>WebWork 2 : Comparison to Struts </SPAN></DIV>
<DIV class=pagesubheading>This page last changed on Jun 18, 2004 by <FONT color=#0050b2>plightbo</FONT>. </DIV>
<P class=paragraph>
<H2 class=heading2 style="MARGIN: 4px 0px"><A name=ComparisontoStruts-FeatureComparison>Feature Comparison</A></H2>
<P></P>
<TABLE class=wiki-table cellSpacing=0 cellPadding=0 border=0>
<TBODY>
<TR>
<TH>Feature</TH>
<TH>Struts</TH>
<TH>WebWork 1.x</TH>
<TH>WebWork 2.x</TH></TR>
<TR class=table-odd>
<TD><B class=strong>Action classes</B></TD>
<TD>Struts requires Action classes to extend an Abstract base class. This shows a common problem in Struts of programming to abstract classes instead of interfaces.</TD>
<TD>Action classes must implement the webwork.Action Interface. There are other Interfaces which can be implemented for other services, such as storing error messages, getting localized texts, etc. The ActionSupport class implements many of these Interfaces and can act as a base class. WebWork is all written to Interfaces, which allows for plugging in your own implementations.</TD>
<TD>An Action must implement the com.opensymphony.xwork.Action Interface, with a series of other Interfaces for other services, like in WebWork 1.x. WebWork2 has its own ActionSupport to implement these Interfaces.</TD></TR>
<TR class=table-even>
<TD><B class=strong>Threading Model</B></TD>
<TD>Struts Actions must be thread-safe because there will only be one instance to handle all requests. This places restrictions on what can be done with Struts Actions as any resources held must be thread-safe or access to them must be synchronized.</TD>
<TD>WebWork Actions are instantiated for each request, so there are no thread-safety issues. In practice, Servlet containers generate many throw-away objects per request, and one more Object does not prove to be a problem for performance or garbage collection.</TD>
<TD>ditto</TD></TR>
<TR class=table-odd>
<TD><B class=strong>Servlet Dependency</B></TD>
<TD>Struts Actions have dependencies on Servlets because they get the ServletRequest and ServletResponse (not HttpServletRequest and HttpServletResponse, I've been told) when they are executed. This tie to Servlets (although not Http*) is a defacto tie to a Servlet container, which is an unneeded dependency. Servlets may be used outside a Web context, but it's not a good fit for JMS, for instance.</TD>
<TD>WebWork Actions are not tied to the web or any container. WebWork actions CAN choose to access the request and response from the ActionContext, but it is not required and should be done only when ABSOLUTELY neccessary to avoid tieing code to the Web.</TD>
<TD>ditto</TD></TR>
<TR class=table-even>
<TD><B class=strong>Testability</B></TD>
<TD>Many strategies have sprung up around testing Struts applications, but the major hurdle is the fact that Struts Actions are so tightly tied to the web (receiving a Request and Response object). This often leads people to test Struts Actions inside a container, which is both slow and NOT UNIT TESTING. There is a Junit extension : Struts TestCase (<A title="Visit page outside Confluence" href="http://strutstestcase.sourceforge.net/"><FONT color=#002c99>http://strutstestcase.sourceforge.net/</FONT></A>)</TD>
<TD>WebWork actions can be tested by instantiating your action, setting the properties, and executing them</TD>
<TD>ditto, but the emphasis on Inversion of Control makes testing even simpler, as you can just set a Mock implementation of your services into your Action for testing, instead of having to set up service registries or static singletons</TD></TR>
<TR class=table-odd>
<TD><B class=strong>FormBeans</B></TD>
<TD>Struts requires the use of FormBeans for every form, necessitating either a lot of extra classes or the use of DynaBeans, which are really just a workaround for the limitation of requiring FormBeans</TD>
<TD>WebWork 1.x allows you to have all of your properties directly accessible on your Action as regular Javabeans properties, including rich Object types which can have their own properties which can be accessed from the web page. WebWork also allows the FormBean pattern, as discussed in "<A title="Populate Form Bean and access its value" href="http://wiki.opensymphony.com//display/WW1/Populate+Form+Bean+and+access+its+value"><FONT color=#002c99>WW1:Populate Form Bean and access its value</FONT></A>"</TD>
<TD>WebWork 2 allows the same features as WebWork 1, but adds ModelDriven Actions, which allow you to have a rich Object type or domain object as your form bean, with its properties directly accessible to the web page, rather than accessing them as sub-properties of a property of the Action.</TD></TR>
<TR class=table-even>
<TD><B class=strong>Expression Language</B></TD>
<TD>Struts 1.1 integrates with JSTL, so it uses the JSTL EL. This EL has basic object graph traversal, but relatively weak collection and indexed property support.</TD>
<TD>WebWork 1.x has its own Expression language which is built for accessing the ValueStack. Collection and indexed property support are basic but good. WebWork can also be made to work directly with JSTL using the Filter described in <A title="Using JSTL seamlessly with WebWork" href="http://wiki.opensymphony.com//display/WW1/Using+JSTL+seamlessly+with+WebWork"><FONT color=#002c99>WW1:Using JSTL seamlessly with WebWork</FONT></A></TD>
<TD>WebWork 2 uses <A title=Ognl href="http://wiki.opensymphony.com//display/XW/Ognl"><FONT color=#002c99>XW:Ognl</FONT></A> which is a VERY powerful expression language, with additions for accessing the value stack. Ognl supports very powerful collection and indexed property support. Ognl also supports powerful features like projections (calling the same method on each member of a collection and building a new collection of the results), selections (filtering a collection with a selector expression to return a subset), list construction, and lambda expressions (simple functions which can be reused). Ognl also allows access to static methods, static fields, and constructors of classes. WebWork2 may also use JSTL as mentioned in <A title="Using JSTL seamlessly with WebWork" href="http://wiki.opensymphony.com//display/WW1/Using+JSTL+seamlessly+with+WebWork"><FONT color=#002c99>WW1:Using JSTL seamlessly with WebWork</FONT></A></TD></TR>
<TR class=table-odd>
<TD><B class=strong>Binding values into views</B></TD>
<TD>Struts uses the standard JSP mechanism for binding objects into the page context for access, which tightly couples your view to the form beans being rendered</TD>
<TD>WebWork sets up a ValueStack which the WebWork taglibs access to dynamically find values very flexibly without tightly coupling your view to the types it is rendering. This allows you to reuse views across a range of types which have the same properties.</TD>
<TD>ditto</TD></TR>
<TR class=table-even>
<TD><B class=strong>Type Conversion</B></TD>
<TD>Struts FormBeans properties are usually all Strings. Struts uses Commons-Beanutils for type conversion. Converters are per-class, and not configurable per instance. Getting a meaningful type conversion error out and displaying it to the user can be difficult.</TD>
<TD>WebWork 1.x uses PropertyEditors for type conversion. PropertyEditors are per type and not settable per Action, but field error messages are added to the field error map in the Action to be automatically displayed to the user with the field.</TD>
<TD>WebWork2 uses Ognl for type conversion with added converters provided for all basic types. Type converters default to these converters, but type conversion can be specified per field per class. Type conversion errors also have a default error message but can be set per field per class using the localization mechanism in WW2 and will be set into the field error messages of the Action.</TD></TR>
<TR class=table-odd>
<TD><B class=strong>Modular Before &amp; After Processing</B></TD>
<TD>Class hierarchies of base Actions must be built up to do processing before and after delegating to the Action classes, which can lead deep class hierarchies and limitations due to the inability to have multiple inheritance <EM class=emphasis><A title="1 on Comparison to Struts" href="http://www.opensymphony.com/webwork/wikidocs/Comparison%20to%20Struts.html#ComparisontoStruts-1"><FONT color=#002c99>WW:Comparison to Struts#1</FONT></A></EM></TD>
<TD>Class hierarchies</TD>
<TD>WebWork 2 allows you to modularize before and after processing in Interceptors. Interceptors can be applied dynamically via the configuration without any coupling between the Action classes and the Interceptors.</TD></TR>
<TR class=table-even>
<TD><B class=strong>Validation</B></TD>
<TD>Struts calls validate() on the FormBean. Struts users often use Commons Validation for validation. I don't know a lot about this, so I'll put some questions here: <BR clear=all>&nbsp;<BR clear=all>Because FormBean properties are usually Strings, some types of validations must either be duplicated (checking type conversion) or cannot be done? <BR clear=all>&nbsp;<BR clear=all>Can Commons Validation have different validation contexts for the same class? (I've been told yes, so that's a good thing) <BR clear=all>&nbsp;<BR clear=all>Can Commons Validation chain to validations on sub-objects, using the validations defined for that object properties class?</TD>
<TD>WebWork1.x calls the validate() method on Actions, which can either do programmatic validations or call an outside validation framework (this is apparently the same as Struts)</TD>
<TD>WebWork2 can use the validate() method of WebWork and Struts and / or use the <A title="Validation Framework" href="http://wiki.opensymphony.com//display/XW/Validation+Framework"><FONT color=#002c99>XW:Validation Framework</FONT></A>, which is activated using an XWork Interceptor. The Xwork Validation Framework allows you to define validations in an XML format with default validations for a class and custom validations added for different validation contexts. The Xwork Validation Framework is enabled via an Interceptor and is therefore completely decoupled from your Action class. The Xwork Validation Framework also allows you to chain the validation process down into sub-properties using the VisitorFieldValidator which will use the validations defined for the properties class type and the validation context.</TD></TR>
<TR class=table-odd>
<TD><B class=strong>Control Of Action Execution</B></TD>
<TD>As far as I know Struts sets up the Action object for you, and you have very little control over the order of operations. To change them I think <IMG class=rendericon height=16 alt="" src="http://www.opensymphony.com/webwork/wikidocs/icons/emoticons/help_16.gif" width=16 align=absMiddle border=0> you need to write your own Servlet to handle dispatching as you want</TD>
<TD>The ActionFactory chain controls the order in which an Action is constructed and initialised, but this requires writing a class</TD>
<TD>The interceptor stacks in WebWork 2 are hugely powerful in this regard. All aspects of Action setup have been moved into Interceptor implementations (ie setting paramters from the web, validation etc), so you can control on a per action basis the order in which they are performed. For example you might want your IOC framework to setup the action before the parameters are set from the request or vice versa - you can thusly control this on a per package or per action basis with interceptor stacks.</TD></TR></TBODY></TABLE>
<P class=paragraph>
<H2 class=heading2><A name=ComparisontoStruts-References>References</A></H2>
<P></P>
<UL class=star>
<LI><A title="Visit page outside Confluence" href="http://www.mail-archive.com/opensymphony-webwork@lists.sourceforge.net/msg00995.html"><FONT color=#002c99>http://www.mail-archive.com/opensymphony-webwork@lists.sourceforge.net/msg00995.html</FONT></A> - compares Struts development to WebWork 1.x development from the point of view of a Stuts developer who switched to WebWork 
<LI><A title="Visit page outside Confluence" href="http://www.mail-archive.com/opensymphony-webwork@lists.sourceforge.net/msg04700.html"><FONT color=#002c99>http://www.mail-archive.com/opensymphony-webwork@lists.sourceforge.net/msg04700.html</FONT></A> - Kind of the first draft of this comparison </LI></UL>
<H2 class=heading2><A name=ComparisontoStruts-Footnotes>Footnotes</A></H2>
<OL>
<LI><A name=ComparisontoStruts-1></A>Some Stuts users have built the beginnings of an Interceptor framework for Struts (<A title="Visit page outside Confluence" href="http://struts.sourceforge.net/saif/"><FONT color=#002c99>http://struts.sourceforge.net/saif/</FONT></A>). It currently has some serious limitations (no "around" processing, just before and after) and is not part of the main Struts project </LI></OL><img src ="http://www.blogjava.net/jackybu/aggbug/3109.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jackybu/" target="_blank">辰</a> 2005-04-11 10:33 <a href="http://www.blogjava.net/jackybu/articles/3109.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>