<?xml version="1.0"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>NetBeans星球</title>
    <link>http://www.planetnetbeans.org/zh_cn/</link>
    <language>zh</language>
    <description>NetBeans星球 - http://www.planetnetbeans.org/zh_cn/</description>
    <item>
      <title>Jerry's Blog--NetBeans: JavaFX.com 简体中文版全新上线</title>
      <guid isPermaLink="false">http://maoa.cn/jerry/html/2008/12/200812222210015812.htm</guid>
      <link>http://maoa.cn/jerry/html/2008/12/200812222210015812.htm</link>
      <description>&lt;p&gt;JavaFX 提供了一种新的脚本语言（JavaFX Script），专为喜欢在可视化编程中的 Web 脚本人员和应用程序开发人员量身定做。JavaFX Script 是一种简单的、易于学习的声明性脚本语言，它允许开发人员编写精确匹配 GUI 布局代码。同时，这种语言完全面向对象，包括方法和属性，允许专业程序员构建高度复杂且健壮的界面。&lt;/p&gt; &lt;p&gt;JavaFX SDK 1.0 已经在12月初正式发布，其官方站点 JavaFX.com 的简体中文版本也于近日在 &lt;a href="http://developers.sun.com.cn/"&gt;Sun 中国技术社区&lt;/a&gt;网站全新上线。该网站提供了大量的示例代码和中文教程供学习和体验，同时 NetBeans 和 JavaFX 插件打包版本也一并放出，这使得开发 JavaFX 更加便捷和迅速。&lt;/p&gt; &lt;ul&gt; &lt;li&gt;JavaFX.com 简体中文版&lt;br /&gt; &lt;a
      href="http://developers.sun.com.cn/javafx/"&gt;http://developers.sun.com.cn/javafx/&lt;/a&gt;&lt;/li&gt; &lt;li&gt;JavaFX 开发者中心&lt;br /&gt; &lt;a href="http://developers.sun.com.cn/javafx/index2.jsp"&gt;http://developers.sun.com.cn/javafx/index2.jsp&lt;/a&gt;&lt;/li&gt; &lt;li&gt;JavaFX Script 入门教程&lt;br /&gt; &lt;a href="http://developers.sun.com.cn/javafx/1/tutorials/core/index.html"&gt;http://developers.sun.com.cn/javafx/1/tutorials/core/index.html&lt;/a&gt;&lt;/li&gt; &lt;li&gt;使用 JavaFX 构建 GUI
      教程&lt;br /&gt; &lt;a href="http://developers.sun.com.cn/javafx/1/tutorials/ui/index.html"&gt;http://developers.sun.com.cn/javafx/1/tutorials/ui/index.html&lt;/a&gt;&lt;/li&gt; &lt;li&gt;JavaFX with NetBeans 6.5&lt;br /&gt; &lt;a href="http://download.developers.sun.com.cn/javafx/netbeans-6.5-javafx-windows.exe"&gt;http://download.developers.sun.com.cn/javafx/netbeans-6.5-javafx-windows.exe&lt;/a&gt;&lt;/li&gt; &lt;li&gt;JavaFX SDK v1.0&lt;br /&gt; &lt;a
      href="http://download.developers.sun.com.cn/javafx/javafx_sdk-1_0-windows-i586.exe"&gt;http://download.developers.sun.com.cn/javafx/javafx_sdk-1_0-windows-i586.exe&lt;/a&gt;&lt;/li&gt; &lt;li&gt;JavaFX Production Suite&lt;br /&gt; &lt;a href="http://download.developers.sun.com.cn/javafx/javafx_production_suite-1_0-windows-i586.exe"&gt;http://download.developers.sun.com.cn/javafx/javafx_production_suite-1_0-windows-i586.exe&lt;/a&gt;&lt;/li&gt; &lt;li&gt;JDK 1.6.0 Update 11&lt;br /&gt; &lt;a
      href="http://developers.sun.com.cn/download/java_se.html"&gt;http://developers.sun.com.cn/download/java_se.html&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt; &lt;p&gt; &lt;/p&gt;</description>
      <pubDate>Mon, 22 Dec 2008 22:10:01 +0000</pubDate>
    </item>
    <item>
      <title>平步星云: Mark Occurrences in NetBeans</title>
      <guid isPermaLink="false">tag:blogger.com,1999:blog-171648533238476397.post-5767573093968662859</guid>
      <link>http://pprun.blogspot.com/2007/03/mark-occurrences-in-netbeans.html</link>
      <description>Mark Occurrences (元素高亮)指的是当鼠标放在某个类元素上时，在当前文件高亮出该元素的 声明和引用。&lt;br /&gt;如果你使用过 Find Usages 的话，你应该能知道这个功能的好处。但是 Mark Occurrences 比起 Find Usages 来属于轻量级的。因为：&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Mark Occurrences 只搜索当前文件&lt;/li&gt;&lt;li&gt;Mark Occurrences 为动态的，不需要菜单来激活只需要将鼠标放在要查看的元素上即可。&lt;/li&gt;&lt;li&gt;Mark Occurrences 懂得语义，比如将鼠标指向当前类的超类，它将显示所有被实现/覆盖的方法；放在方法的返回类型上，将显示方法的所有返回的语句上；...&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;如果你使用的是 NetBeans 6.0 的开发版的话，这个功能已经内置了，不过它被叫做 Highlights：&lt;br /&gt; &lt;span
      style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;ul&gt;&lt;li&gt;成员作用域&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;a href="http://wiki.netbeans.org/wiki/attach/Java_EditorUsersGuide/HL_Identifier.png"&gt;&lt;img src="http://wiki.netbeans.org/wiki/attach/Java_EditorUsersGuide/HL_Identifier.png" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px;" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;方法返回点&lt;/li&gt;&lt;/ul&gt;&lt;a
      href="http://wiki.netbeans.org/wiki/attach/Java_EditorUsersGuide/HL_ExitPoints.png"&gt;&lt;img src="http://wiki.netbeans.org/wiki/attach/Java_EditorUsersGuide/HL_ExitPoints.png" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px;" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;特定异常抛出点&lt;/li&gt;&lt;/ul&gt;&lt;a href="http://wiki.netbeans.org/wiki/attach/Java_EditorUsersGuide/HL_ExceptionPoints.png"&gt;&lt;img
      src="http://wiki.netbeans.org/wiki/attach/Java_EditorUsersGuide/HL_ExceptionPoints.png" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px;" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;如果你使用的是 NetBeans 5.x 系列的话，你需要注册一个更新中心，然后下载插件，具体步骤如下：&lt;br /&gt;&lt;ol&gt;&lt;li&gt;选择 &lt;span style="font-weight: bold;"&gt;Tools | Options&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;单击 &lt;span style="font-weight: bold;"&gt;Advanced
      Options &lt;/span&gt;按钮&lt;/li&gt;&lt;li&gt;选择&lt;span style="font-weight: bold;"&gt; Options | IDE Configuration | System | Autoupdate Types&lt;/span&gt;&lt;/li&gt;&lt;li&gt;右击并选择 &lt;span style="font-weight: bold;"&gt;New | General Update Center&lt;/span&gt;&lt;/li&gt;&lt;li&gt;在 &lt;span style="font-weight: bold;"&gt;Name &lt;/span&gt;输入域中输入&lt;span style="font-weight: bold;"&gt;Sandip Chitale's Modules &lt;/span&gt;然后单击 &lt;span style="font-weight:
      bold;"&gt;Finish&lt;/span&gt;&lt;/li&gt;&lt;li&gt;(此步骤不必，如果你在完成上述步骤后立即进行下面的步骤时) 展开&lt;span style="font-weight: bold;"&gt;Autoupdate Types node&lt;/span&gt;, 选择 &lt;span style="font-weight: bold;"&gt;Sandip Chitale's Modules&lt;/span&gt;&lt;/li&gt;&lt;li&gt;在右边的窗口中的第一个属性值Server URL，输入: http://blogs.sun.com/roller/resources/scblog/update-center.xml&lt;/li&gt;&lt;li&gt;确保&lt;span style="font-weight: bold;"&gt;Enabled&lt;/span&gt; 属性勾上。然后关闭当前窗口&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br
      /&gt;现在这个更新中心就可以用了，我们目标是得到 Mark Occurrences 插件，它就在这个更新中心中：&lt;br /&gt;选择&lt;span style="font-weight: bold;"&gt;Tools | Update Center &lt;/span&gt;菜单. 勾上 &lt;span style="font-weight: bold;"&gt;Sandip Chitale's Modules&lt;/span&gt; 项，如果它还没被勾上的话。依照更新向导在 Select Modules to Install 窗口中选择&lt;br /&gt;Sandip Chitale's Modules 选择Make Occurrences&lt;br /&gt;&lt;br /&gt;&lt;b&gt;虽然作者声明：&lt;/b&gt;这个模块是个实验性的模块，但是到目前为止在我的工作中我一直在用它，而且没有出现任何问题(比起一些 Eclipse 的插件可强多了!)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span
      style="font-weight: bold;"&gt;注意: &lt;/span&gt;安装完后(不记得要不要重启 NetBeans), 你应该能看到工具条上出现一个黄色的按钮(如下图)，或者你可以从 &lt;span style="font-weight: bold;"&gt;View | Mark Occurrences&lt;/span&gt; 激活它：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_bpUunzIgcNA/RkU4QqKBVvI/AAAAAAAAAAk/Hcjh5jdB9BA/s1600-h/Mark+Occurrences.png"&gt;&lt;img src="http://3.bp.blogspot.com/_bpUunzIgcNA/RkU4QqKBVvI/AAAAAAAAAAk/Hcjh5jdB9BA/s400/Mark+Occurrences.png" alt="" style="margin: 0px auto 10px; display: block;
      text-align: center; cursor: pointer; width: 400px;" border="0" id="BLOGGER_PHOTO_ID_5063515214893373170" /&gt;&lt;/a&gt;</description>
      <pubDate>Wed, 10 Dec 2008 17:08:14 +0000</pubDate>
    </item>
    <item>
      <title>平步星云: Hibernate Jpetstore 之四 表示层技术</title>
      <guid isPermaLink="false">tag:blogger.com,1999:blog-171648533238476397.post-4840119221115522578</guid>
      <link>http://pprun.blogspot.com/2007/06/hibernate-jpetstore.html</link>
      <description>&lt;h2&gt;文档内容&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;概览&lt;/li&gt;&lt;li&gt;Struts 表示层组件 FormBean&lt;/li&gt;&lt;ul&gt;&lt;li&gt;FormBean 配置&lt;/li&gt;&lt;li&gt;FormBean 类层次&lt;/li&gt;&lt;li&gt;BaseActionForm 子类实例 AccountActionForm&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;避免重复提交&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Struts 的事务 Token&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;我们还缺什么?&lt;/li&gt;&lt;ul&gt;&lt;li&gt;客户端校验&lt;/li&gt;&lt;li&gt;漂亮的页面&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;总结&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;a
      href="http://2.bp.blogspot.com/_bpUunzIgcNA/RnKM9o3zgfI/AAAAAAAAAEU/jsleco4RgaY/s1600-h/index.png"&gt;&lt;img src="http://2.bp.blogspot.com/_bpUunzIgcNA/RnKM9o3zgfI/AAAAAAAAAEU/jsleco4RgaY/s400/index.png" alt="" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" border="0" id="BLOGGER_PHOTO_ID_5076274720571359730" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;在阅读本篇文章之前，请先仔细阅读前面系列的相关内容。&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;概览&lt;/h2&gt;&lt;br /&gt;在各种框架欣欣向荣的今天，你能想象最初 Java WEB
      开发者的日子吗？要知道，就算是JSP，当时都被寄予厚望，因为当时，开发者不得不在Servlet 中书写之如：out.println("&amp;lt;html&gt;&amp;lt;head&gt;&amp;lt;title&gt;My God&amp;lt;/title&gt;&amp;lt;/head&gt;&amp;lt;body&gt;");&lt;br /&gt;&lt;br /&gt;你能想象，以这种方式做一个象样的页面是怎样的一种情形。这种情况下，是将“表示层”的内容(HTML标记)渗透进Java代码中了，你哪怕是修改页面上的一个文字，你都不得不在上述的 println 中修改 -&gt; 编译 -&gt; 测试-&gt; ...&lt;br /&gt;&lt;br /&gt;于是，JSP应运而生，可是很快，开发者发现，情况反过来了：在JSP页面代码中到处散布有之如：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:
      monospace;"&gt;&amp;lt;%&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;String amount =&lt;br /&gt;request.getParameter("amount");&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; if&lt;br /&gt;( amount != null &amp;amp;&amp;amp;&lt;br /&gt;amount.length() &gt; 0 ) {&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;%&gt;&lt;/span&gt;&lt;br
      /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;也就是说，此时表示逻辑的代码渗透进页面代码中了。&lt;br /&gt;&lt;br /&gt;于是才有后来的 JavaBeans, &amp;lt;jsp:useBean&gt;, Taglibs 等，以及术语 WEB MVC, MVC2 等。&lt;br /&gt;&lt;br /&gt;毫无疑问，对于在JAVA Web 领域工作多年的老手，看到我这篇关于 Struts 的文章肯定会觉得好土，或者甚至老掉牙了! 的确，这也是我这段时间一直在考虑是否需要写这样一个系列的原因。&lt;br /&gt;&lt;br /&gt;不管现在 JSF. WebWorks/Struts2, SpringMVC , JBoss Seam 被如何鼓吹，Struts 作为 Web&lt;br /&gt;框架的先行者，还是有它的位置。尽管此例子中所采用的方法比起最新的 Struts (Struts 1.3.x 系列)也同样显得有些陈旧，但是正如 JAVA
      领域中的一惯作法，“在引入新功能前先考虑向后兼容”，因此，新的功能尽管加入吧，你可以欣喜若狂，但我也同样可以一直运行已经稳定运行好几年的产品。&lt;br /&gt;&lt;br /&gt;随便提一下，本人并不认为上述新的WEB框架使开发工作简化了多少，相反，倒是增加了不少复杂性。作为新手，很难保证在研究这些框架一周后能开发出一个稳&lt;br /&gt;定可靠的方案。相反象几个简单的框架反而在引入面向 Page 的设计方法的同时，简化了开发的难度：&lt;a href="http://wicket.sourceforge.net/"&gt;Wicket&lt;/a&gt; &lt;a href="http://click.sourceforge.net/"&gt;Click&lt;/a&gt; ，而且更加符合当今的 Web2 的需求。&lt;br /&gt;&lt;br /&gt;再有，由于 JSTL 的流行，几乎所有的 Web 框架都依靠它来排除JSP脚本。但是我们不会在这里介绍每个 JSTL 标记的用法，具体的用法见工程的JSP 源代码。&lt;br /&gt;&lt;br
      /&gt;好了，一来就说了这么多，无非是为了引入主角 Struts，但是请原谅，关于整个Struts&lt;br /&gt;的介绍是需要一整书才能介绍完的。所以我们还是以代码为依托，一步步来吧。&lt;br /&gt;我们的主题是表示层的相关技术。&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Struts 表示层组件 FormBean&lt;/h2&gt;&lt;h3&gt;FormBean 配置&lt;/h3&gt;&lt;br /&gt;FormBean 即是我们熟悉的 JSP + JavaBean 设置方式中的 JavaBean，只不过它作为 Struts 框架的组件担任起页面表单与 Struts Action的信息传递的使者。&lt;br /&gt;&lt;br /&gt;为了弄清 FormBean 的工作原理，我们现在给出我们整个的 struts-config.xml 文件的内容&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;lt;?xml
      version="1.0"&lt;br /&gt;encoding="GBK"?&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;lt;!DOCTYPE struts-config PUBLIC&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;"-//Apache Software&lt;br /&gt;Foundation//DTD Struts Configuration 1.1//EN"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;"http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:
      monospace;"&gt;&amp;lt;struts-config&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;!-- 配置此应用中的所有 FormBean&lt;br /&gt;--&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;form-beans&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(51, 204, 0);"&gt;&amp;lt;!-- 这种复用&lt;br /&gt;FormBean 的方式值得讨论，见紧随其后的说明 1 --&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;&amp;lt;!--&lt;br
      /&gt;与注册帐户和帐户信息相关的页面使用的 FormBean --&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;form-bean name="accountForm"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.AccountActionForm"/&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;&amp;lt;!--&lt;br /&gt;与购物车相关的页面使用的 FormBean --&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;form-bean
      name="cartForm"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.CartActionForm"/&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: monospace;"&gt;&lt;span style="color: rgb(51, 204, 0);"&gt; &amp;lt;!-- 没有对应的页面元素的&lt;br /&gt;FormBean, 例如点击一个链接或按下搜索按钮等等功能，被设计成不需要 FormBean 来收集用户输入 --&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;form-bean&lt;br /&gt;name="emptyForm"&lt;br
      /&gt;type="org.springframework.samples.jpetstore.web.struts.BaseActionForm"/&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: monospace;"&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;&amp;lt;!-- 与帐户修改相关的页面使用的&lt;br /&gt;FormBean，因为此时也许在当前的 session 已经存在了一个 accountForm --&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;form-bean&lt;br /&gt;name="workingAccountForm"&lt;br
      /&gt;type="org.springframework.samples.jpetstore.web.struts.AccountActionForm"/&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: monospace;"&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;&amp;lt;!-- 与所有定单操作相关的页面使用的 FormBean --&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;form-bean&lt;br /&gt;name="workingOrderForm"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.OrderActionForm"/&gt;&lt;/span&gt;&lt;br
      /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;/form-beans&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;&amp;lt;!-- 全局跳转声明，这此跳转可以被所有的&lt;br /&gt;Action 中共享 --&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;global-forwards&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;forward&lt;br /&gt;name="failure"
      path="/WEB-INF/jsp/struts/Error.jsp"&lt;br /&gt;redirect="false"/&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;forward&lt;br /&gt;name="unknown-error" path="/WEB-INF/jsp/struts/Error.jsp"/&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;forward&lt;br /&gt;name="global-signon" path="/WEB-INF/jsp/struts/SignonForm.jsp"/&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;
      &amp;lt;/global-forwards&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;&amp;lt;!-- 以下为所有的 Action 映射&lt;br /&gt;--&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;action-mappings&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;&amp;lt;!--&lt;br /&gt;点击链接将一只宠物加入购物车 --&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:
      monospace;"&gt;&lt;br /&gt;&amp;lt;action path="/shop/addItemToCart"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.AddItemToCartAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;name="cartForm" scope="session" validate="false"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success" path="/WEB-INF/jsp/struts/Cart.jsp"/&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:
      monospace;"&gt; &amp;lt;/action&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;&amp;lt;!-- 结算购物车&lt;br /&gt;--&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;action path="/shop/checkout"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.ViewCartAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;name="cartForm" scope="session" validate="false"&gt;&lt;/span&gt;&lt;br
      /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success" path="/WEB-INF/jsp/struts/Checkout.jsp"/&gt;&lt;/span&gt;&amp;lt;/action&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;&amp;lt;!--&lt;br /&gt;修改帐号信息 --&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;action path="/shop/editAccount"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.EditAccountAction"&lt;br /&gt;&lt;br /&gt;name="workingAccountForm" scope="session"
      validate="true"&lt;br /&gt;input="/WEB-INF/jsp/struts/EditAccountForm.jsp"&gt;&lt;br /&gt;&amp;lt;forward name="success" path="/shop/index.do"/&gt;&lt;br /&gt;&amp;lt;/action&gt;&lt;br /&gt;&amp;lt;action&lt;br /&gt;path="/shop/editAccountForm"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.EditAccountFormAction"&lt;br /&gt;name="workingAccountForm" scope="session"&lt;br /&gt;validate="false"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;forward
      name="success"&lt;br /&gt;path="/WEB-INF/jsp/struts/EditAccountForm.jsp"/&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;/action&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;action&lt;br /&gt;path="/shop/index"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.DoNothingAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;validate="false"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span
      style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success" path="/WEB-INF/jsp/struts/index.jsp"/&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;/action&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;action&lt;br /&gt;path="/shop/help"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.DoNothingAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br
      /&gt;validate="false"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success" path="/WEB-INF/jsp/struts/help.jsp"/&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;/action&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;action&lt;br /&gt;path="/shop/listOrders"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.ListOrdersAction"&lt;/span&gt;&lt;br /&gt;&lt;span
      style="font-family: monospace;"&gt;&lt;br /&gt;name="accountForm" scope="session" validate="false"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success"&lt;br /&gt;path="/WEB-INF/jsp/struts/ListOrders.jsp"/&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;/action&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;action&lt;br /&gt;path="/shop/newAccount"&lt;br
      /&gt;type="org.springframework.samples.jpetstore.web.struts.NewAccountAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;name="workingAccountForm" scope="session" validate="true"&lt;br /&gt;input="/WEB-INF/jsp/struts/NewAccountForm.jsp"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success" path="/shop/index.do"/&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;
      &amp;lt;/action&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;action&lt;br /&gt;path="/shop/newAccountForm"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.NewAccountFormAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;name="workingAccountForm" scope="session" validate="false"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success"&lt;br
      /&gt;path="/WEB-INF/jsp/struts/NewAccountForm.jsp"/&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;/action&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;&amp;lt;!--&lt;br /&gt;进入结算中心页面后，点击继续进入此 --&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;action path="/shop/newOrderForm"&lt;br
      /&gt;type="org.springframework.samples.jpetstore.web.struts.NewOrderFormAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;name="workingOrderForm" scope="session" validate="false"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success"&lt;br /&gt;path="/WEB-INF/jsp/struts/NewOrderForm.jsp"/&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;/action&gt;&lt;br /&gt;&lt;br
      /&gt;&lt;/span&gt;&lt;span style="font-family: monospace;"&gt; &lt;span style="font-weight: bold; color: rgb(51, 204, 0);"&gt;&amp;lt;!-- &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;fixed by pprun: 将原先混在一起的逻辑打破成几个小部分，否则在多步向导式提交&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;页面中的任何一步出错都无理地返回到 NewOrderForm.jsp
      页面，而不是真正的出错的页面&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;--&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;!--&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;action&lt;br /&gt;path="/shop/newOrder"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.NewOrderAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br
      /&gt;name="workingOrderForm" scope="session" validate="true"&lt;br /&gt;input="/WEB-INF/jsp/struts/NewOrderForm.jsp"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="confirm"&lt;br /&gt;path="/WEB-INF/jsp/struts/ConfirmOrder.jsp"/&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="shipping"&lt;br /&gt;path="/WEB-INF/jsp/struts/ShippingForm.jsp"/&gt;&lt;/span&gt;&lt;br /&gt;&lt;span
      style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success" path="/WEB-INF/jsp/struts/ViewOrder.jsp"/&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;/action&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; --&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-weight: bold;"&gt;&amp;lt;!--&lt;br /&gt;填写定单信息的多页向导式页面 --&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204,
      0);"&gt;&amp;lt;!--&lt;br /&gt;当第一页校验失败时，需要跳回填写购物单的第一页 --&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;action path="/shop/newOrderStep1"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.NewOrderAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;name="workingOrderForm" scope="session" validate="true"&lt;br /&gt;input="/shop/newOrderForm.do"&gt;&lt;/span&gt;&lt;br
      /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="confirm"&lt;br /&gt;path="/WEB-INF/jsp/struts/ConfirmOrder.jsp"/&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="shipping"&lt;br /&gt;path="/WEB-INF/jsp/struts/ShippingForm.jsp"/&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;/action&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0); font-family:
      monospace;"&gt;&amp;lt;!--&lt;br /&gt;&lt;span&gt;(只有页面上填写了将宠物送到不同的地址时，默认为送到当前用户的地址)，&lt;/span&gt;&lt;br /&gt;&lt;span&gt;才会出现此面。此页校验失败，毫无疑问应该回到这个新地址填写页，&lt;/span&gt;&lt;br /&gt;&lt;span&gt;而不是整个流程的第一页。这就是原版中的BUG所在处，因为它将这个向导性的流程&lt;/span&gt;&lt;br /&gt;&lt;span&gt;处理放到了一个映射中，所以没法处理这种情况 --&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;action&lt;br /&gt;path="/shop/newOrderStep2"&lt;br
      /&gt;type="org.springframework.samples.jpetstore.web.struts.NewOrderAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;name="workingOrderForm" scope="session" validate="true"&lt;br /&gt;input="/WEB-INF/jsp/struts/ShippingForm.jsp"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="confirm"&lt;br /&gt;path="/WEB-INF/jsp/struts/ConfirmOrder.jsp"/&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:
      monospace;"&gt; &amp;lt;/action&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&amp;lt;!--&lt;br /&gt;当在最后一步确认时出错，需要跳回填写购物单的第一页 --&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;action&lt;br /&gt;path="/shop/newOrderStep3"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.NewOrderAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;name="workingOrderForm"
      scope="session" validate="true"&lt;br /&gt;input="/WEB-INF/jsp/struts/NewOrderForm.jsp"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success" path="/WEB-INF/jsp/struts/ViewOrder.jsp"/&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;/action&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;!-- fixed&lt;br /&gt;end --&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:
      monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: monospace;"&gt;&lt;/span&gt;&lt;span style="font-family: monospace;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;action&lt;br /&gt;path="/shop/removeItemFromCart"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.RemoveItemFromCartAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;name="cartForm" scope="session"
      validate="false"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success" path="/WEB-INF/jsp/struts/Cart.jsp"/&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;/action&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;action&lt;br /&gt;path="/shop/searchProducts"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.SearchProductsAction"&lt;/span&gt;&lt;br /&gt;&lt;span
      style="font-family: monospace;"&gt;&lt;br /&gt;name="emptyForm" scope="session" validate="false"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success"&lt;br /&gt;path="/WEB-INF/jsp/struts/SearchProducts.jsp"/&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;/action&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;action&lt;br /&gt;path="/shop/signon"&lt;br
      /&gt;type="org.springframework.samples.jpetstore.web.struts.SignonAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;name="accountForm" scope="session" validate="false"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success" path="/shop/index.do"/&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;/action&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;
      &amp;lt;action&lt;br /&gt;path="/shop/signonForm"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.DoNothingAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;validate="false"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success"&lt;br /&gt;path="/WEB-INF/jsp/struts/SignonForm.jsp"/&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;
      &amp;lt;/action&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;action&lt;br /&gt;path="/shop/updateCartQuantities"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.UpdateCartQuantitiesAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;name="cartForm" scope="session" validate="false"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success"
      path="/WEB-INF/jsp/struts/Cart.jsp"/&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;/action&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;action&lt;br /&gt;path="/shop/viewCart"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.ViewCartAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;name="cartForm" scope="session" validate="false"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span
      style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success" path="/WEB-INF/jsp/struts/Cart.jsp"/&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;/action&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;action&lt;br /&gt;path="/shop/viewCategory"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.ViewCategoryAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br
      /&gt;name="emptyForm" scope="session" validate="true"&lt;br /&gt;input="/WEB-INF/jsp/struts/index.jsp"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success" path="/WEB-INF/jsp/struts/Category.jsp"/&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;/action&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;action&lt;br /&gt;path="/shop/viewItem"&lt;br
      /&gt;type="org.springframework.samples.jpetstore.web.struts.ViewItemAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;name="emptyForm" scope="session" validate="true"&lt;br /&gt;input="/WEB-INF/jsp/struts/Product.jsp"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success" path="/WEB-INF/jsp/struts/Item.jsp"/&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;
      &amp;lt;/action&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;action&lt;br /&gt;path="/shop/viewOrder"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.ViewOrderAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;name="accountForm" scope="session" validate="false"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success"
      path="/WEB-INF/jsp/struts/ViewOrder.jsp"/&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;/action&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;action&lt;br /&gt;path="/shop/viewProduct"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.ViewProductAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;name="emptyForm" scope="session" validate="true"&lt;br
      /&gt;input="/WEB-INF/jsp/struts/index.jsp"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success" path="/WEB-INF/jsp/struts/Product.jsp"/&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;/action&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;/action-mappings&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span
      style="font-family: monospace;"&gt;&amp;lt;/struts-config&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;说明：&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;1. 从FormBean 的数量和每个使用了FormBean的 Action 映射可知，这里存在 FormBean&lt;br /&gt;复用问题，即用一个来服务多个 Action, 这种方式可以大大减少 FormBean 的数量，&lt;br /&gt;但是，在 Action中的逻辑变得复杂了。因为在 FormBean 中包括了所有 Action 的需求，&lt;br /&gt;而在Action中不得不排除它所不需要的元素的干扰。这样使代码看起来很混乱。&lt;br /&gt;&lt;br /&gt;2. 有了全局声明，在 Action 的代码中就可以随时发出
      mapping.findForward("failure");&lt;br /&gt;之类的代码，而不需要在对应的 Action 映射中配置该 &amp;lt;forward&gt; 子元素.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3. 注释掉的 Action 映射是为了修复一个BUG：&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: monospace;"&gt;&lt;/span&gt;&lt;br /&gt;因为在涉及到定单提交时，采用的是多页提交(也就向导页面)方式，即收集的信息是从连续多个&lt;br /&gt;页面中获得的，而不是普通的从一个页面中得到的。这样就涉及到，当其中的一个页面出现校验&lt;br /&gt;失败时，将要将流控跳转到出错的页面，通过将原先混在一起的逻辑打破成几个小部分，&lt;br /&gt;否则在多步向导式提交页面中的任何一步出错都无理地返回到 NewOrderForm.jsp
      页面，&lt;br /&gt;而不是真正的出错的页面,请看相应的映射元素的注释说明。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;4. 为了保持连贯性，关于每个映射元素的每个属性，我们重复 &lt;a href="http://pprun.blogspot.com/2007/05/hibernate-jpetstore_31.html"&gt;Hibernate&lt;br /&gt;JPetstore 系列之三: 控制层技术&lt;/a&gt; 中的 ActionForm &amp;lt;-- struts-config.xml --&gt;Action 部分的内容：&lt;br /&gt;&lt;br /&gt;1. path=&lt;span style="font-weight: bold;"&gt;/shop/editAccount&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;所有要去住 /shop/editAccount （严格地讲，如果按照Struts 的方言是 /shop/editAccount.do)&lt;br
      /&gt;的请求，都要遵循这里的配置&lt;br /&gt;&lt;br /&gt;2. &lt;span style="font-weight: bold;"&gt;name="workingAccountForm"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;都将绑定 workingAccountForm ，注意 form-bean 在 Action 中引用是通过 name&lt;br /&gt;属性来引用的，它是在一开始定义的: &amp;lt;form-bean name="workingAccountForm"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.AccountActionForm"/&gt;&lt;br /&gt;&lt;br /&gt;3. &lt;span style="font-weight: bold;"&gt;scope="session"&lt;/span&gt; 该 bean&lt;br /&gt;&lt;br /&gt;将在整个会话其间始终有效
      ，但注意这个配置是多余的，默认就是 session 上下文的，反而如果 bean 只在&lt;br /&gt;request上下文时，才需要明确地声明。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;4. validate="true" 将对表单的输入调用 form-bean 的 validate 方法。但我们发现在&lt;br /&gt;AccountActionForm.java 中，只有 doValidate(...) 方法，并没有 validate()方法，&lt;br /&gt;但细心的话，应该发现了，和所有的Action 都是从BaseAction 中派生而来一样，&lt;br /&gt;所有的ActionForm 中都是从一个基类 BaseActionForm.java 中派生下来。&lt;br /&gt;&lt;br /&gt;其中定义了所有 formbean都需要的东西，对于校验错误的处理。&lt;br /&gt;&lt;br /&gt;其中就是 validate(...) 方法，并在其中调用了 doValidate() 方法，&lt;br
      /&gt;&lt;br /&gt;而每个BaseActionForm 的子类只要override 这个doValidate() 方法，&lt;br /&gt;&lt;br /&gt;如果 validate="true"声明了的话，那么子类中的 doValidate() 方法将会被调用。这是多态性的表现。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;5. input="..." 一般来讲，一个表单在校验失败后都需要回去重纠正错误的输出项，&lt;br /&gt;所以我们通过这个值来告诉 Struts该回到哪去纠错.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;FormBean 类层次&lt;/h3&gt;&lt;br /&gt;与 Action 类一样，FormBean 也基于类的继承关系设计的，这样子类 FormBean&lt;br /&gt;只需实现父类 FormBean指定的约束，所有的子类都复用父类中的功能并按照这种设计约束工作。&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;基类
      BaseActionForm&lt;/h4&gt;该类本身又是从 抽象类 org.apache.struts.action.ActionForm 派生而来，&lt;br /&gt;所以应用中的所有 FormBean只要从 BaseActionForm 派生即可：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;public class BaseActionForm&lt;br /&gt;extends ActionForm {&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt; /**&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt; *此乃最原始的错误处理方法，将所有错误信息加入到一个列表后，然后存入到&lt;/span&gt;&lt;br /&gt;&lt;span style="color:
      rgb(51, 204, 0);"&gt; *Servlet 请求属性中供页面使用.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt; *更现代的方法是使用 Struts1.1 之后的 commons-validator,关于这个功能在&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt; * 各种关于Struts 的参考或书籍中都有介绍。&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt; *&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt; *是否为调用此方法是通过属性 &lt;span style="color: rgb(102, 0, 204);"&gt;&lt;span style="color: rgb(255, 0,
      0);"&gt;validate&lt;/span&gt; &lt;/span&gt;来控制的，如：&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt; *&amp;lt;action path="/shop/signon"type="org.springframework.samples.jpetstore.web.struts.SignonAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt; *name="accountForm" scope="session" &lt;span style="color: rgb(255, 0, 0);"&gt;validate="false"&lt;/span&gt;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt; *是不会调用的，因为
      validate="false".&lt;br /&gt;　　　&lt;br /&gt; * 这是“模板方法”（Template method) 设计模式中的“方法”&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);"&gt; */&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;public ActionErrors validate(ActionMapping mapping,&lt;br /&gt;HttpServletRequest request) {&lt;br /&gt;ActionErrors errorMessages =&lt;br /&gt;null;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;// 整个系统的错误信息列表，通过调用doValidate(mapping, request,
      errorList);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;&lt;br /&gt;// addErrorIfStringEmpty 会将错误信息加入到列表当中，并且它被存入了请求属性当中.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;ArrayList errorList = new&lt;br /&gt;ArrayList();&lt;br /&gt;&lt;br /&gt;doValidate(mapping, request,&lt;br /&gt;errorList);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;request.setAttribute("errors", errorList);&lt;br /&gt;&lt;br /&gt;if (!errorList.isEmpty()) {&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;errorMessages = new
      org.apache.struts.action.ActionErrors();&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;errorMessages.add(ActionErrors.GLOBAL_MESSAGE, new&lt;br /&gt;ActionMessage("global.error"));&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;return errorMessages;&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;/**&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt; *此方法被设计为供子类覆盖的(overriding).&lt;/span&gt;&lt;br /&gt;&lt;span style="color:
      rgb(51, 204, 0);"&gt; *任何子类实现了这个方法，将自动被上面的 validate 方法调用。&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt; *&lt;br /&gt; * 这是“模板方法"模式中的默认钓子方法，由子类的实现方法来替换。&lt;br /&gt; *&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);"&gt; * @param mapping&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt; * @param request&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt; * @param&lt;br /&gt;errors&lt;/span&gt;&lt;br /&gt;&lt;span style="color:
      rgb(51, 204, 0);"&gt; */&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;public void doValidate(ActionMapping mapping,&lt;br /&gt;HttpServletRequest request, List errors) {&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;/**&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt; *此辅助方法被用来给定的页面输入内容是否为空，如果是空的话，将显示给定的出错信息。&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt; *&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51,
      204, 0);"&gt; * @param errors 错误信息列表&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt; * @param message 当 value 为空时，将显示这个错误信息&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt; * @param value 页面元素对应的值&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt; */&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;protected void addErrorIfStringEmpty(List errors,&lt;br /&gt;String message, String value) {&lt;br /&gt;&lt;br /&gt;if (value == null ||&lt;br
      /&gt;value.trim().length() &amp;lt; 1) {&lt;br /&gt;&lt;br /&gt;errors.add(message);&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;}&lt;/span&gt;&lt;span style="font-family: monospace;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;BaseActionForm 子类实例 AccountActionForm&lt;/h4&gt;&lt;br /&gt;我仅介绍一个子类 &lt;span style="font-family: monospace;"&gt;AccountActionForm :&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span
      style="font-family: monospace;"&gt;public class AccountActionForm&lt;br /&gt;extends BaseActionForm {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;span style="color: rgb(51, 204, 0);"&gt;/** 用于检验的常量定义，因为在新建帐户与修改帐户时检验逻辑是不一样的。&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;* 至少在修改帐户时，帐户名是已经存在了 */&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:
      monospace;"&gt; public static final String VALIDATE_EDIT_ACCOUNT = "editAccount";&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; public static final String VALIDATE_NEW_ACCOUNT = "newAccount";&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;span style="color: rgb(51, 204, 0);"&gt;/** 用于存贮用户的首先语言的列表 */&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;
      private static final ArrayList LANGUAGE_LIST = new ArrayList();&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;span style="color: rgb(51, 204, 0);"&gt;/* Private Fields */&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;// 看起来好象与 Account 中的成员重复了，这是因为此 Form 被多个页面重复使用的&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0); font-family:
      monospace;"&gt;&lt;br /&gt;// 结果，因为在登录页面时，那时根本不存在 Account, 所以不可能通过&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;// account.getUsername() 和 account.getPassword() 来得到用户的输入值的，&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;// 下面两项即是在登录当时收集输入 信息，&lt;/span&gt; &lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;// 其它情况（比如修改，新建帐户时）都是间接使用了 Account
      中的成员，因当时都&lt;/span&gt; &lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;// 已经在 session 中存放了一个 Account 的实例&lt;/span&gt; &lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;// 所以重用是有代价的（使代码不那么直观了，如果是一个页面表单 Form 对应一个&lt;/span&gt; &lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;// FormBean 的话，以下成员与页面中的输入元素是一一对应的）&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;
      &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;// 供登录页面使用的 元素&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; private String username;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; private String password;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;span style="color: rgb(51, 204, 0);"&gt;//
      登录后，与帐户相关的元素&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; private String repeatedPassword;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; private List languages;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; private List categories;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;/span&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204,
      0);"&gt;/**&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;* 这个成员的值是通过页面隐藏元素传入的：&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;* &lt;span style="color: rgb(51, 51, 255);"&gt;NewAccountForm.jsp 中: &amp;lt;html:hidden name="workingAccountForm" property="validate"&lt;br /&gt;value="newAccount"/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255); font-family:
      monospace;"&gt;* EditAccountForm.jsp 中:&amp;lt;html:hidden name="workingAccountForm" property="validate" value="editAccount" /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;*/&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; private String validate;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;span style="color: rgb(51, 204,
      0);"&gt;/**&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;* 用来记住用户是从哪里跳转过来的，因为准备对购物车进行结算时，如果没有登录&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;* 的话，首先将结算中心页面的地址存入此成员中，登录成功后再跳转过去。&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;* 如果没有这样一步操作的话，那么就会出现讨厌的将你送回首页面(也就是程序&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br
      /&gt;* 的逻辑流程打扰了用户的进程，&lt;span style="color: rgb(255, 0, 0);"&gt;这是最应当避免的&lt;/span&gt;。)&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;*/&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; private String forwardAction;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;/span&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;/**&lt;/span&gt;&lt;/span&gt;&lt;span
      style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;* 所有的帐号信息放在这个 POJO 中&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;*/&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; private Account account;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;/span&gt;&lt;span style="font-family: monospace;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;span style="color:
      rgb(51, 204, 0);"&gt;/**&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;* 用于显示标语，当你在用户信息页面选择显示标语时&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;*/&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; private String bannerName;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;span
      style="color: rgb(51, 204, 0);"&gt;/**&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;* 用于显示根据用户的喜好被推荐的宠物列表,当你选择了显示该列表时。&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;*/&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; private PagedListHolder myList;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:
      monospace;"&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;/**&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;* 用户最喜欢的宠物类别&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;*/&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; private String favCategoryName;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:
      monospace;"&gt; /* Static Initializer */&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; static {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;LANGUAGE_LIST.add("english");&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;LANGUAGE_LIST.add("japanese");&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; }&lt;/span&gt;&lt;br
      /&gt;&lt;span style="font-family: monospace;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; public AccountActionForm() {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;languages = LANGUAGE_LIST;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; public PagedListHolder getMyList()
      {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;return myList;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; public void setMyList(PagedListHolder myList) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;this.myList = myList;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; }&lt;/span&gt;&lt;br /&gt;&lt;span
      style="font-family: monospace;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; public String getForwardAction() {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;return forwardAction;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; public void setForwardAction(String forwardAction) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:
      monospace;"&gt;&lt;br /&gt;this.forwardAction = forwardAction;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; public String getUsername() {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;return username;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; }&lt;/span&gt;&lt;br /&gt;&lt;span
      style="font-family: monospace;"&gt; public void setUsername(String username) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;this.username = username;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; public String getPassword() {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br
      /&gt;return password;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; }&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: monospace;"&gt; public void setPassword(String password) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;this.password = password;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span
      style="font-family: monospace;"&gt; public String getRepeatedPassword() {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;return repeatedPassword;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; }&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: monospace;"&gt; public void setRepeatedPassword(String repeatedPassword) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;this.repeatedPassword =
      repeatedPassword;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; public Account getAccount() {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;return account;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;
      &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; public void setAccount(Account account) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;this.account = account;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; public List getLanguages() {&lt;/span&gt;&lt;br /&gt;&lt;span
      style="font-family: monospace;"&gt;&lt;br /&gt;return languages;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; public void setLanguages(List languages) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;this.languages = languages;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;
      &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; public List getCategories() {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;return categories;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; public void setCategories(List categories) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;this.categories =
      categories;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; public String getBannerName() {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;return bannerName;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;
      &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; public void setBannerName(String bannerName) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;this.bannerName = bannerName;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; public String getFavCategoryName() {&lt;/span&gt;&lt;br
      /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;return favCategoryName;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; public void setFavCategoryName(String favCategoryName) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;this.favCategoryName = favCategoryName;&lt;/span&gt;&lt;br /&gt;&lt;span
      style="font-family: monospace;"&gt; }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; public String getValidate() {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;return validate;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; }&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: monospace;"&gt; public void setValidate(String validate)
      {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;this.validate = validate;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;span style="color: rgb(51, 204, 0);"&gt;/**&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt; *
      覆盖父类中的方法”默认钓子“方法，用于特定于此子类的输入校验&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt; */&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; public void doValidate(ActionMapping mapping,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;HttpServletRequest request, List errors) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;if (validate != null) {&lt;/span&gt;&lt;br /&gt;&lt;span
      style="font-family: monospace;"&gt;&lt;br /&gt;if (VALIDATE_EDIT_ACCOUNT.equals(validate) ||&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;br /&gt;VALIDATE_NEW_ACCOUNT.equals(validate)) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;if (VALIDATE_NEW_ACCOUNT.equals(validate)) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt; //
      是新建帐户时，需要额外的校验&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;account.setStatus("OK");&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;br /&gt;addErrorIfStringEmpty(errors, "User ID is required.",&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;br /&gt;account.getUsername());&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span
      style="font-family: monospace;"&gt; &lt;br /&gt;if (account.getPassword() == null ||&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;br /&gt;account.getPassword().length() &amp;lt; 1 ||&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;br /&gt;!account.getPassword().equals(repeatedPassword)) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;br /&gt;errors.add("Passwords did not match or were not provided. " +&lt;/span&gt;&lt;br
      /&gt;&lt;span style="font-family: monospace;"&gt; &lt;br /&gt;"Matching passwords are required.");&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;if (account.getPassword() != null &amp;amp;&amp;amp;&lt;/span&gt;&lt;br
      /&gt;&lt;span style="font-family: monospace;"&gt; &lt;br /&gt;account.getPassword().length() &gt; 0) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;br /&gt;if (!account.getPassword().equals(repeatedPassword)) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;br /&gt;errors.add("Passwords did not match.");&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:
      monospace;"&gt;&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;addErrorIfStringEmpty(errors, "First name is required.",&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;br /&gt;this.account.getFirstname());&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;addErrorIfStringEmpty(errors, "Last name is
      required.",&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;br /&gt;this.account.getLastname());&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;addErrorIfStringEmpty(errors, "Email address is required.",&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;br /&gt;this.account.getEmail());&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;addErrorIfStringEmpty(errors, "Phone number is
      required.",&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;br /&gt;this.account.getPhone());&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;addErrorIfStringEmpty(errors, "Address (1) is required.",&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;br /&gt;this.account.getUserAddr().getAddr1());&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;addErrorIfStringEmpty(errors, "City is
      required.",&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;br /&gt;this.account.getUserAddr().getCity());&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;addErrorIfStringEmpty(errors, "State is required.",&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;br /&gt;this.account.getUserAddr().getState());&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;addErrorIfStringEmpty(errors, "ZIP is
      required.",&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;br /&gt;this.account.getUserAddr().getZipcode());&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;addErrorIfStringEmpty(errors, "Country is required.",&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;br /&gt;this.account.getUserAddr().getCountry());&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;}&lt;/span&gt;&lt;br
      /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;span style="color: rgb(51, 204, 0);"&gt;/**&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-family:
      monospace;"&gt;&lt;br /&gt;* 此方法是一个很重要的方法，我们看看基类中对该方法的描述:&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;*&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;* Reset bean properties to their default state, as needed.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;* This method is called before the properties are repopulated by the&lt;br
      /&gt;controller.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;* 在需要时，复位 Bean 的属性值，此方法是在控制器重新组装Bean的属性值之前调用的。&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;*&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;* The default implementation does nothing. In practice, the only&lt;br /&gt;properties&lt;/span&gt;&lt;br /&gt;&lt;span
      style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;* that need to be reset are those which represent checkboxes on a&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;* session-scoped form. Otherwise, properties can be given initial values&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;* where the field is declared.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51,
      204, 0); font-family: monospace;"&gt;&lt;br /&gt;* 默认的实现，并没有做任何事。实际上，唯一需要重置的属性是那些基于&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;* session 作用域的复选框页面元素。否则这些元素将使用页面上声明的默认值。&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;* 是勾选还是未勾选。&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;*&lt;/span&gt;&lt;br /&gt;&lt;span style="color:
      rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;* If the form is stored in session-scope so that values can be collected&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;* over multiple requests (a "wizard"), you must be very careful of&lt;br /&gt;which properties,&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;* if any, are reset. As mentioned, session-scope checkboxes must
      be&lt;br /&gt;reset to&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;* false for any page where this property is set. This is because the&lt;br /&gt;client&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;* does not submit a checkbox value when it is clear (false).&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;* If a session-scoped
      checkbox is not proactively reset, it can never&lt;br /&gt;be set to false.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;* 假如表单是存贮在 Session 作用域中(如：&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;* &lt;span style="color: rgb(102, 51, 255);"&gt;&amp;lt;action&lt;br /&gt;path="/shop/signon"&lt;br
      /&gt;type="org.springframework.samples.jpetstore.web.struts.SignonAction"&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(102, 51, 255); font-family: monospace;"&gt;&lt;br /&gt;* name="accountForm" &lt;span style="color: rgb(255, 0, 0);"&gt;scope="session"&lt;/span&gt;&lt;br /&gt;validate="false"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;* 即声明为 session 范围的 formBean)的话，表单元素的值可以在多个请求(即多页向导性页面)&lt;/span&gt;&lt;br
      /&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;* 中被收集，此时必须小心对等哪些输入域必须重置。象我们前面所述，session&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;* 作用域范围内的 checkbox(复选按钮)，在为它们设置值之前必须重置为 false，&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;* 因为客户端(即浏览器)在复选按钮未被勾选时并不会发送任何值到服务器端。(否则，&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-family:
      monospace;"&gt;&lt;br /&gt;* 就出现这样的问题：如果之前该复选按钮是勾选状态，并且用户请求这一页面&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;* 该按钮显示为勾选状态，在后续的操作中，用户取消选中状态。但是因为 checkbox&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;* 在取消选中状态后，浏览器并不发送任何关于这个控件的信息，但 ActionForm 中&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;*
      要改变控制的状态，必须比较浏览器传上来的状态和当前状态，但因为浏览器并未&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;* 告知它，所以 ActionForm 认为这个控件的状态并未改变。因为从这时开始，无论&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;* 用户怎么做，&lt;span style="color: rgb(255, 0, 0);"&gt;这个控件将永远保持为选中状态&lt;/span&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-family: monospace;"&gt;&lt;br /&gt;*/&lt;/span&gt;&lt;br
      /&gt;&lt;span style="font-family: monospace;"&gt; public void&lt;br /&gt;reset(ActionMapping mapping, HttpServletRequest request) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;super.reset(mapping, request);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;setUsername(null);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;setPassword(null);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:
      monospace;"&gt;&lt;br /&gt;setRepeatedPassword(null);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);"&gt;// BUG here: by pprun&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0); font-family: monospace;"&gt;&lt;br /&gt;// 按照此方法的 api 文档说明，说 checkbox 的值必须在此复位，&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);
      font-family: monospace;"&gt;&lt;br /&gt;//可是 NewAccountForm.jsp 中 Enable MyList 和 Enable MyBanner 却没有&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0); font-family: monospace;"&gt;&lt;br /&gt;// 所以当用户第一次选中后，以后想改为未选中是没门了，(除了象程序控制那样：&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0); font-family: monospace;"&gt;&lt;br /&gt;// 比如：&lt;br /&gt;acctForm.getAccount().setDisplayMylist(&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0); font-family: monospace;"&gt;&lt;br
      /&gt;//&lt;br /&gt;request.getParameter("account.displayMylist") != null);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0); font-family: monospace;"&gt;&lt;br /&gt;// acctForm.getAccount().setDisplayBanner(&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0); font-family: monospace;"&gt;&lt;br /&gt;//&lt;br /&gt;request.getParameter("account.displayBanner") != null);)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0); font-family: monospace;"&gt;&lt;br
      /&gt;//&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0); font-family: monospace;"&gt;&lt;br /&gt;// 但是当输入错误时重新显示当前页面时，上次选为未选中状态被丢失了！&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0); font-family: monospace;"&gt;&lt;br /&gt;//&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0); font-family: monospace;"&gt;&lt;br /&gt;// 因为按照 api 的说明&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0); font-family: monospace;"&gt;&lt;br /&gt;// 当 checkbox
      为未选中状态时，浏览器是不会发信息到服务器端的，所以&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0); font-family: monospace;"&gt;&lt;br /&gt;// struts 无法设置其值&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0); font-family: monospace;"&gt;&lt;br /&gt;// 解决办法：&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;if (getAccount() != null) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;getAccount().setDisplayMylist(false);&lt;/span&gt;&lt;br
      /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;getAccount().setDisplayBanner(false);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;基于 JSTL 和 Struts HTML Tag 的 JSP&lt;/h2&gt;&lt;br /&gt;我们主要介绍一下JSP文件的总体结构。&lt;br /&gt;&lt;br /&gt;&lt;br
      /&gt;&lt;br /&gt;由于此应用在表示层来讲，大体上还是属于 Demo 级别的，所以并未采用 Struts Tile&lt;br /&gt;技术来对页面布局进行管理。而是使用传统的JSP表态包含指令，来包含进公共部分，如页眉，页脚及导航区域等。&lt;br /&gt;&lt;br /&gt;所有以 Include 前缀命名的JSP都用来被其它JSP页面包含的页面块。例如：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;lt;%@ include&lt;br /&gt;file="IncludeTop.jsp" %&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; 页面的具体内容&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:
      monospace;"&gt;&amp;lt;%@ include&lt;br /&gt;file="IncludeBottom.jsp" %&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;在 IncludeTop.jsp 中声明：&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt"
      %&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;%@ taglib prefix="html" uri="http://jakarta.apache.org/struts/tags-html" %&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;这样我们就不需要在所有用到JSTL的页面中重复声明。&lt;br /&gt;同时，我们并没有使用 Struts 的 Bean 和 Logic 等标记库，因为在 Struts 网站上声明有：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Note:&lt;/strong&gt; - Many of the features in this taglib are also&lt;br /&gt;available in the &lt;a
      href="http://java.sun.com/products/jsp/jstl/"&gt;&lt;br /&gt;JavaServer Pages Standard Tag Library (JSTL).&lt;/a&gt; The Apache Struts&lt;br /&gt;group encourages the use of the standard tags over the Struts specific&lt;br /&gt;tags when possible.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;避免重复提交&lt;/h2&gt;&lt;br /&gt;避免重复提交是一项挑战性的工作，如果你曾经真正参与过一个基于 B/S 结构的项目的话，&lt;br /&gt;甚至基于 C/S结构的界面也同样有这样的工作，正不过在那个领域叫做控制状态管理，&lt;br /&gt;比如，当你按下一个登录按钮后，而按钮并没有变为disable/不可用状态，&lt;br
      /&gt;你可能在不经意间又点了一次该按钮，那么在一瞬间你肯定登录了两次，这种情况还好，&lt;br /&gt;因为登录并不伤害系统的其它情况，只不过统计系统或许会感觉到纳闷，&lt;br /&gt;为什么在不到两秒钟内，你登录了两次？&lt;br /&gt;&lt;br /&gt;但是如果这个操作是插入一条数据或者是删除一条数据呢？&lt;br /&gt;&lt;br /&gt;对于插入一条数据，如果系统没设唯一性检查，则两条相同的数据生成了；&lt;br /&gt;&lt;br /&gt;对于删除数据，则第二次删除必然会失败。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;知道问题的重要性了，可是对B/S 开发人员来说，问题还不止这些：&lt;br /&gt;&lt;br /&gt;1.典型的，网络状况不是很好时，为完成一个插入操作可有会等上好几十秒的时间，&lt;br /&gt;用户此时会“再点”一次，还是会“回退”，甚至是忍无可忍关掉浏览器呢？&lt;br /&gt;&lt;br /&gt;2.
      对于回退，如果前一操作是删除操作，是否需要再次进行一次删除操作？&lt;br /&gt;&lt;br /&gt;3. 如果用户收藏起了这一个进行删除或插入操作的URL，在他/她重新激活这一链接后，&lt;br /&gt;该做何处理，如果这一操作需要授权呢？&lt;br /&gt;&lt;br /&gt;我们要介绍的机制并不是完美的机制，事实上这些现实的问题并没有列入大多数的WEB&lt;br /&gt;框架的设计议程中，所以做WEB应用开发是乏味的，甚至有时会让人冒火!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Struts 的事务 Token&lt;/h3&gt;&lt;br /&gt;通过使用Struts 的事务Token 来防止重复提交是可行的，&lt;br /&gt;仔细阅读org.apache.struts.action.Action中的如下方法的 javadoc&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;generateToken&lt;/li&gt;&lt;br
      /&gt;&lt;li&gt;saveToken&lt;/li&gt;&lt;br /&gt;&lt;li&gt;isTokenValid&lt;/li&gt;&lt;br /&gt;&lt;li&gt;resetToken&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://struts.apache.org/1.3.8/struts-taglib/tagreference.html#link"&gt;&amp;lt;html:link&lt;br /&gt;transaction="true"&gt;&lt;/a&gt; If set to true, any current transaction&lt;br /&gt;control token will be included in the generated hyperlink, so that it&lt;br /&gt;will pass an isTokenValid() test in the receiving Action.&lt;br /&gt;&lt;br
      /&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;我们通过提交定单的例子来看这个事务 Token 的工作流:&lt;br /&gt;&lt;br /&gt;我们的例子中，是要在显示确认页面中，如果点 'Continue' 按钮，会将一个定单插入到数据库中，&lt;br /&gt;显然，我们需避免重复点击该按钮。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;解决方案&lt;/span&gt;：&lt;br /&gt;&lt;br /&gt;我们得看看这个过程的映射配置：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;&amp;lt;!-- 进入结算中心页面后，点击继续进入此 --&gt;&lt;/span&gt;&lt;br /&gt;&lt;br
      /&gt;&lt;/span&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;action path="/shop/newOrderForm"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.NewOrderFormAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;name="workingOrderForm" scope="session" validate="false"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success"&lt;br
      /&gt;path="/WEB-INF/jsp/struts/NewOrderForm.jsp"/&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;/action&gt;&lt;/span&gt;&lt;span style="font-family: monospace;"&gt;&lt;/span&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-weight: bold;"&gt;&amp;lt;!--&lt;br /&gt;填写定单信息的多页向导式页面 --&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;&amp;lt;!--&lt;br
      /&gt;当第一页校验失败时，需要跳回填写购物单的第一页 --&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;action path="/shop/newOrderStep1"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.NewOrderAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;name="workingOrderForm" scope="session" validate="true"&lt;br /&gt;input="/shop/newOrderForm.do"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:
      monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="confirm"&lt;br /&gt;path="/WEB-INF/jsp/struts/ConfirmOrder.jsp"/&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="shipping"&lt;br /&gt;path="/WEB-INF/jsp/struts/ShippingForm.jsp"/&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;/action&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0); font-family:
      monospace;"&gt;&amp;lt;!--&lt;br /&gt;(只有页面上填写了将宠物送到不同的地址时，默认为送到当前用户的地址)，才会出现此面。&lt;br /&gt;此页校验失败，毫无疑问应该回到这个新地址填写页，而不是整个流程的第一页。&lt;br /&gt;这就是原版中的BUG所在处，因为它将这个向导性的流程处理放到了一个映射中，&lt;br /&gt;所以没法处理这种情况 --&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;action&lt;br /&gt;path="/shop/newOrderStep2"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.NewOrderAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br
      /&gt;name="workingOrderForm" scope="session" validate="true"&lt;br /&gt;input="/WEB-INF/jsp/struts/ShippingForm.jsp"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="confirm"&lt;br /&gt;path="/WEB-INF/jsp/struts/ConfirmOrder.jsp"/&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;/action&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0); font-family:
      monospace;"&gt;&amp;lt;!--&lt;br /&gt;当在最后一步确认时出错，需要跳回填写购物单的第一页 --&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;action&lt;br /&gt;path="/shop/newOrderStep3"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.NewOrderAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;name="workingOrderForm" scope="session" validate="true"&lt;br /&gt;input="/WEB-INF/jsp/struts/NewOrderForm.jsp"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span
      style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success" path="/WEB-INF/jsp/struts/ViewOrder.jsp"/&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;/action&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1. 因为最后三个映射使用的是同一个 NewOrderAction，再有作重复提交检查就是在这个 Action 中，因此，不可能在这个Action 的 exeute 方法中调用 &lt;span style="font-weight: bold; color: rgb(255, 0, 0);"&gt;saveToken(request);,&lt;br /&gt;一般来说，总是在进行重复提交检查的前一个Action 中放一个
      Token, 即调用 saveToken(request);方法，因此根据这个流程，我们只能在 &lt;/span&gt;&lt;span style="font-family: monospace;"&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;NewOrderFormAction&lt;br /&gt;&lt;/span&gt;中生成：正如你可以在源码中看到一样：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;//避免重复提交&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;saveToken(request);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;&lt;br /&gt;return
      mapping.findForward("success");&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;2. 因为我们是要避免重复按 &lt;span style="font-family: monospace;"&gt;ConfirmOrder.jsp&lt;br /&gt;中的 'Continue' 按钮，因此我们需要这样写:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;&amp;lt;%-- prevent duplication submit --%&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;center&gt;&amp;lt;html:link&lt;br
      /&gt;page="/shop/newOrderStep3.do?step=3&amp;amp;newOrder=true" &lt;span style="color: rgb(255, 0, 0);"&gt;transaction="true"&lt;/span&gt;&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;img border="0"&lt;br /&gt;src="../images/button_continue.gif" /&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/html:link&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/center&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3. 最后，在处理的 Action 中(即 &lt;span style="font-family: monospace;"&gt;&lt;span style="color: rgb(255, 0,
      0);"&gt;NewOrderAction&lt;/span&gt;) 进行有效性检查：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;protected ActionForward &lt;span style="font-weight: bold;"&gt;doExecute&lt;/span&gt;(ActionMapping mapping, ActionForm form,&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;HttpServletRequest request, HttpServletResponse response) throws Exception {&lt;br /&gt;&lt;br /&gt;if (!isTokenValid(request, false)&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;// 如果结果不是同一个令牌，为多重提交&lt;br /&gt;&lt;br /&gt;//resetToken(request); &lt;span
      style="color: rgb(255, 0, 0);"&gt;// 判断完不自动销毁，留待下面的逻辑处理&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;request.setAttribute("message", "多重提交！");&lt;br /&gt;request.getSession().removeAttribute("workingOrderForm");&lt;br /&gt;request.getSession().removeAttribute("cartForm");&lt;br /&gt;&lt;br /&gt;// Fixed by pprun for duplicate-submitand bug in the next time submit:&lt;br /&gt;// 竟然不再需要确认了！&lt;br /&gt;&lt;br /&gt;request.getSession().removeAttribute("orderForm");&lt;br /&gt;return
      mapping.findForward("failure");&lt;br /&gt;&lt;br /&gt;} else {&lt;br /&gt;&lt;br /&gt;// 多页表单&lt;br /&gt;&lt;br /&gt;OrderActionForm orderForm = (OrderActionForm) form;&lt;br /&gt;&lt;br /&gt;// 是否要进入可选的 shipingAddress 页面&lt;br /&gt;&lt;br /&gt;if&lt;br /&gt;(orderForm.isShippingAddressRequired() &amp;amp;&amp;amp; orderForm.getStep().equals("1")) {&lt;br /&gt;&lt;br /&gt;// 需要将物品寄给别人，而不是自己&lt;br /&gt;&lt;br /&gt;return mapping.findForward("shipping");&lt;br /&gt;&lt;br /&gt;// 两种情况：&lt;br /&gt;//
      1.&lt;br /&gt;从页面1直接进入确认页面（不需要寄到不同的地址时）&lt;br /&gt;&lt;br /&gt;// 2. 从 shipingAddress&lt;br /&gt;进入到确认页面&lt;br /&gt;&lt;br /&gt;} else if&lt;br /&gt;((orderForm.getStep().equals("1") &amp;amp;&amp;amp; orderForm.isShippingAddressRequired() == false)&lt;br /&gt;|| orderForm.getStep().equals("2")) {&lt;br /&gt;&lt;br /&gt;// 进入确认页面&lt;br /&gt;&lt;br /&gt;return mapping.findForward("confirm");&lt;br /&gt;&lt;br /&gt;} else if (orderForm.getOrder() != null) {&lt;br /&gt;&lt;br /&gt;// 最终处理&lt;br
      /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;// 销毁事务标记(放在此处，最开始处很重要，&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;&lt;br /&gt;// 以保证不管再快的多重提交都会得到无效的判断的)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;resetToken(request);&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Order order = orderForm.getOrder();&lt;br /&gt;// todo 这段逻辑应该放在 DAO 层？&lt;br /&gt;&lt;br
      /&gt;getPetStore().insertOrder(order);&lt;br /&gt;&lt;br /&gt;// 成功进行后，移除会话状态，&lt;br /&gt;// 以便 NewOrderFormAction 中检查出是否用户后退操作&lt;br /&gt;&lt;br /&gt;request.getSession().removeAttribute("workingOrderForm");&lt;br /&gt;request.getSession().removeAttribute("cartForm");&lt;br /&gt;&lt;br /&gt;// Fixed by pprun for duplicate-submit and bug in the next time submit:&lt;br /&gt;&lt;br /&gt;// 竟然不再需要确认了！所以必须移除它&lt;br /&gt;request.getSession().removeAttribute("orderForm");&lt;br
      /&gt;request.setAttribute("order", order);&lt;br /&gt;request.setAttribute("message", "Thank you, your order has been&lt;br /&gt;submitted.");&lt;br /&gt;&lt;br /&gt;// 选择 ViewOrder.jsp 中的显示方式&lt;br /&gt;&lt;br /&gt;request.setAttribute("newOrder", true);&lt;br /&gt;return mapping.findForward("success");&lt;br /&gt;&lt;br /&gt;} else {&lt;br /&gt;&lt;br /&gt;request.setAttribute("message",&lt;br /&gt;"An error occurred processing your order (order was null).");&lt;br /&gt;&lt;br /&gt;return
      mapping.findForward("failure");&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;调用 &lt;/span&gt;&lt;span style="font-family: monospace;"&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;isTokenValid(request,false) 判断我们上述的 1, 2, 3 三处步骤是否是按顺序成功处理完，如果中途哪个步骤重新执行，比如在执行到第三步的 &lt;/span&gt;&lt;/span&gt;&lt;span style="font-family: monospace;"&gt;&lt;span style="font-weight:
      bold;"&gt;doExecute&lt;/span&gt;()的代码&lt;/span&gt;&lt;span style="font-family: monospace;"&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;&lt;span style="font-weight: bold;"&gt;resetToken(request)之前，&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family: monospace;"&gt;又来了一个请求，由于此时 Token 还在，未被 resetToken, 此时比较已经存在的 Token 和 link 带进的&lt;br /&gt;Token，发现它们俩不同，因此&lt;/span&gt;&lt;span style="font-family: monospace;"&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;&lt;span style="font-weight:
      bold;"&gt;isTokenValid(request,false&lt;/span&gt;)将返回 false,告之多重提交，并跳到错误页面。&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family: monospace;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&lt;br /&gt;我们之所以调用&lt;/span&gt;&lt;span style="font-family: monospace;"&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;&lt;span style="font-weight: bold;"&gt; isTokenValid(request, false&lt;/span&gt;&lt;/span&gt;) 这个方法并传一个
      false是因为我们使用的向导页面，在这个判断之后到最终的确认页面还有一个或两个页面要处理，因此我们不能在判断完后，立即销毁 Token,而是要等到真正处理完时才这样做。但是对简单逻辑的页面，可以直接调用isTokenValid(request) 或isTokenValid(request,true) 在判断完后，直接销毁 Token.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;我们还缺什么?&lt;/h2&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;客户端校验&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;基于 JavaScript 的检验方式。Struts支持这种处理方式，只不过我们没有把这一功能加入进来而已。因为客户端检验可以在第一时间发现输入数据的问题，而不至于浪费一个数据传输来回(提交错误数&lt;br /&gt;据 -&gt; 在 FormBean 中判断为无效 -&gt; 以错误信息的形式显示给用户)。&lt;br /&gt;&lt;br
      /&gt;但是，请记住!&lt;br /&gt;服务端校验是一定要做的，因为有人总喜欢在中途拦截、篡改客户发来的数据而骗过客户端的校验器。而服务端是发生在服务器上，只要服务器没被攻破，黑客是不&lt;br /&gt;可能篡改这段 FormBean 代码的。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;漂亮的页面&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;现在的页面只是个原型，离最终的漂亮还有段距离。但是这是需要美工设计人员介入的，因为一个人总不可能样样在行的。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;总结&lt;/h2&gt;&lt;br /&gt;对于新手而言，看基于 Struts 的实现代码，有时的确会失去方向。此时，最好将 Strut-config.xml&lt;br /&gt;文件打印一份在手边，然后对应页面上的每一个动作(提交，链接点击等)得到其要去往的URL，然后在Strut-config.xml
      中找到对应的Action 映射。例如：&lt;br /&gt;&lt;br /&gt;在 SignonForm.jsp 页面中有：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;a href="&amp;lt;c:url&lt;br /&gt;value="&lt;span style="color: rgb(255, 0, 0);"&gt;/shop/newAccountForm&lt;/span&gt;.do"/&gt;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &amp;lt;img&lt;br /&gt;border="0" src="../images/button_register_now.gif" /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:
      monospace;"&gt; &amp;lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;于是我们在struts-config.xml 文件中搜索“&lt;span style="color: rgb(255, 0, 0);"&gt;/shop/newAccountForm”&lt;/span&gt; 找到：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;&amp;lt;!-- 修改帐号信息 --&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;lt;action path="&lt;span style="color: rgb(255, 0,
      0);"&gt;/shop/newAccountForm&lt;/span&gt;"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.&lt;span style="color: rgb(255, 0, 0);"&gt;NewAccountFormAction&lt;/span&gt;"&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;name="&lt;span style="color: rgb(255, 0, 0);"&gt;workingAccountForm&lt;/span&gt;"&lt;br /&gt;scope="session" validate="false"&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;forward name="success"&lt;br /&gt;path="/WEB-INF/jsp/struts/&lt;span style="color: rgb(255, 0,
      0);"&gt;NewAccountForm.jsp&lt;/span&gt;"/&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/action&gt;&lt;/span&gt;&lt;span style="font-family: monospace;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;这样我们得知：&lt;br /&gt;&lt;br /&gt;1. 在页面 SignonForm.jsp 中，如果点击了 注册 按钮的话，Struts 将使用 workingAccountForm&lt;br /&gt;(即，类AccountActionForm) 来收集页面的即将的输入值，&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2. validate="false" 所以这时不需要做任何校验，因为此时，用户还没输入数据，只是在&lt;br
      /&gt;注册页面上点了“注册”按钮被带到了注册信息填写页面。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3. 执行&lt;span style="font-family: monospace;"&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;NewAccountFormAction&lt;/span&gt;&lt;/span&gt;#execute()方法，在成功处理后，将前进到页面 &lt;span style="font-family: monospace;"&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;NewAccountForm.jsp&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;4. 用户输入用户信息数据&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;我们看到在 NewAccountForm.jsp 页面中有：&lt;br
      /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;html:form action="&lt;span style="color: rgb(255, 0, 0);"&gt;/shop/newAccount&lt;/span&gt;.do"&lt;br /&gt;styleId="workingAccountForm" method="post" &gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;5. 我们再次在 struts-config.xml 文件中找 "&lt;span style="font-family: monospace;"&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;/shop/newAccount"&lt;/span&gt;, 得到&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;action path="&lt;span style="color: rgb(255, 0,
      0);"&gt;/shop/newAccount&lt;/span&gt;"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.NewAccountAction"&lt;br /&gt;&lt;br /&gt;name="workingAccountForm" scope="session" validate="true"&lt;br /&gt;input="/WEB-INF/jsp/struts/NewAccountForm.jsp"&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;forward name="success" path="&lt;span style="color: rgb(255, 0, 0);"&gt;/shop/index.do&lt;/span&gt;"/&gt;&lt;br /&gt;&amp;lt;/action&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;6. 这一次还是利用同一个
      FormBean(已经在前面收集了用户的输入数据),&lt;br /&gt;因为这一次 在&lt;span style="color: rgb(255, 0, 0);"&gt;NewAccountAction#execute()&lt;/span&gt;方法中要用到 前面的输入值.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;7. 判断输入数据的合法性&lt;br /&gt;&lt;br /&gt;如果不合法，将跳转到同一页面，但此时将显示错误信息&lt;br /&gt;&lt;br /&gt;如果合法，则继续向前，这一次是回到首页，即这一流程宣告结束。&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;</description>
      <pubDate>Wed, 10 Dec 2008 17:08:14 +0000</pubDate>
    </item>
    <item>
      <title>平步星云: NetBeans 6.0 抢先试用</title>
      <guid isPermaLink="false">tag:blogger.com,1999:blog-171648533238476397.post-3739164309819377361</guid>
      <link>http://pprun.blogspot.com/2007/05/netbeans-60.html</link>
      <description>NetBeans 6.0 M9 (Preview) 已经出来好些天了，还剩下最后一个里程碑就要进入测试阶段。&lt;br /&gt;&lt;br /&gt;对我来说，自从从 Oracle JDeveloper 转向 NetBeans 以来，在工作中我一直坚持用它。也许是的我工作表现迫使远在美国那边的同事放弃了说服我使用 Eclipse 吧。你也许想知道，作为一名NetBeans 的老用户，我期待 6.0 的什么，虽然它已经很好了。&lt;br /&gt;&lt;br /&gt;1.不要因为整个 Editor 的体系重组，而使强“稳定性”的口碑打折扣 (基本上大部分模块都重新Retouche了），因为我拒绝使用 Eclipse 的原因之一就是: JVM OutOfMemoryError.&lt;br /&gt;&lt;br /&gt;2.Occurrences Highlight 我在之前的文章中写过关于这一功能&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3.Javadoc and Declaration View
      我已经等了好几年，我甚至曾经自己利用 NetBeans 的API 实现过一个类似的模块，但是因为NetBeans本身的问题（java meta data record)，功能不完整。有了这两个窗口，就永远不用 Go to Source, Show JavaDoc 了，所有的信息都在手边，只需将鼠标放在想看的类元素上。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_bpUunzIgcNA/RkXXRKKBVwI/AAAAAAAAAAs/IMDowTFQ0lo/s1600-h/1.jpg"&gt;&lt;img src="http://1.bp.blogspot.com/_bpUunzIgcNA/RkXXRKKBVwI/AAAAAAAAAAs/IMDowTFQ0lo/s400/1.jpg" alt="" style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" border="0"
      id="BLOGGER_PHOTO_ID_5063690045832124162" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;4.Code Generation dialog 我的确很厌倦写类的构造器的实现，特别是类的成员很多的情况下。还有标准的、功能完善的、性能良好的　Common Methods: equals, hashcode　的实现等。&lt;br /&gt;有了它，在右图中的例子中我只需要输入&lt;br /&gt;private long id;&lt;br /&gt;private String name;&lt;br /&gt;private int age;&lt;br /&gt;&lt;br /&gt;其它的代码都是由它产生的。&lt;br /&gt;&lt;br /&gt;5. Local History &lt;br /&gt;&lt;br /&gt;或许有些功能被我忽视了，如是这样的话，请见&lt;a
      href="http://wiki.netbeans.org/wiki/view/WhatsCoolInNetBeans60"&gt;此处&lt;/a&gt;的详细列表。还有整个重写的 Editor 的功能都陆续地出现在&lt;a href="http://wiki.netbeans.org/wiki/view/Java_EditorUsersGuide"&gt;这&lt;/a&gt;。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;是的，我也保留些目前还未完善的功能，我本人也没有加紧试用。如果我认为有用的话，我会进一步写出来的。</description>
      <pubDate>Wed, 10 Dec 2008 17:08:14 +0000</pubDate>
    </item>
    <item>
      <title>平步星云: NetBeans多语言版本，更换默认 Locale 设置时的问题</title>
      <guid isPermaLink="false">tag:blogger.com,1999:blog-171648533238476397.post-8872930461868475353</guid>
      <link>http://pprun.blogspot.com/2007/05/netbeans-locale.html</link>
      <description>&lt;span style="color: rgb(255, 0, 0);"&gt;update: (这个BUG只会在中文操作系统下出现，在英文版的操作系统上一切正常。看来是一些模块在编写时没有正确地加载对应locale 的 properties 文件)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;在我看来，在日常的工作平台，JDK/NetBeans 的i18n 字体问题已经成为历史了。但是我前些天又登记了一个 &lt;a href="http://www.netbeans.org/issues/show_bug.cgi?id=103908"&gt;BUG &lt;/a&gt;到 NetBeans 的 IssueZilla 中:&lt;br /&gt;&lt;br /&gt;1. 下载多语言版本的安装包，安装&lt;br /&gt;2. 因为我不喜欢那些翻译的不准确的词，所以我打算回退到英文的 locale:&lt;br /&gt;增加一个启动参数到 $NetBeans/etc/netbeans.conf 文件：&lt;br
      /&gt;netbeans_default_options="&lt;span style="font-weight: bold;"&gt;$默认的配置&lt;/span&gt; --locale en"&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;&lt;span style="font-weight: bold; font-family: georgia;"&gt;语法为:&lt;/span&gt; --locale language[:country[:variant]]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;3. 重启后，你将看到“著名的字体问题”重新又出现了，显示为小方框：&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_bpUunzIgcNA/RkvO_QKV81I/AAAAAAAAABI/iB6nXRhgZM0/s1600-h/i18n.png"&gt;&lt;img
      src="http://4.bp.blogspot.com/_bpUunzIgcNA/RkvO_QKV81I/AAAAAAAAABI/iB6nXRhgZM0/s400/i18n.png" alt="" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" border="0" id="BLOGGER_PHOTO_ID_5065369791973684050" /&gt;&lt;/a&gt;&lt;br /&gt;当前，只有两种办法可以解决这一问题：&lt;br /&gt;&lt;br /&gt;1. 去掉加上的 locale 参数，但必须忍受翻译得不佳的词了。&lt;br /&gt;&lt;br /&gt;2. 下载英文版，继续用吧。但这样的话，在 Welcome 中你将看不到中文的 Blog.</description>
      <pubDate>Wed, 10 Dec 2008 17:08:13 +0000</pubDate>
    </item>
    <item>
      <title>平步星云: GlassFish/Sun App Server 配置 MySqlXADataSource 的问题</title>
      <guid isPermaLink="false">tag:blogger.com,1999:blog-171648533238476397.post-5359638578221088052</guid>
      <link>http://pprun.blogspot.com/2007/05/glassfishsun-app-server.html</link>
      <description>如果你打算使用 GlassFish/Sun App Server，并且打算使用 MySql 的 XA 数据源的话。在目前的配置过程中，会遇到如下问题：&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;重现步骤：&lt;/span&gt;&lt;br /&gt;1. (如果之前没做这一步的话)将 Mysql 的 Connector/J 包 (如我的：mysql-connector-java-3.1.12-bin.jar）放入 GlassFish/Sun App Server 安装目录下子目录 \AppServer\lib\ 中&lt;br /&gt;&lt;br /&gt;2. 启动 GlassFish/Sun App Server. 可通过　右击 Runtime | Servers | Sun App Server 选择 start&lt;br /&gt;&lt;br /&gt;3. 启动后，右击 Sun App Server 选择 View Admin console&lt;br
      /&gt;&lt;br /&gt;4. 登录WEB 管理后台&lt;br /&gt;&lt;br /&gt;5. 在左侧导航器中 点击 Resources | JDBC | Connection Pool s，在表格的头部点击 New... 按钮&lt;br /&gt;&lt;br /&gt;6. 在右侧中填入：&lt;br /&gt;Name: MySql&lt;br /&gt;Resource Type: javax.sql.XADataSource&lt;br /&gt;Database Vendor: mysql &lt;br /&gt;&lt;br /&gt;然后点击 next&lt;br /&gt;&lt;br /&gt;7. 注意在 Datasource class name 中自动填入了: com.mysql.jdbc.jdbc2.optional.MysqlXaConnectionPoolDataSource，这个值是不对的。&lt;br /&gt;&lt;br /&gt;你如果想试试的话，在最下面的　Properties　窗格中填入 :&lt;br /&gt;&lt;br
      /&gt;&lt;a href="http://1.bp.blogspot.com/_bpUunzIgcNA/Rk0F_AKV82I/AAAAAAAAABQ/8-xOwAPMy18/s1600-h/mydqljdbc.png"&gt;&lt;img src="http://1.bp.blogspot.com/_bpUunzIgcNA/Rk0F_AKV82I/AAAAAAAAABQ/8-xOwAPMy18/s400/mydqljdbc.png" alt="" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" border="0" id="BLOGGER_PHOTO_ID_5065711735794955106" /&gt;&lt;/a&gt;&lt;br /&gt;点击 Finish&lt;br /&gt;&lt;br /&gt;8. 在结果窗口中点击 Mysql&lt;br /&gt;&lt;br /&gt;9. 在打开的页面中可以看到一个ping
      按钮，点击是用来测试配置成功与否，点击一下，将出现如下错误：&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_bpUunzIgcNA/Rk0HEAKV83I/AAAAAAAAABY/oYX5Mdt52ec/s1600-h/mydqljdbc_error.png"&gt;&lt;img src="http://1.bp.blogspot.com/_bpUunzIgcNA/Rk0HEAKV83I/AAAAAAAAABY/oYX5Mdt52ec/s400/mydqljdbc_error.png" alt="" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" border="0" id="BLOGGER_PHOTO_ID_5065712921205928818" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-weight:
      bold;"&gt;解决的办法：&lt;/span&gt;&lt;br /&gt;如果解开mysql-connector-java-3.1.12-bin.jar 文件，在包com.mysql.jdbc.jdbc2.optional 中可　看到:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;com/mysql/jdbc/jdbc2/optional/&lt;br /&gt;com/mysql/jdbc/jdbc2/optional/CallableStatementWrapper.class&lt;br /&gt;com/mysql/jdbc/jdbc2/optional/ConnectionWrapper.class&lt;br /&gt;com/mysql/jdbc/jdbc2/optional/MysqlConnectionPoolDataSource.class&lt;br /&gt;com/mysql/jdbc/jdbc2/optional/MysqlDataSource.class&lt;br
      /&gt;com/mysql/jdbc/jdbc2/optional/MysqlDataSourceFactory.class&lt;br /&gt;com/mysql/jdbc/jdbc2/optional/MysqlPooledConnection.class&lt;br /&gt;com/mysql/jdbc/jdbc2/optional/MysqlXAConnection.class&lt;br /&gt;com/mysql/jdbc/jdbc2/optional/MysqlXADataSource.class&lt;br /&gt;com/mysql/jdbc/jdbc2/optional/MysqlXAException.class&lt;br /&gt;com/mysql/jdbc/jdbc2/optional/MysqlXid.class&lt;br /&gt;com/mysql/jdbc/jdbc2/optional/PreparedStatementWrapper.class&lt;br
      /&gt;com/mysql/jdbc/jdbc2/optional/StatementWrapper.class&lt;br /&gt;com/mysql/jdbc/jdbc2/optional/SuspendableXAConnection.class&lt;br /&gt;&lt;br /&gt;...&lt;/pre&gt;其中并没有默认填入的 com.mysql.jdbc.jdbc2.optional.MysqlXaConnectionPoolDataSource, 但是有　com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource&lt;br /&gt;&lt;br /&gt;在页面Application Server &gt; Resources &gt; JDBC &gt; Connection Pools &gt; MySql 中：&lt;br /&gt;1.将 Datasource class name 的值改为：
      com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource&lt;br /&gt;&lt;br /&gt;2.点击 Save 按钮&lt;br /&gt;&lt;br /&gt;3. 点击 Ping 按钮，成功显示：&lt;br /&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_bpUunzIgcNA/Rk0IVwKV84I/AAAAAAAAABg/-SZNDikl42Y/s1600-h/mydqljdbc_success.png"&gt;&lt;img src="http://4.bp.blogspot.com/_bpUunzIgcNA/Rk0IVwKV84I/AAAAAAAAABg/-SZNDikl42Y/s400/mydqljdbc_success.png" alt="" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" border="0"
      id="BLOGGER_PHOTO_ID_5065714325660234626" /&gt;&lt;/a&gt;</description>
      <pubDate>Wed, 10 Dec 2008 17:08:12 +0000</pubDate>
    </item>
    <item>
      <title>平步星云: 体验更多 NetBeans 的新功能</title>
      <guid isPermaLink="false">tag:blogger.com,1999:blog-171648533238476397.post-5203850018959686363</guid>
      <link>http://pprun.blogspot.com/2007/05/netbeans.html</link>
      <description>不喜欢 NetBeans 的开发者往往指出 NetBeans 没有这个功能，没有那个功能。无可厚非，当时他们是对的，但随着时间的推移，现在也许错了：&lt;br /&gt;&lt;br /&gt;1. Last Edit （是近更改按钮，带星号的那个），将你带到最近更改的地方&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_bpUunzIgcNA/RlQLuwKV87I/AAAAAAAAAB4/5kqPXrZ45xc/s1600-h/last+edit.png"&gt;&lt;img src="http://3.bp.blogspot.com/_bpUunzIgcNA/RlQLuwKV87I/AAAAAAAAAB4/5kqPXrZ45xc/s400/last+edit.png" alt="" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" border="0"
      id="BLOGGER_PHOTO_ID_5067688378528822194" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2. Diff SideBar (差异侧条), 根据所在行代码是增加、更改还是删除，在侧条中显示不同的小条，右击可以使用进一步的功能&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_bpUunzIgcNA/RlQMfQKV88I/AAAAAAAAACA/5L0j_Nr2uUo/s1600-h/diff+sidebar.png"&gt;&lt;img src="http://1.bp.blogspot.com/_bpUunzIgcNA/RlQMfQKV88I/AAAAAAAAACA/5L0j_Nr2uUo/s400/diff+sidebar.png" alt="" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;"
      border="0" id="BLOGGER_PHOTO_ID_5067689211752477634" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;3. JUnit4 支持（也就是现在可以使用基于 JDK 5 Annotation 的单元测试了）&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_bpUunzIgcNA/RlQMuwKV89I/AAAAAAAAACI/DlpU2V4jrcA/s1600-h/JUnit4.png"&gt;&lt;img src="http://3.bp.blogspot.com/_bpUunzIgcNA/RlQMuwKV89I/AAAAAAAAACI/DlpU2V4jrcA/s400/JUnit4.png" alt="" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" border="0"
      id="BLOGGER_PHOTO_ID_5067689478040450002" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;4. Find/Replace in Project (全工程范围内搜索)，是的，这个功能我真的也非常需要:&lt;br /&gt;看到左下方的"Replace" 按钮了吗？&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(255, 0, 0);"&gt;值得注意的是，这个功能在 M9 中被屏蔽了，但在每日构建的版本中可以使用。&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;img src="http://1.bp.blogspot.com/_GUaFO77rw-w/RcDNGbkZUrI/AAAAAAAAAAg/t_qTqZMw834/s1600/nb-find-replace.png"
      alt="[nb-find-replace.png]" border="0" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;另外，大部分初次使用NetBeans 的开发者，不知道更改“自动完成弹出窗口”的键绑定，因为最常用的"Ctrl + 空格" 是不可工作的，因为在中文操作系统中被绑定到输入法的切换了。所以我一般把它改成 'Ctrl + Enter' , 如下进行：&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Tools | Options -&gt; Keymap -&gt; Other&lt;/li&gt;&lt;li&gt;找到 Show Code Completion Popup, 选中它，点击Add...&lt;/li&gt;&lt;li&gt;按下任何所你希望的键序列，但是如果直接按 Ctrl + Enter 的话，系统提示这个组合键已经被绑定到 Split Line，所以如果我们要使用这个组合键的话，要先把它与 Split Line
      解除绑定&lt;/li&gt;&lt;li&gt;在 Show Code completion Popup 下方第六个即是　Split Line, 选中它，点击移除。你可以为这个功能提供另外的组合键，如果经常使用这一功能的话。&lt;/li&gt;&lt;li&gt;然后，按照上述把"Ctrl + Enter " 加到 Show Code Completion Popup 中去。&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;(期待下一篇)</description>
      <pubDate>Wed, 10 Dec 2008 17:08:12 +0000</pubDate>
    </item>
    <item>
      <title>平步星云: NetBeans6 功能介绍: 布置 declaration View 和 Javadoc View</title>
      <guid isPermaLink="false">tag:blogger.com,1999:blog-171648533238476397.post-6690572939674191050</guid>
      <link>http://pprun.blogspot.com/2007/05/netbeans6-declaration-view-javadoc-view.html</link>
      <description>此篇文章介绍一个在 NetBeans 6 中同时查看鼠标指针处的源代码和&lt;br /&gt;Javadoc (不再Go to Source .../ Show JavaDoc)&lt;br /&gt;&lt;br /&gt;1. 首先打开它们：Window | Other | Declaration View 和 Window | Other | Javadoc View, 它们都被搁浅在 Output 窗口的位置，但此时只能看到一个窗口的内容，因为无论切换到其中的任何一个，它们都占据整个下端窗口。如下：&lt;br /&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_bpUunzIgcNA/RlQX3AKV8-I/AAAAAAAAACQ/d7N40OUDYh0/s1600-h/decl_doc_1.png"&gt;&lt;img
      src="http://4.bp.blogspot.com/_bpUunzIgcNA/RlQX3AKV8-I/AAAAAAAAACQ/d7N40OUDYh0/s400/decl_doc_1.png" alt="" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" border="0" id="BLOGGER_PHOTO_ID_5067701714402276322" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;2. 我们要将它们分开，点击其中任一窗口的上方（类似标题栏区域），按住不放，将其拖向左侧（或右侧也可），当出现一个红色的方框后释放，如下：&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_bpUunzIgcNA/RlQYGwKV8_I/AAAAAAAAACY/KBwpchWvfPM/s1600-h/decl_doc_2.png"&gt;&lt;img
      src="http://3.bp.blogspot.com/_bpUunzIgcNA/RlQYGwKV8_I/AAAAAAAAACY/KBwpchWvfPM/s400/decl_doc_2.png" alt="" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" border="0" id="BLOGGER_PHOTO_ID_5067701984985215986" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;释放后的效果如下：&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_bpUunzIgcNA/RlQYPQKV9AI/AAAAAAAAACg/ywrhb2_9JSo/s1600-h/decl_doc_3.png"&gt;&lt;img
      src="http://1.bp.blogspot.com/_bpUunzIgcNA/RlQYPQKV9AI/AAAAAAAAACg/ywrhb2_9JSo/s400/decl_doc_3.png" alt="" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" border="0" id="BLOGGER_PHOTO_ID_5067702131014104066" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;这些位置会被记录下来，只要你在设置之后正常退出了。在下次启动 NetBeans 后，你可以看到同样的布局。&lt;br /&gt;&lt;br /&gt;这个截图中显示的是　Integer.toHexString　方法的 Javadoc 和 实现源码。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;(期待下一篇)</description>
      <pubDate>Wed, 10 Dec 2008 17:08:11 +0000</pubDate>
    </item>
    <item>
      <title>平步星云: Java 安全拷贝协议 (JSCP: Java Secure Copy Protocol) NetBeans 插件</title>
      <guid isPermaLink="false">tag:blogger.com,1999:blog-171648533238476397.post-8348407469588799409</guid>
      <link>http://pprun.blogspot.com/2007/06/java-jscp-java-secure-copy-protocol.html</link>
      <description>&lt;h3&gt;JSCP NetBeans 插件的作用&lt;/h3&gt;&lt;br /&gt;大家知道，SCP 广泛使用于SSH出现之前的 Unix 之类的平台上，它允许在 Client &amp;lt;-&gt; Server 间进行双向的文件传输（ScpTo, ScpFrom)&lt;br /&gt;&lt;br /&gt;JSCP NetBeans plugin 作为一个 TopComponet 插入到 NetBeans 的 Navigator 方位，通过 Tools | Java SCP 调用。&lt;br /&gt;&lt;br /&gt;SCP 可进行文件双向传输的&lt;br /&gt;&lt;ul&gt;&lt;li&gt;向支持 SCP 的 Unix/Linux 服务器上传文件（ScpTo）&lt;/li&gt;&lt;li&gt;从支持SCP的 Unix/Linux 服务器获得文件（ScpFrom)&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;这两种工作模式是分别作为 &lt;span
      style="font-family: monospace;"&gt;JTabbedPane &lt;/span&gt;的 两个 Tab 出现在 JScp 这个 &lt;span style="font-family: monospace;"&gt;TopComponent &lt;/span&gt;中&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;div style="text-align: left;"&gt;&lt;h3&gt;JSCP NetBeans 插件的使用方法&lt;/h3&gt;&lt;div style="text-align: left;"&gt;从NetBeans &lt;a
      href="http://plugins.netbeans.org/PluginPortal/faces/MainPage.jsp?pluginid=2786"&gt;PluginPortal&lt;/a&gt;&lt;a href="http://plugins.netbeans.org/PluginPortal/faces/MainPage.jsp?pluginid=2786"&gt; &lt;/a&gt; 网站上获得一个压缩包，然后解压到一个目录供下面的步骤使用。&lt;br /&gt;&lt;/div&gt; &lt;h3&gt;&lt;a name="5.1"&gt;&lt;/a&gt;安装 .NBM 文件&lt;/h3&gt;&lt;ol&gt;&lt;li&gt;Tools | Update Center&lt;/li&gt;&lt;li&gt;选择 Install Manually Downloaded Modules (.nbm Files) 后，点击 Next&lt;/li&gt;&lt;li&gt;点击 Add... , 在 Select Directory or .nbm
      Files 对话框中，导航到此插件的两个 .nbm 文件（com-jcraft-jsch.nbm 和 org.pprun-jscp.nbm），同时选中它们后点击 Ok&lt;/li&gt;&lt;li&gt;点击 Next &lt;/li&gt;&lt;li&gt;点击 Next&lt;/li&gt;&lt;li&gt;点击 Next, 在View Certificates and Install Modules 界面点击 Include 列下面的多选框中打上勾。界面将出现版权及插件签名信息。（如果你希望使用计算机的所有用户都使用这个插件，可以将在 Global 列下打勾）&lt;/li&gt;&lt;li&gt; Finish, 不出意外，将显示插件更新界面。&lt;/li&gt;&lt;li&gt;等到NetBeans 的状态条中显示 Turing on modules... done. 后，点击 Tools 菜单，此时将在菜单最底端看到 Java SCP 菜单项，如下：&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;h3&gt;&lt;a
      href="http://1.bp.blogspot.com/_bpUunzIgcNA/RmdvEI3zgXI/AAAAAAAAADY/hKD6I3Qvky0/s1600-h/menu.png"&gt;&lt;img src="http://1.bp.blogspot.com/_bpUunzIgcNA/RmdvEI3zgXI/AAAAAAAAADY/hKD6I3Qvky0/s400/menu.png" alt="" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" border="0" id="BLOGGER_PHOTO_ID_5073145622147858802" /&gt;&lt;/a&gt;&lt;/h3&gt;&lt;br /&gt;&lt;/div&gt;&lt;h3&gt;使用说明&lt;/h3&gt; &lt;h4&gt;&lt;a name="5.2.1"&gt;&lt;/a&gt;前提条件：&lt;/h4&gt;
      &lt;ul&gt;&lt;li&gt;保证网络可以访问到一台支持 SCP/ SSH1 的 Unix/Linux 服务器&lt;/li&gt;&lt;li&gt;保证具有以上服务器上的一个帐户并且对其中的一个目录具有“写”权限（如果你只使用 ScpFrom 的话，此项可选）&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h4&gt;&lt;a name="5.2.2"&gt;&lt;/a&gt;ScpTo (文件上传)&lt;/h4&gt;&lt;br /&gt;（如果还没打开 JScp Window 的话）通过 Tools | Java SCP 打开，它会出现在左下角并停靠在 Navigator 所在的窗口中，如下图所示：&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;LocalFile&lt;/span&gt; 上传的文件，通过右边的按钮来选择&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight:
      bold;"&gt;User@Host&lt;/span&gt; 用户名和主机名(或IP地址) 的组合&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Password&lt;/span&gt; 上述用户的密码&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;RemoteDir&lt;/span&gt; 上传的文件在服务器上放置的目录&lt;/li&gt;&lt;/ol&gt;&lt;a href="http://1.bp.blogspot.com/_bpUunzIgcNA/RmdutI3zgWI/AAAAAAAAADQ/z_ukNeEy1Kg/s1600-h/ScpFrom.png"&gt;&lt;img src="http://1.bp.blogspot.com/_bpUunzIgcNA/RmdutI3zgWI/AAAAAAAAADQ/z_ukNeEy1Kg/s400/ScpFrom.png" alt="" style="margin: 0px auto
      10px; display: block; text-align: center; cursor: pointer;" border="0" id="BLOGGER_PHOTO_ID_5073145227010867554" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;请注意在输入的过程中，会动态对输入域的值进行校验，如下，桔色的字显示没有指定服务器主机名(或IP地址）：&lt;br /&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_bpUunzIgcNA/Rmdvx43zgYI/AAAAAAAAADg/B7CwA5HwNZ8/s1600-h/warning.png"&gt;&lt;img src="http://4.bp.blogspot.com/_bpUunzIgcNA/Rmdvx43zgYI/AAAAAAAAADg/B7CwA5HwNZ8/s400/warning.png" alt="" style="margin: 0px auto 10px; display: block;
      text-align: center; cursor: pointer;" border="0" id="BLOGGER_PHOTO_ID_5073146408126873986" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;如果所有的输入都合法的话，按钮 Scp 将可用，点击它将进行网络传输，进度条指示这一过程:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_bpUunzIgcNA/RmdwWY3zgbI/AAAAAAAAAD4/JGROQtiQf_k/s1600-h/progress.png"&gt;&lt;img src="http://2.bp.blogspot.com/_bpUunzIgcNA/RmdwWY3zgbI/AAAAAAAAAD4/JGROQtiQf_k/s400/progress.png" alt="" style="margin: 0px auto 10px; display: block; text-align: center; cursor:
      pointer;" border="0" id="BLOGGER_PHOTO_ID_5073147035192099250" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;如果一切正常，最终进度条将停止指示。反之，如果后台操作出现错误的话，错误将显示：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_bpUunzIgcNA/RmdwBo3zgZI/AAAAAAAAADo/pE1KM2gEZp8/s1600-h/progressError.png"&gt;&lt;img src="http://3.bp.blogspot.com/_bpUunzIgcNA/RmdwBo3zgZI/AAAAAAAAADo/pE1KM2gEZp8/s400/progressError.png" alt="" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;"
      border="0" id="BLOGGER_PHOTO_ID_5073146678709813650" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;&lt;a name="5.2.3"&gt;&lt;/a&gt;ScpFrom (文件下载)&lt;br /&gt;&lt;/h4&gt;&lt;br /&gt;（如果还没打开 JScp Window 的话）通过 Tools | Java SCP 打开，它会出现在左下角并停靠在 Navigator 所在的窗口中，如下图所示：&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;User@Host&lt;/span&gt; 用户名和主机名(或IP地址) 的组合&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Password&lt;/span&gt;
      上述用户的密码&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;RemoteFile&lt;/span&gt; 要下载的服务器上的文件&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;LocalDir&lt;/span&gt; 下载的文件放置的目录，通过右边的按钮来选择&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_bpUunzIgcNA/Rmduko3zgVI/AAAAAAAAADI/9btBs3U3hfU/s1600-h/ScpTo.png"&gt;&lt;img src="http://3.bp.blogspot.com/_bpUunzIgcNA/Rmduko3zgVI/AAAAAAAAADI/9btBs3U3hfU/s400/ScpTo.png" alt="" style="margin: 0px auto 10px; display: block;
      text-align: center; cursor: pointer;" border="0" id="BLOGGER_PHOTO_ID_5073145080981979474" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;如果所有的输入都合法的话，按钮 Scp 将可用，点击它将进行网络传输。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;a name="6"&gt;&lt;/a&gt;总结&lt;/h3&gt;&lt;br /&gt;自从 NetBeans 5.0 开始，编写基于 NetBeans 的插件或平台应用已经变得非常简单。对于新来者，最大的障碍无非是一些NetBeans专用的术语及早期遗留下来的几个不大好理解的概念。不过还好， NetBeans 自己在快速前进的同时并没有忘记为开发者提供便利。&lt;br /&gt;&lt;a href="http://wiki.netbeans.org/wiki/view/Main"&gt;NetBeans wiki&lt;/a&gt;
      是各种信息的大轮盘&lt;br /&gt;&lt;a href="http://www.planetnetbeans.org/"&gt;planetnetbeans&lt;/a&gt; 则是全世界NetBeans开发者的乐园。大家为了 NetBeans 开怀畅谈。&lt;br /&gt;&lt;a href="http://blogs.sun.com/geertjan/" title="Geertjan's Weblog"&gt;Geertjan's Weblog&lt;/a&gt; 不得不看</description>
      <pubDate>Wed, 10 Dec 2008 17:08:10 +0000</pubDate>
    </item>
    <item>
      <title>平步星云: Hibernate Jpetstore 之五 部署</title>
      <guid isPermaLink="false">tag:blogger.com,1999:blog-171648533238476397.post-5072407594529084050</guid>
      <link>http://pprun.blogspot.com/2007/08/hibernate-jpetstore.html</link>
      <description>文档内容&lt;br /&gt;&lt;ul&gt;&lt;li&gt;概览&lt;/li&gt;&lt;li&gt;获得工程代码&lt;/li&gt;&lt;li&gt;配置&lt;/li&gt;&lt;ul&gt;&lt;li&gt;数据库初始化&lt;/li&gt;&lt;ul&gt;&lt;li&gt;MySQL 5.x&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Oracle 9i, 10g, HsqlDB, Postgres 及其它&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;应用服务器初始化&lt;/li&gt;&lt;ul&gt;&lt;li&gt;本地数据源（非JNDI 数据源）&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;ul&gt;&lt;li&gt;Tomcat 5.x,&lt;/li&gt;&lt;li&gt;Sun Application Server8.x, 9.x / GlassFish 1.x, 2.x&lt;/li&gt;&lt;li&gt;Jetty
      6.1.3&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;JNDI 数据源&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;ul&gt;&lt;li&gt;Sun Application Server8.x, 9.x / GlassFish 1.x, 2.x&lt;/li&gt;&lt;li&gt;JBoss 4.0.4 +&lt;/li&gt;&lt;li&gt;Jetty 6.1.3&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;li&gt;部署并运行&lt;/li&gt;&lt;li&gt;总结&lt;/li&gt;&lt;/ul&gt; PS: &lt;span style="font-style: itali