<?xml version="1.0" standalone="yes"?>
<?xml-stylesheet type="text/xsl" href="css/rss.xslt"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>AUG Team - Java</title><link>http://www.augweb.net/blog/</link><description>welcome。。。 - </description><generator>RainbowSoft Studio Z-Blog 1.8 Spirit Build 80605</generator><language>zh-CN</language><copyright>Copyright @ 2003-2008 AUG.(专业网站建设 北京) All Rights Reserved.</copyright><pubDate>Sun, 05 Sep 2010 23:27:21 +0800</pubDate><item><title>Windows下ORACLE 10g安装与操作图解</title><author>lorrons@gmail.com (lorron)</author><link>http://www.augweb.net/blog/post/224.html</link><pubDate>Mon, 16 Aug 2010 20:33:17 +0800</pubDate><guid>http://www.augweb.net/blog/post/224.html</guid><description><![CDATA[<div class="tit">Windows下ORACLE 10g安装与操作图解</div><div class="date">2007年10月21日 星期日 上午 06:16</div><p><table style="table-layout: fixed; width: 100%">    <tbody>        <tr>            <td>            <div class="cnt" id="blog_text">            <p>刚刚接触ORACLE的人来说,从那里学,如何学,有那些工具可以使用,应该执行什么操作,一定回感到无助。所以在学习使用ORACLE之前，首先来安装一下ORACLE 10g，在来掌握其基本工具。俗话说的好：工欲善其事，必先利其器。我们开始吧！</p>            <p>　　首先将ORACLE 10g的安装光盘放入光驱，如果自动运行，一般会出现如图1安装界面：<br />            <img border="undefined" alt="" src="http://img.ddvip.com/2007_05/1179042900_ddvip_1698.jpg" /><br />            <br />            图1</p>            <p>　　单击&ldquo;开始安装&rdquo;，就可以安装ORACLE 10g，一般会检查系统配置是否符合要求，然后出现&ldquo;Oracle DataBase 10g安装&rdquo;对话框，如图2所示：<br />            <br />            <img src="http://img.ddvip.com/2007_05/1179042906_ddvip_2092.jpg" border="undefined" alt="" /><br />            <br />            图2</p>            <p>　　在安装Oracle DataBase 10g时可以选择&ldquo;基本安装&rdquo;和&ldquo;高级安装&rdquo;两种方法。选择&ldquo;基本安装&rdquo;时，&ldquo;Oracle主目录位置&rdquo;用于指定Oracle DataBase 10g软件的存放位置；&ldquo;安装类型&rdquo;用于指定Oracle产品的安装类型(企业版、标准版和个人版)。如果选择&ldquo;创建启动数据库&rdquo;，那就要指定全局数据库名称和数据库用户的口令。</p>            <p>　　选择&ldquo;高级安装&rdquo;，单击&ldquo;下一步&rdquo;，会出现&ldquo;指定文件对话框&rdquo;，在源路径显示的是安装产品所在的磁盘路径；目标名称用于资定Oracle主目录所对应的环境变量，目标路径用于指定安装Oracle软件的目标安装路径。设置目标名称为：OraDb10g_home1，目标路径为：D:oracleproduct10.1.0db1。如图3：</p>            <p><img src="http://img.ddvip.com/2007_05/1179042915_ddvip_5846.jpg" border="undefined" alt="" /><br />            <br />            图3</p>            <p>　　单击&ldquo;下一步&rdquo;，会加载Oracle产品列表，然后出现&ldquo;选择安装类型&rdquo;对话框；如图4：<br />            <br />            <img src="http://img.ddvip.com/2007_05/1179042922_ddvip_8313.jpg" border="undefined" alt="" /><br />            <br />            图4</p>            <p>　　选择安装类型时一般选择&ldquo;企业版&rdquo;，单击&ldquo;下一步&rdquo;，会出现&ldquo;选择数据库配置&rdquo;对话框，如图5 ：</p>            <p><img src="http://img.ddvip.com/2007_05/1179042929_ddvip_9706.jpg" border="undefined" alt="" /><br />            <br />            图5</p>            <p>　　在&ldquo;选择数据库配置&rdquo;对话框中可以选择是否要创建启动数据库，如果要创建数据库还要选择建立数据库的类型。选择&ldquo;不创建启动数据库&rdquo;单击&ldquo;下一步&rdquo;，会出现&ldquo;概要&rdquo;对话框，如图6所示：<br />            <br />            <img src="http://img.ddvip.com/2007_05/1179042940_ddvip_7699.jpg" border="undefined" alt="" /><br />            <br />            图6</p>            <p>　　单击&ldquo;安装&rdquo;，就会开始安装Oracle DataBase 10g产品了。如图7为安装过程：</p>            <p><img src="http://img.ddvip.com/2007_05/1179042946_ddvip_8572.jpg" border="undefined" alt="" /><br />            <br />            图7</p>            <p>　　图8为安装完成<br />            <br />            <img src="http://img.ddvip.com/2007_05/1179042949_ddvip_5370.jpg" border="undefined" alt="" /><br />            <br />            图8</p>            <p>　　在安装完成Oracle Database 10g后，就要建立数据库。</p>            <p>　　 数据库配置助手(Database Configuration Assistant)用于创建数据库、配置数据库选项、删除数据库和管理模板。在安装Oracle database 10g的时候如果没有建立数据库，在安装完成之后就可以使用数据库配置助手(DBCA)建立数据库。</p>            <p>　　 建立数据库的方法有两种，第一种是在命令行下直接运行：dbca;第二种是点击开始菜单：开始=&gt;程序=&gt;Oracle=&gt;oraDb10g_home1=&gt;Configuration and Migration Tool=&gt;Database Configuration Assistant。如图1:</p>            <p><img src="http://img.ddvip.com/2007_05/1179042953_ddvip_224.jpg" width="740" border="undefined" alt="" /><br />            <br />            图1</p>            <p>　　之后，具体步骤如下，先出现欢迎对话框，如图2：</p>            <p><img src="http://img.ddvip.com/2007_05/1179042960_ddvip_3589.jpg" width="740" border="undefined" alt="" /><br />            <br />            图2</p>            <p>　　单击&ldquo;下一步&rdquo;，出现&ldquo;操作&rdquo;对话框，该对话框用于要执行的数据库操作(创建数据库、配置数据库选项、删除数据库和管理模板)，如图3：</p>            <p><img src="http://img.ddvip.com/2007_05/1179042962_ddvip_9584.jpg" width="740" border="undefined" alt="" /><br />            <br />            图3</p>            <p>　　如果是第一次创建数据库，只能创建数据库和管理模板可以使用，选择创建数据库，单击&ldquo;下一步&rdquo;，会出现数据库模板对话框，如图4：<br />            <br />            <img src="http://img.ddvip.com/2007_05/1179042973_ddvip_9631.jpg" width="740" border="undefined" alt="" /><br />            <br />            图4</p>            <p>　　数据库模板是本地硬盘上的XML文件，用来存储数据库的配置信息。</p>            <p>　　选择&ldquo;事务处理&rdquo;，单击&ldquo;下一步&rdquo;，会显示数据库标示对话框，该对话框用于设置全局数据库名和例程名。如图5：</p>            <p><img src="http://img.ddvip.com/2007_05/1179042978_ddvip_7192.jpg" width="740" border="undefined" alt="" /><br />            <br />            图5</p>            <p>　　全局数据库名，格式一般为：db_name.db_domain。db_name用于对应数据库名，db_domain对应于网络域名。SID(例程)应该与db_name完全一致.如图5都设置为:demo.</p>            <p>　　单击&ldquo;下一步&rdquo;，会出现&ldquo;管理选项&rdquo;对话框。用于设置OEM管理信息，如图6：</p>            <p><img src="http://img.ddvip.com/2007_05/1179042986_ddvip_5273.jpg" width="740" border="undefined" alt="" /><br />            <br />            图6<br />            <br />            　　如果要集中管理所有的Oracle数据库，那就要选择&ldquo;Grid Control管理数据库&rdquo;，如果只管理本地数据库，那就选择&ldquo;使用Database Control管理数据库&rdquo;。</p>            <p>　　选择&ldquo;使用Database Control管理数据库&rdquo;，单击&ldquo;下一步&rdquo;，会出现&ldquo;数据库身份证明&rdquo;对话框，该对话框用于设置初始数据库用户帐号的口令。如图7：</p>            <p><img src="http://img.ddvip.com/2007_05/1179042992_ddvip_8675.jpg" width="740" border="undefined" alt="" /><br />            <br />            图7</p>            <p>　　要选择用户SYS、SYSTEM、DBSNMP、SYSMAN使用相同的口令，那就选择&ldquo;所有账户使用同一口令&rdquo;。这里选择&ldquo;使用不同的口令&rdquo;，分别设置用户的口令：SYS用户的口令为ORACLE,SYSTEM用户的口令为MANAGER,DBSNMP用户的口令为DBSNMP,SYSMAN用户的口令为SYSMAN。</p>            <p>　　设置口令后，单击&ldquo;下一步&rdquo;，会出现&ldquo;存储选项&rdquo;对话框，该对话框用于指定数据库的存储机制(文件系统、自动存储管理、裸设备)，如图8：</p>            <p><img src="http://img.ddvip.com/2007_05/1179043004_ddvip_9970.jpg" width="740" border="undefined" alt="" /><br />            <br />            图8</p>            <p>　　选择&ldquo;文件系统&rdquo;，单击&ldquo;下一步&rdquo;，会出现&ldquo;数据库文件位置&rdquo;对话框，该对话框用于指定数据库文件的存放位置。如图9：<br />            　　<img src="http://img.ddvip.com/2007_05/1179043010_ddvip_1627.jpg" alt="" /></p>            <p>　　图9</p>            <p>　　选择&ldquo;使用模板中的数据库文件位置&rdquo;，单击&ldquo;下一步&rdquo;，会出现&ldquo;恢复配置&rdquo;对话框，该对话框用于指定数据库的恢复选项，如图10：<br />            　<img src="http://img.ddvip.com/2007_05/1179043017_ddvip_438.jpg" alt="" /></p>            <p>　　图10</p>            <p>　　快速恢复区用于恢复数据，以免系统发生故障时丢失数据；启用归档用于将数据库设置为ARCHIVELOG模式，使得当数据库出现失败时可以完全恢复数据库数据。<br />            <br />            　　单击&ldquo;下一步&rdquo;，会出现&ldquo;数据库内容&rdquo;对话框，该对话框用指定是否安装示例方案，并运行自定义脚本。如图11：<br />            <br />            <img src="http://img.ddvip.com/2007_05/1179043022_ddvip_1787.jpg" width="740" border="undefined" alt="" /><br />            <br />            图11</p>            <p>　　单击&ldquo;下一步&rdquo;，会出现&ldquo;初始化参数&rdquo;对话框，该对话框用配置初始化参数、数据库字符集和连接模式。如图12：<br />            　　<img src="http://img.ddvip.com/2007_05/1179043027_ddvip_6772.jpg" alt="" /></p>            <p>　　图12</p>            <p>　　这里的内容相对初学者来说有垫补好理解，放到后面讲解。</p>            <p>　　单击&ldquo;下一步&rdquo;，会出现&ldquo;数据库存储&rdquo;对话框，该对话框用指定控制文件、数据文件、重做日志文件、名称和尺寸。如图13：<br />            　　<img src="http://img.ddvip.com/2007_05/1179043034_ddvip_4673.jpg" alt="" /></p>            <p>　　图13</p>            <p>　　单击&ldquo;下一步&rdquo;，会出现&ldquo;创建选项&rdquo;对话框，该对话框用指定建立数据库，还是保存为数据库模板。如图14：<br />            　　<img src="http://img.ddvip.com/2007_05/1179043040_ddvip_6934.jpg" alt="" /></p>            <p>　图14</p>            <p>　　单击&ldquo;完成&rdquo;，会显示&ldquo;确认&rdquo;对话框，列出了要安装Oracle选项的所有信息。如图15：<br />            　　<img src="http://img.ddvip.com/2007_05/1179043045_ddvip_9795.jpg" alt="" /></p>            <p>　　图15</p>            <p>　　单击&ldquo;确定&rdquo;，就完成数据库的建立过程。就会开始数据库的建立，如图16：<br />            <br />            <img src="http://img.ddvip.com/2007_05/1179043050_ddvip_4667.jpg" width="740" border="undefined" alt="" /><br />            <br />            图16</p>            <p>　　当数据库建立完成后，就会出现如下对话框，如图17：<br />            　　<img src="http://img.ddvip.com/2007_05/1179043055_ddvip_7065.jpg" alt="" /></p>            <p>　　图17</p>            <p>　　当建立完成数据库后，系统会锁定除SYS、SYSTEM、DBSNMP、SYSMAN之外的所有其他用户。应为以后要使用SCOTT用户，所以在点击&ldquo;口令管理&rdquo;按钮后，解锁SCOTT用户，如图18：<br />            　　<img src="http://img.ddvip.com/2007_05/1179043064_ddvip_1496.jpg" alt="" /></p>            <p>　　图18</p>            <p>　　指定用户口令为TIGER，单击&ldquo;确定&rdquo;按钮，最后单击&ldquo;退出&rdquo;按钮完成数据库建立的全部过程。</p>            </div>            </td>        </tr>    </tbody></table></p>]]></description><category>Java</category><comments>http://www.augweb.net/blog/post/224.html#comment</comments><wfw:comment>http://www.augweb.net/blog/</wfw:comment><wfw:commentRss>http://www.augweb.net/blog/feed.asp?cmt=224</wfw:commentRss><trackback:ping>http://www.augweb.net/blog/cmd.asp?act=tb&amp;id=224&amp;key=c60f21e6</trackback:ping></item><item><title>eclipse汉化 大家来参与</title><author>lorrons@gmail.com (lorron)</author><link>http://www.augweb.net/blog/post/91.html</link><pubDate>Wed, 19 Nov 2008 14:30:38 +0800</pubDate><guid>http://www.augweb.net/blog/post/91.html</guid><description><![CDATA[<p><a href="https://babel.eclipse.org/babel/login.php">https://babel.eclipse.org/babel/login.php</a></p>]]></description><category>Java</category><comments>http://www.augweb.net/blog/post/91.html#comment</comments><wfw:comment>http://www.augweb.net/blog/</wfw:comment><wfw:commentRss>http://www.augweb.net/blog/feed.asp?cmt=91</wfw:commentRss><trackback:ping>http://www.augweb.net/blog/cmd.asp?act=tb&amp;id=91&amp;key=59e55c18</trackback:ping></item><item><title>java,jsp,sevlet,struts,ajax乱码最终解决方案</title><author>lorrons@gmail.com (lorron)</author><link>http://www.augweb.net/blog/post/90.html</link><pubDate>Tue, 11 Nov 2008 05:15:48 +0800</pubDate><guid>http://www.augweb.net/blog/post/90.html</guid><description><![CDATA[<div class="tit">java,jsp,sevlet,struts,ajax乱码最终解决方案</div><p><table style="table-layout: fixed">    <tbody>        <tr>            <td>            <div class="cnt" id="blog_text">            <p><font size="3">乱码问题好像跟我们中国程序员特别有缘，一直困扰着我们，从开始的<span style="font-size: 10pt">JSP</span><span style="font-size: 10pt"><font face="宋体">乱码问题，</font></span><span style="font-size: 10pt">STRUTS</span><span style="font-size: 10pt"><font face="宋体">乱码问题，到现在的</font></span><span style="font-size: 10pt">AJAX</span><span style="font-size: 10pt"><font face="宋体">乱码问题，无一不是搞得许多程序员焦头烂额的，整天骂</font></span><span style="font-size: 10pt">XXX</span><span style="font-size: 10pt"><font face="宋体">产品对中文支持不了，UTF-8无法使用中文啊什么的，其实这里面被骂的产品中其实</font></span><span style="font-size: 10pt">99</span><span style="font-size: 10pt"><font face="宋体">％以上是对中文支持非常好的，而出现乱码的原因只是因为自身对国际化支持以及文件编码等信息的认识不知造成的。要知道一个产品那么流行，怎么可能对中文支持不了呢，下面就开始一一帮大家解决这些问题。</font></span> </font><span style="font-size: 10pt"><br />            <br />            <font size="3">1</font></span><font size="3"> <span style="font-size: 10pt"><font face="宋体">、编码</font> </span></font><span style="font-size: 10pt"><br />            <font size="3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; －－</font></span><font size="3"> <span style="font-size: 10pt"><font face="宋体">想要解决好中文问题，对编码肯定是不能一概不懂了，编码是解决中文乱码问题的根本。</font> </span></font><span style="font-size: 10pt"><br />            <font size="3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font></span><font size="3"> <span style="font-size: 10pt"><font face="宋体">编码比较常用的有：</font> </span><span style="font-size: 10pt">UTF-8</span> <span style="font-size: 10pt"><font face="宋体">，</font> </span><span style="font-size: 10pt">GBK</span> <span style="font-size: 10pt"><font face="宋体">，</font> </span><span style="font-size: 10pt">GB2312</span> <span style="font-size: 10pt"><font face="宋体">，</font> </span><span style="font-size: 10pt">ISO-8859-1</span> <span style="font-size: 10pt"><font face="宋体">，除了</font> </span><span style="font-size: 10pt">iso-8859-1</span> <span style="font-size: 10pt"><font face="宋体">之外的其它三个编码都能很好的支持中文，但它们都兼容</font> </span><span style="font-size: 10pt">ISO-8859-1</span> <span style="font-size: 10pt"><font face="宋体">的编码（就是说无论编码怎么改变，只要是</font> </span><span style="font-size: 10pt">ISO-8859-1</span> <span style="font-size: 10pt"><font face="宋体">中的字符，永远不会出现乱码）。</font> </span></font><span style="font-size: 10pt"><br />            <font size="3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font></span><font size="3"><span style="font-size: 10pt"><font face="宋体">这四种编码中，</font> </span><span style="font-size: 10pt; mso-font-kerning: 1.0pt">GB2312</span> <span style="font-size: 10pt; mso-ascii-: 1.0pt"><font face="宋体">是中国规定的汉字编码，也可以说是简体中文的字符集编码</font> </span><span style="font-size: 10pt; mso-font-kerning: 1.0pt">;</span> <span style="font-size: 10pt">GBK </span><span style="font-size: 10pt"><font face="宋体">是</font> </span><span style="font-size: 10pt">GB2312</span> <span style="font-size: 10pt"><font face="宋体">的扩展</font> </span><span style="font-size: 10pt">,</span> <span style="font-size: 10pt; mso-ascii-: 1.0pt"><font face="宋体">除了兼容</font> </span><span style="font-size: 10pt; mso-font-kerning: 1.0pt">GB2312</span> <span style="font-size: 10pt; mso-ascii-: 1.0pt"><font face="宋体">外，它还能显示繁体中文，还有日文的假名</font> </span><span style="font-size: 10pt; mso-font-kerning: 1.0pt">;</span> <span style="font-size: 10pt"><font face="宋体">而</font> </span><span style="font-size: 10pt">UTF-8</span> <font face="宋体"><span style="font-size: 10pt">虽然也支持中文，但却</span> <span style="font-size: 10pt; mso-ascii-: 1.0pt">与</span> </font><span style="font-size: 10pt; mso-font-kerning: 1.0pt">GB</span> <font face="宋体"><span style="font-size: 10pt; mso-ascii-: 1.0pt">码不兼容（编码值不同）</span> <span style="font-size: 10pt">。</span> </font><span style="font-size: 10pt">UTF-8</span> <span style="font-size: 10pt"><font face="宋体">使用的是可变长的</font> </span><span style="font-size: 10pt">UNICODE</span> <span style="font-size: 10pt"><font face="宋体">编码，编码可能是</font> </span><span style="font-size: 10pt">1</span> <span style="font-size: 10pt"><font face="宋体">位</font> </span><span style="font-size: 10pt">16</span> <span style="font-size: 10pt"><font face="宋体">进制（即</font> </span><span style="font-size: 10pt">ISO-8859-1</span> <span style="font-size: 10pt"><font face="宋体">中的字符，其编码也是相同的）也有可能是</font> </span><span style="font-size: 10pt">2</span> <span style="font-size: 10pt"><font face="宋体">位或</font> </span><span style="font-size: 10pt">3</span> <span style="font-size: 10pt"><font face="宋体">位的</font> </span><span style="font-size: 10pt">16</span> <span style="font-size: 10pt"><font face="宋体">进制。</font> </span><span style="font-size: 10pt; mso-font-kerning: 1.0pt">UTF-8</span> <span style="font-size: 10pt; mso-ascii-: 1.0pt"><font face="宋体">的优点是：</font> </span><span style="font-size: 10pt; mso-font-kerning: 1.0pt">1</span> <font face="宋体"><span style="font-size: 10pt; mso-ascii-: 1.0pt">、</span> <span style="font-size: 10pt; mso-ascii-: 1.0pt">与</span> </font><span style="font-size: 10pt; mso-font-kerning: 1.0pt">CPU</span> <span style="font-size: 10pt; mso-ascii-: 1.0pt"><font face="宋体">字节顺序无关</font> </span><span style="font-size: 10pt; mso-font-kerning: 1.0pt">, </span><span style="font-size: 10pt; mso-ascii-: 1.0pt"><font face="宋体">可以在不同平台之间交流。</font> </span><span style="font-size: 10pt; mso-font-kerning: 1.0pt">2</span> <span style="font-size: 10pt; mso-ascii-: 1.0pt"><font face="宋体">、容错能力高</font> </span><span style="font-size: 10pt; mso-font-kerning: 1.0pt">, </span><span style="font-size: 10pt; mso-ascii-: 1.0pt"><font face="宋体">任何一个字节损坏后</font> </span><span style="font-size: 10pt; mso-font-kerning: 1.0pt">, </span><span style="font-size: 10pt; mso-ascii-: 1.0pt"><font face="宋体">最多只会导致一个编码码位损失</font> </span><span style="font-size: 10pt; mso-font-kerning: 1.0pt">, </span><span style="font-size: 10pt; mso-ascii-: 1.0pt"><font face="宋体">不会链锁错误</font> </span><span style="font-size: 10pt; mso-font-kerning: 1.0pt">(</span> <span style="font-size: 10pt; mso-ascii-: 1.0pt"><font face="宋体">如</font> </span><span style="font-size: 10pt; mso-font-kerning: 1.0pt">GB</span> <span style="font-size: 10pt; mso-ascii-: 1.0pt"><font face="宋体">码错一个字节就会整行乱码</font> </span><span style="font-size: 10pt; mso-font-kerning: 1.0pt">)</span> <span style="font-size: 10pt; mso-ascii-: 1.0pt"><font face="宋体">，所以在国际化处理中基本都是建议使用</font> </span><span style="font-size: 10pt; mso-font-kerning: 1.0pt">UTF-8</span> </font><span style="font-size: 10pt; mso-ascii-: 1.0pt"><font face="宋体" size="3">作为编码。<br />            </font></span><span style="font-size: 10pt"><br />            <font size="3">2、文件的编码</font><span style="font-size: 10pt"><br />            <font size="3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; －－虽然说只要设置了正确的编码就可以使字符正确显示了，但如果忽略了文件保存时的编码的话，那可是会让你走进迷雾中的。</font><span style="font-size: 10pt"><br />            <font size="3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 文件编码最常使用的有两种：ANSI和UTF-8，光看名字估计你都可以猜到了，ANSI就是我们保存文件时使用的默认编码，而UTF-8则需自己设置。对于编码的改变，我使用的工具是NOTEPAD和ECLIPSE，NOTEPAD使用最简单，只要打开文件后在另存为中选择相应的编码就行了，而且它对编码的支持非常好;而在ECLIPSE中，只要稍微设置一下就行了，打开首选项，然后选择：常规-&gt;内容类型(ContentType)，在右边选中你想改变保存编码的文件类型，然后在下方的缺省编码中改变其值，最后点击更新（UPDATE）按钮即可。<br />            </font></span></span></span></p>            <p align="center"><font size="3"><img height="567" width="613" alt="" src="http://www.augweb.net/blog/upload/eclipse.png" /> </font></p>            <p align="left"><br />            <br />            <font size="3">而在其它的编辑器中，默认保存的内容都是GB2312或者GBK（NOTEPAD中对应ANSI）.而根据前面所说的UTF-8和GBK,GB2312等的编码值是不同的这一点，可以知道，如果文件使用了UTF-8，那么字符编码就必须使用UTF-8，否则编码值的不同就可能造成乱码。而这也就是为什么那么多的人使用了UTF-8编码后还会产生乱码的根本原因。（JS和JSP都是这个道理）<br />            <br />            3、JSP,STRUTS等的中文乱码解决方案</font><span style="font-size: 10pt"><br />            <font size="3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 其实解决的方法只有一个：</font></span></p>            <div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><font size="3"><img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" /> <span style="color: #000000">request.setCharacterEncoding(encoding);</span> </font></div>            <p align="left"><font size="3">&nbsp;&nbsp;&nbsp; 方法只有一种，但处理方式就多种多样了，初学者会在JSP页面上直接使用，而有经验的程序员会使用过滤器。而现在所要说的方法也是过滤器。这里以统一使用UTF-8作为编码作为例子说明。具体过程就不多说了，网上有很多教程。偷懒一点的，到TOMCAT中复制就行了。在TOMCAT的目录下的\webapps\jsp-examples\WEB-INF\classes\filters\找到SetCharacterEncodingFilter.java 这个类，放到你的程序中并配置好映射路径。配置好后基本上你的乱码问题就解决了。但要映射路径中需要注意的就是不能使用 '*'</font></p>            <div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><font size="3"><img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" /> <span style="color: #000000">&nbsp;&nbsp;</span> <span style="color: #0000ff">&lt;</span> <span style="color: #800000">filter-mapping</span> <span style="color: #0000ff">&gt;</span> </font><span style="color: #000000"><br />            <font size="3"><img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</font></span><font size="3"> <span style="color: #0000ff">&lt;</span> <span style="color: #800000">filter-name</span> <span style="color: #0000ff">&gt;</span> <span style="color: #000000">Set Character Encoding</span> <span style="color: #0000ff">&lt;/</span> <span style="color: #800000">filter-name</span> <span style="color: #0000ff">&gt;</span> </font><span style="color: #000000"><br />            <font size="3"><img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</font></span><font size="3"> <span style="color: #0000ff">&lt;</span> <span style="color: #800000">servlet-name</span> <span style="color: #0000ff">&gt;</span> <span style="color: #000000">*</span> <span style="color: #0000ff">&lt;/</span> <span style="color: #800000">servlet-name</span> <span style="color: #0000ff">&gt;</span> </font><span style="color: #000000"><br />            <font size="3"><img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" />&nbsp;&nbsp;</font></span><font size="3"> <span style="color: #0000ff">&lt;/</span> <span style="color: #800000">filter-mapping</span> <span style="color: #0000ff">&gt;</span> </font></div>            <p align="left"><font size="3">像上面这样配置的话(可能也是网上大多教程的做法，想当年也是害苦了我)，可能你只有JSP的乱码解决了，要解决STRUTS的乱码需要映射 *.do 或者 servletActionName。然后在初始化参数中设置encoding的值就行了。</font></p>            <div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><font size="3"><img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" /> <span style="color: #0000ff">&lt;</span> <span style="color: #800000">init-param</span> <span style="color: #0000ff">&gt;</span> </font><span style="color: #000000"><br />            <font size="3"><img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font></span><font size="3"> <span style="color: #0000ff">&lt;</span> <span style="color: #800000">param-name</span> <span style="color: #0000ff">&gt;</span> <span style="color: #000000">encoding</span> <span style="color: #0000ff">&lt;/</span> <span style="color: #800000">param-name</span> <span style="color: #0000ff">&gt;</span> </font><span style="color: #000000"><br />            <font size="3"><img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font></span><font size="3"> <span style="color: #0000ff">&lt;</span> <span style="color: #800000">param-value</span> <span style="color: #0000ff">&gt;</span> <span style="color: #000000">UTF-8</span> <span style="color: #0000ff">&lt;/</span> <span style="color: #800000">param-value</span> <span style="color: #0000ff">&gt;</span> </font><span style="color: #000000"><br />            <font size="3"><img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" /> </font></span><font size="3"><span style="color: #0000ff">&lt;/</span> <span style="color: #800000">init-param</span> <span style="color: #0000ff">&gt;</span> </font></div>            <p align="left"><font size="3">当然，最重要的是要记得根据前面所说的方法，改变你所使用的编辑器保存文件的编码要与使用的字符编码一致。<br />            而在JSP内容中，还是使用如网上教程所说的那种技俩，在所有页面的页首加入：</font></p>            <div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><font size="3"><img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" /> <span style="color: #808080">&lt;%</span> <span style="color: #000000">@ page language</span> <span style="color: #808080">=</span> <span style="color: #000000">&quot;java&quot; contentType</span> <span style="color: #808080">=</span> <span style="color: #000000">&quot;</span> <span style="font-weight: bold; color: #000000">text</span> <span style="color: #808080">/</span> <span style="color: #000000">html; charset</span> <span style="color: #808080">=</span> <span style="color: #000000">UTF</span> <span style="color: #808080">-</span> <span style="font-weight: bold; color: #800000">8</span> </font><font size="3"><span style="color: #000000">&quot;<br />            <img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;&nbsp; pageEncoding</span> <span style="color: #808080">=</span> <span style="color: #000000">&quot;UTF</span> <span style="color: #808080">-</span> <span style="font-weight: bold; color: #800000">8</span> <span style="color: #000000">&quot;</span> <span style="color: #808080">%&gt;</span> </font></div>            <br />            <font size="3">至此，相信JSP,ACTION都不太可能出现乱码了。<br />            <br />            4、资源文件的乱码解决方案<br />            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 资源文件谁都知道是国际化支持不可或缺的一部分，如果资源文件都出现乱码了那还了得？其实资源文件的乱码是很好解决的，其原因也是因为使用了UTF-8做为JSP编码后，没有相应地改变资源文件的文件编码造成的，所以只要对资源文件保存的编码进行更正后，乱码问题也就解决了。当然，你的中文要使用 native2ascii 命令进行正确的转换。<br />            <br />            5、调用JS时，JS内容乱码的解决方案。<br />            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 其实JS的乱码还是跟文件的编码有关系的，如果JS中有中文的话，那JS文件保存的编码就必须跟调用此JS的页面编码相同，否则，你的所有中文都要从JSP页面传给JS才会显示正常。可以看出对于调用JS出现的乱码是最容易解决的（也是建立在前面的辛苦之下的）。<br />            <br />            6、AJAX提交数据乱码，返回数据乱码的解决方案<br />            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 随着AJAX的流行，乱码问题也开始困扰着许多刚开始使用它的程序员，幸好我之前对JSP乱码有过一点研究，在遇到AJAX后，并没有给我带来多大的困扰，在此将我的一些心得共享给大家。<br />            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 万变不离其宗，AJAX的乱码问题自然跟编码有关了，其实很多人跟我一样想到了对文件编码进行设置，并且在接数据时设置了requet的编码，在返回的数据时设置了response的编码一切都以为会很顺利，可是这一切都是徒劳无功的，讨厌的乱码再一次出现在你眼前。在你试了N多种方法，包括JS自身的escape,unescape方法后，你发现乱码仍然猖狂地出现在屏幕上。<br />            &nbsp;&nbsp;&nbsp;&nbsp; 其实在试过这N多方法后，很多人都没发现，解决的方法其实很简单，而且其答案就在我们之前处理的JSP乱码之中。让我们先看一下AJAX的经典请求代码<br />            </font><span style="font-size: 10pt"><font face="宋体">            <p>&nbsp;</p>            <div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><font size="3"><img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" /><span style="color: #000000">xmlhttp.open( </span><span style="color: #000000">&quot;</span><span style="color: #000000">post</span><span style="color: #000000">&quot;</span></font><font size="3"><span style="color: #000000">, url, async );<br />            <img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" />xmlhttp.setRequestHeader( </span><span style="color: #000000">&quot;</span><span style="color: #000000">Content-Type</span><span style="color: #000000">&quot;</span><span style="color: #000000">, </span><span style="color: #000000">&quot;</span><span style="color: #000000">text/html</span><span style="color: #000000">&quot;</span></font><span style="color: #000000"><font size="3"> );<br />            <img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" />xmlhttp.send( params );</font></span></div>            <br />            <font size="3">通过前面的说明，不知道你现在看出端倪了没有。不知道是受了网上教程的影响还是其它方面影响，setRequestHeader并是万年不变的，也没人想过去改它，而问题就正好出在这个地方。回想一个JSP页面内容的编码设置，其中有这么一节： </font>            <div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><font size="3"><img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" /><span style="color: #000000">contentType</span><span style="color: #000000">=</span><span style="color: #000000">&quot;</span><span style="color: #000000">text/html; charset=UTF-8</span><span style="color: #000000">&quot;</span></font></div>            <br />            <font size="3">现在知道问题了吧，所以我们要把第二句代码改为： </font>            <div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><font size="3"><img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" /><span style="color: #000000">xmlhttp.setRequestHeader( </span><span style="color: #000000">&quot;</span><span style="color: #000000">Content-Type</span><span style="color: #000000">&quot;</span><span style="color: #000000">, </span><span style="color: #000000">&quot;</span><span style="color: #000000">text/html;charset=UTF-8</span><span style="color: #000000">&quot;</span><span style="color: #000000"> );<img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" /></span></font></div>            </font></span><br />            <font face="宋体, MS Song" size="3">最后别忘了在返回数据时也设置上： </font>            <div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><font size="3"><font face="宋体, MS Song"><img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" /></font><span style="color: #000000">response.setContentType( </span><span style="color: #000000">&quot;</span><span style="color: #000000">text/xml</span><span style="color: #000000">&quot;</span></font><font size="3"><span style="color: #000000"> );<br />            <img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" />response.setCharacterEncoding( </span><span style="color: #000000">&quot;</span><span style="color: #000000">UTF-8</span><span style="color: #000000">&quot;</span><span style="color: #000000"> );</span></font></div>            <br />            <font size="3">是不是很简单，一点都不麻烦呢？<br />            如果要问为什么的话，其实我们可以把xmlhttp看成是一个临时页面，它由浏览器动态生成，主要作用是在后台获得请求的数据（可以看成是一个高级的iframe）。所以对于普通页面设置的编码，对它也要同样设置。而在servlet中返回数据为什么要设置contentType和encoding其道理也是一样的。众所周知，jsp的最后形态就是servlet，而jsp页首设置的那个内容其实也就是让生成的servlet中生成这么两句话：<br />            </font>            <div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><font size="3"><img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" /><span style="color: #000000">response.setContentType( </span><span style="color: #000000">&quot;</span><span style="color: #000000">text/html</span><span style="color: #000000">&quot;</span></font><font size="3"><span style="color: #000000"> );<br />            <img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" />response.setCharacterEncoding( </span><span style="color: #000000">&quot;</span><span style="color: #000000">UTF-8</span><span style="color: #000000">&quot;</span><span style="color: #000000"> );</span></font></div>            <br />            <font size="3">而pageEncoding则是跟jvm说明了这个页面的内容要使用什么编码保存（这跟之后生成的CLASS有关系）。所以在servlet设置response的编码也是理所当然的了。<br />            <br />            一口气把自己一年以来遇到的乱码问题和解决的方案写出来了，希望对你有所帮助。</font></div>            </td>        </tr>    </tbody></table></p><p><img title="" alt="" src="http://www.augweb.net/blog/upload/eclipse.png" onload="ResizeImage(this,520)" /></p>]]></description><category>Java</category><comments>http://www.augweb.net/blog/post/90.html#comment</comments><wfw:comment>http://www.augweb.net/blog/</wfw:comment><wfw:commentRss>http://www.augweb.net/blog/feed.asp?cmt=90</wfw:commentRss><trackback:ping>http://www.augweb.net/blog/cmd.asp?act=tb&amp;id=90&amp;key=f9f1ffc4</trackback:ping></item><item><title>Struts 学习笔记之Action</title><author>lorrons@gmail.com (lorron)</author><link>http://www.augweb.net/blog/post/89.html</link><pubDate>Sun, 28 Sep 2008 06:26:57 +0800</pubDate><guid>http://www.augweb.net/blog/post/89.html</guid><description><![CDATA[<p>下面是Struts中的一些常用Action如DispatchAction/LookupDispatchAction/MappingDispatchAction/ForwardAction/IncludeAction的总结</p><p>1 ．DispatchAction extends BaseAction</p><p>一般的Action如&lt;action path=&quot;/createUser&quot; type=&quot;examples.UserAction&quot;&gt;，在这里UserAction只需要继承父类（extends Action类），然后重写父类的execute方法，在execute中实现具体的控制转向。</p><p>对于同一个formbean上进行的新增、修改、删除等，我们需要分发不同的Action，这里有两种做法。</p><p><b>① </b>一种是通过在execute方法中if判断进行不同的转向：</p><p>㈠ UserAction 类的execute方法中</p><p>String method = <b>request.getParameter(&quot;method&quot;)</b>;</p><p>if (method.equals(&quot;create&quot;)) {</p><p>&hellip;&hellip;</p><p>return mapping.findForward(&quot;createUser&quot;);</p><p>}</p><p>if (method.equals(&quot;save&quot;)) {</p><p>&hellip;&hellip;</p><p>return mapping.findForward(&quot;saveUser&quot;);</p><p>}</p><p>㈡ struts-config.xml 中：</p><p>&lt;action path=&quot;/createUser&quot; type=&quot;examples.UserAction&quot;</p><p>name=&quot;userForm&quot;</p><p>scope=&quot;request&quot;&gt;</p><p>&lt;forward name=&quot;createUser&quot; path=&quot;/pages/listUser.jsp&quot;/&gt;</p><p>&lt;/action&gt;</p><p>&lt;action path=&quot;/saveUser&quot; type=&quot;examples.UserAction&quot;</p><p>name=&quot;userForm&quot;</p><p>scope=&quot;request&quot;&gt;</p><p>&lt;forward name=&quot;saveUser&quot; path=&quot;/pages/saveUser.jsp&quot;/&gt;</p><p>&lt;/action&gt;</p><p>㈢ 可以在页面中定义一个隐藏变量来指明相应的操作</p><p>// 这里最好不要使用&lt;html:hidden property=&quot;<b>method</b>&quot;/&gt;</p><p>// 因为这种写法需要在formbean中定义相应的property，我们可以采用普通隐藏域</p><p>&lt;input type=&quot;hidden&quot; name=&quot;<b>method</b>&quot;/&gt;</p><p>然后定义一个javascript函数，我们可以在通过点击提交按钮的时候，在函数中修改它的值。</p><p>&lt;script&gt;</p><p>function set(operation) {</p><p>with (document.forms[0]) {</p><p>method.value = operation;</p><p>}</p><p>}</p><p>&lt;/script&gt;</p><p>点击提交按钮时，通过set方法设置提交的method属性值：</p><p>&lt;html:submit onclick=&quot;set('create');&quot;&gt;CREATE&lt;/html:submit&gt;</p><p>&lt;html:submit onclick=&quot;set('save');&quot;&gt;SAVE&lt;/html:submit&gt;</p><p><b>② </b>第二就是使UserAction继承DispatchAction，不需要重写execute方法:</p><p>public ActionForward <b>create</b>(ActionMapping mapping,</p><p>ActionForm form,</p><p>HttpServletRequest request,</p><p>HttpServletResponse response)</p><p>throws Exception {</p><p>// 進行一些create的逻辑</p><p>// &hellip;&hellip;</p><p>return mapping.findForward(&quot;createUser&quot;);</p><p>}</p><p>public ActionForward <b>save</b>(ActionMapping mapping,</p><p>ActionForm form,</p><p>HttpServletRequest request,</p><p>HttpServletResponse response)</p><p>throws Exception {</p><p>// 進行一些save的逻辑</p><p>// &hellip;&hellip;</p><p>return mapping.findForward(&quot;saveUser&quot;);</p><p>}</p><p>㈡ DispatchAction 在配置上和一般Action稍有不同，就是要在Action配置中多一个parametr属性，这个属性可以指定执行DispatchAction中对应的方法。</p><p>struts-config.xml 中：</p><p>&lt;action path=&quot;<b>/processUser</b>&quot; type=&quot;examples.UserAction&quot;</p><p>name=&quot;userForm&quot;</p><p>scope=&quot;request&quot;</p><p><b>parameter</b>=&quot;<b>method</b>&quot;&gt;</p><p>&lt;forward name=&quot;createUser&quot; path=&quot;/pages/listUser.jsp&quot;/&gt;</p><p>&lt;forward name=&quot;saveUser&quot; path=&quot;/pages/saveUser.jsp&quot;/&gt;</p><p>&lt;/action&gt;</p><p>㈢ 我们在这里指定了parameter的值为<b>method</b>，则页面提交时我们必须指定提交时action的method参数来确定去我们想要调用哪个Action方法。</p><p>&lt;script&gt;</p><p>function submitForm(operation) {</p><p>with (document.forms[0]) {</p><p>action = action + '?method = '+ operation;</p><p>submit();</p><p>}</p><p>}</p><p>&lt;/script&gt;</p><p>点击提交按钮时，通过submitForm方法设置提交时action的method参数：</p><p>&lt;html:form action=&quot;<b>/processUser</b>&quot; method=&quot;get&quot;&gt;</p><p>&lt;html:button onclick=&quot;submitForm('create');&quot;&gt;CREATE&lt;/html:button&gt;</p><p>&lt;html:button onclick=&quot;submitForm('save');&quot;&gt;SAVE&lt;/html:button&gt;</p><p>&lt;/html:form&gt;</p><p>2 ． LookupDispatchAction <b>extends DispatchAction</b></p><p>LookupDispatchAction 继承DispatchAction, 在上面的 <b>② </b>㈢ 中对于同一个页面上的多个submit按钮，不需要那么多复杂的js函数来指定提交时action的method参数，即上面的submitForm(operation)方法可以省去，LookupDispatchAction其用法为：</p><p><strong>①</strong> 用MessageResource将按钮的文本和ResKey相关联，例如button.save=保存； <strong>② </strong>㈢ 中用LookupDispatchAction代替就是:</p><p>&lt;html:form action=&quot;/processUser&quot; method=&quot;get&quot;&gt;</p><p>&lt;html:submit property=&quot; <strong>method</strong> &quot;&gt;</p><p>&lt;bean:message key=&quot; button.create &quot;/&gt;</p><p>&lt;/html:submit&gt;</p><p>&lt;html:submit property=&quot; <strong>method</strong> &quot;&gt;</p><p>&lt;bean:message key=&quot; button.save &quot;/&gt;</p><p>&lt;/html:submit&gt;</p><p>&lt;/html:form&gt;</p><p><strong>②</strong> 在Action配置中多一个parametr属性，属性值与submit按钮的property属性值相同，这个属性可以指定执行LookupDispatchAction中对应的方法。</p><p>struts-config.xml 中：</p><p>&lt;action path=&quot; <strong>/processUser</strong> &quot; type=&quot;examples.UserAction&quot;</p><p>name=&quot;userForm&quot;</p><p>scope=&quot;request&quot;</p><p><strong>parameter</strong>=&quot; <strong>method</strong> &quot;&gt;</p><p>&lt;forward name=&quot;createUser&quot; path=&quot;/pages/listUser.jsp&quot;/&gt;</p><p>&lt;forward name=&quot;saveUser&quot; path=&quot;/pages/saveUser.jsp&quot;/&gt;</p><p>&lt;/action&gt;</p><p><strong>③ </strong></p><p>使UserAction继承LookupDispatchAction，重写getKeyMethodMap()方法, 将ResKey和MethodName对应起来, 如下：</p><p>protected Map getKeyMethodMap() {</p><p>Map map = new HashMap();</p><p>map.put(&quot;button.create&quot;, &quot;create&quot;);</p><p>map.put(&quot;button.save&quot;, &quot;save&quot;);</p><p>return map;</p><p>}</p><p><b>注： </b>DispatchAction 类使用请求参数的值确定调用哪种方法，而LookupDispatchAction类利用请求参数值，反向查询资源绑定，并将它与类中的一种方法匹配，实际上这两种方法有异曲同工之处。</p><p>3 ． MappingDispatchAction <b>extends DispatchAction</b></p><p>DispatchAction 指定了parameter的值为<b>method</b>，则页面提交时我们必须指定提交时action的method参数来确定去我们想要调用哪个Action方法,而MappingDispatchAction直接通过struts-config.xml将多个action-mapping映射到同一个Action类的不同方法:</p><p>&lt;action path=&quot;/createUser&quot; type=&quot;examples.UserAction&quot;</p><p>name=&quot;userForm&quot;</p><p>scope=&quot;request&quot;</p><p><b>parameter=&quot;create&quot;</b>&gt;</p><p>&lt;forward name=&quot;createUser&quot; path=&quot;/pages/listUser.jsp&quot;/&gt;</p><p>&lt;/action&gt;</p><p>&lt;action path=&quot;/saveUser&quot; type=&quot;examples.UserAction&quot;</p><p>name=&quot;userForm&quot;</p><p>scope=&quot;request&quot;</p><p><b>parameter=&quot;save&quot;</b>&gt;</p><p>&lt;forward name=&quot;saveUser&quot; path=&quot;/pages/saveUser.jsp&quot;/&gt;</p><p>&lt;/action&gt;</p><p>然后UserAction继承MappingDispatchAction即可：</p><p>public ActionForward save(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception</p><p>public ActionForward edit(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception</p><p><b>注： </b>查看MappingDispatchAction的源码：</p><p>protected String getMethodName(ActionMapping mapping, ActionForm form,</p><p>HttpServletRequest request, HttpServletResponse response,</p><p>String parameter) throws Exception {</p><p>// Return the unresolved mapping parameter.</p><p>return parameter;</p><p>}</p><p>可以看到它调用的方法是直接返回struts-config.xml中parameter的值。</p><p>4 ． ForwardAction extends BaseAction</p><p>相当于&lt;jsp:forward&gt;功能，不需要配置formbean和action，可以直接进行跳转，只需要在struts-config.xml中配置：</p><p>&lt;action path=&quot;/listUser&quot;</p><p>type=&quot;org.apache.struts.actions.ForwardAction&quot;</p><p>scope=&quot;request&quot;</p><p>parameter=&quot;/pages/listUser.jsp&quot;&gt;</p><p>&lt;/action&gt;</p><p>parameter 属性用于指定forward到哪个页面，path、type、parameter三个属性为必须，其他可省略。</p><p>5 ． IncludeAction extends BaseAction</p><p>相当于&lt;jsp:include&gt;功能，需要在struts-config.xml中配置：</p><p>&lt;action path=&quot;/listUser&quot; type=&quot;org.apache.struts.actions.IncludeAction&quot;</p><p>name=&quot;userForm&quot;</p><p>scope=&quot;request&quot;</p><p>parameter=&quot;/pages/includepage.jsp&quot;&gt;</p><p>&lt;/action&gt;</p><p><b>转载</b></p><p><a href="http://www.blogjava.net/xiaodaoxiaodao/archive/2007/06/10/123141.html">http://www.blogjava.net/xiaodaoxiaodao/archive/2007/06/10/123141.html </a></p>]]></description><category>Java</category><comments>http://www.augweb.net/blog/post/89.html#comment</comments><wfw:comment>http://www.augweb.net/blog/</wfw:comment><wfw:commentRss>http://www.augweb.net/blog/feed.asp?cmt=89</wfw:commentRss><trackback:ping>http://www.augweb.net/blog/cmd.asp?act=tb&amp;id=89&amp;key=d898a42f</trackback:ping></item><item><title>Struts学习笔记之ActionForm</title><author>lorrons@gmail.com (lorron)</author><link>http://www.augweb.net/blog/post/88.html</link><pubDate>Sun, 28 Sep 2008 06:23:57 +0800</pubDate><guid>http://www.augweb.net/blog/post/88.html</guid><description><![CDATA[<p> <p><a href="http://www.blogjava.net/xiaodaoxiaodao/archive/2007/05/31/121264.html"></a></p> <p>Struts 中定义了一些JavaBeans，主要是以ActionForm为父类扩展开来的，如下图： <p><img height="223" alt="actionform.JPG" src="http://www.blogjava.net/images/blogjava_net/xiaodaoxiaodao/actionform.JPG" width="289" border="0"> <p>① <b>org.apache.struts.action包中 </b> <p>public abstract class <b>ActionForm</b> implements Serializable <p>public class <b>DynaActionForm</b> extends ActionForm implements DynaBean <p>② <b>org.apache.struts.validator包中 </b> <p>public class <b>ValidatorForm</b> extends ActionForm implements Serializable <p>public class <b>DynaValidatorForm</b> extends DynaActionForm <p>implements DynaBean, Serializable <p>③ <b>org.apache.struts.validator包中 </b> <p>public class <b>ValidatorActionForm</b> extends ValidatorForm implements Serializable <p>public class <b>DynaValidatorActionForm</b> extends DynaValidatorForm <p>implements DynaBean, Serializable <p>1 ． ActionForm中比较常用的两个方法是reset()和validator()： <p>// 恢复ActionForm属性的默认值，如把boolean型设为true/false，字符串设为null。 <p>public void <b>reset</b>( ActionMapping mapping, HttpServletRequest request ) { } <p>// validate 只检查数据格式和语法，不检查数据是否符合业务逻辑。 <p>public ActionErrors <b>validate</b>( ActionMapping mapping, HttpServletRequest request ) { return (null); } <p>这两个方法的默认实现是不执行任何操作，我们可以重写这两个方法来实现相关逻辑。 <p><b>注： </b>对于每个request，控制器都会先调用ActionForm的reset()方法，然后表单数据组装到ActionForm中。如ActionForm在request范围内，那么对于每个新的request请求都会创建新的ActionForm实例。新实例创建后，如果它的属性<b>已经被初始化为默认值</b>，那么接着再在reset()方法中把属性设为默认值不是很有必要，这时可以让reset()方法为空。 <p>对于session范围内的ActionForm，同一ActionForm实例会被多个请求共享，reset()方法在这种情况下极为有用。 <p>2 ． 其中，ActionForm需要我们创建一个formbean类继承ActionForm，在ActionForm中可以定义一些property和get/set方法。 <p>ActionForm 的property必须声明然后才可以使用，不过在查询时我们常常需要输入一些查询条件，这些查询条件（property）其实不需要在formbean中声明，这时可以使用Map对象来封装整个查询表单提交的数据，如下： <p>public class MapForm extends ActionForm { <p>private Map map = null; <p>public void setMap(Map map) { <p>this.map = map; <p>} <p>public Map getMap() { <p>return this.map; <p>} <p>// 增加查询条件（property）的get/set方法，并把数据放到Map中 <p>public void setAttribute(String attributeKey, Object attributeValue) { <p>map.put(attributeKey, attributeValue); <p>} <p>public Object getAttribute(String attributeKey) { <p>Object keyValue = map.get(attributeKey); <p>return keyValue; <p>} <p>} <p>在页面上可以通过 <p>&lt;html:text property="attribute(id)"/&gt; <p>来获取表单数据，这会调用getAttribute("id")方法。 <p>3 ． 其中，<b>Dyna</b>开头的动态ActionForm不需要创建具体的ActionForm类，只需通过Struts的配置文件就可以完成ActionForm的全部配置，如： <p>&lt;form-bean name="optionsForm" type="org.apache.struts.action.<b>DynaActionForm</b>"&gt; <p>&lt;form-property name="fruit1" type="java.lang.String" initial="Pear" /&gt; <p>&lt;form-property name="fruit2" type="java.lang.String" initial="Apple" /&gt; <p>&lt;/form-bean&gt; <p>4 ． 其中，含有<b>validator</b>的ActionForm用来进行表单验证，验证方法有两种。 <p><b>① </b>在struts-config.xml中设置action的validate属性为"true"（默认为"true"）， <p>&lt;action path="/updateUser" <p>type="com.cn.lively.action.UpdateUserAction" <p>name="userForm" <p>scope="request" <p>input="/jsp/updateUser.jsp" <p>cancellable="true" <p><b>validate="true" </b>&gt; <p>&lt;forward name="success" path="/jsp/validator/updateUserResults.jsp"/&gt; <p>&lt;/action&gt; <p>并且在相应的formbean中重写其中的<b>validate</b>方法，在<b>validate</b>方法中实现自己的数据验证逻辑。 <p><b>② </b>通过validation框架进行验证，这分为两步： <p><b>⑴ </b>在struts-config.xml中配置validation插件, <p>&lt;plug-in className="org.apache.struts.validator.ValidatorPlugIn"&gt; <p>&lt;set-property property="pathnames" <p>value="/org/apache/struts/validator/validator-rules.xml, <p>/WEB-INF/validation.xml" /&gt; <p>&lt;/plug-in&gt; <p><b>⑵ </b>配置formbean，有下面两种方法： <p>㈠ 使自己的formbean类继承含有<b>validator</b>的ActionForm <p>public class UserForm extends ValidatorForm{ <p>private String userName; <p>public String getUserName() { <p>return userName; <p>} <p>public void setUserName(String userName) { <p>this.userName = userName; <p>} <p>} <p>并配置struts-config.xml文件： <p>&lt;form-bean name="<b>userForm</b>" type="com.cn.lively.formbean.UserForm"&gt; <p>&lt;/form-bean&gt; <p>㈡ 使自己的formbean类继承含有<b>validator</b>的<b>DynaValidatorForm</b> <p>&lt;form-bean name="<b>userForm</b>" type="org.apache.struts.validator.<b>DynaValidatorForm</b>"&gt; <p>&lt;form-property name="userName" type="java.lang.String" /&gt; <p>&lt;/form-bean&gt; <p><b>⑶ </b>配置validation.xml文件： <p>&lt;formset&gt; <p>&lt;form name="<b>userForm</b>"&gt; <p>&lt;field property="userName" depends="required"&gt; <p>&lt;arg key="userForm.userName" /&gt; <p>&lt;/field&gt; <p>&lt;/form&gt; <p>&lt;/formset&gt; <p><b>注： </b>注意 validation.xml文件中的<b>userForm</b>是struts-config.xml文件中formbean的名字。 <p>关于arg的几个属性如下： <p>bundle ：指定资源文件名，如不指定，则从默认资源文件中读取 <p>key ：从资源文件 ActionResources.properties 中得到的值 <p>resource ：key所指定的信息是否来自外部的资源文件，默认为true。如果为true，则代表key为buddle属性所指定的资源文件中的key。 <p>position ，这个arg中的值用来替换信息中的哪一部分， 需要替换的部分以{n}标志。 <p>5 ． 关于<b>ValidatorForm/DynaValidatorForm</b>与<b>ValidatorActionForm/DynaValidatorActionForm</b>之间的区别 <p>对于一个actionform，可以被多个action所使用，而每个action可能需要的验证字段都不一样，而validation.xml中配置的验证方式（如&lt;form name="userForm"&gt;）是对这个formbean进行的. <p><b>① </b>如果需要<strong>针对每个action来验证</strong>，则必须使formbean继承<b>ValidatorActionForm</b>（或者直接配置<b>DynaValidatorActionForm</b>）。如下两种方法： <p>㈠ 使自己的formbean类继承含有<b>validator</b>的ActionForm <p>public class UserForm extends <b>ValidatorActionForm</b>{ <p>…… <p>} <p>并配置struts-config.xml文件： <p>&lt;form-bean name="<b>userForm</b>" type="com.cn.lively.formbean.UserForm"&gt; <p>&lt;/form-bean&gt; <p>&lt;action-mappings&gt; <p>&lt;action path="<b>/createUser</b>" <p>type="com.cn.lively.action.CreateUserAction" <p>name="<b>userForm</b>"/&gt; <p>&lt;action path="<b>/updateUser</b>" <p>type="com.cn.lively.action.UpdateUserAction" <p>name="<b>userForm</b>"/&gt; <p>&lt;/action-mappings&gt; <p>㈡ 使自己的formbean类继承含有<b>validator</b>的<b>DynaValidatorActionForm</b> <p>&lt;form-bean name="<b>userForm</b>" type="org.apache.struts.validator.<b>DynaValidatorActionForm</b>"&gt; <p>&lt;form-property name="userName" type="java.lang.String" /&gt; <p>&lt;/form-bean&gt; <p>&lt;action-mappings&gt; <p>&lt;action path="<b>/createUser</b>" <p>type="com.cn.lively.action.CreateUserAction" <p>name="<b>userForm</b>"/&gt; <p>&lt;action path="<b>/updateUser</b>" <p>type="com.cn.lively.action.UpdateUserAction" <p>name="<b>userForm</b>"/&gt; <p>&lt;/action-mappings&gt; <p><b>② </b>配置validation.xml文件： <p>&lt;formset&gt; <p>&lt;form name="<b>/createUser</b>"&gt; <p>&lt;field property="userName" depends="required"&gt; <p>&lt;arg key="userForm.userName" /&gt; <p>&lt;/field&gt; <p>&lt;/form&gt; <p>&lt;form name="<b>/updateUser</b>"&gt; <p>&lt;field property="userName" depends="maxlength"&gt; <p>&lt;arg key="userForm.userName" /&gt; <p>&lt;arg key="prompt.max" position="0"/&gt; <p>&lt;arg name="maxlength" key="${var:maxlength}" resource="false" position="1" /&gt; <p>&lt;var&gt; <p>&lt;var-name&gt;maxlength&lt;/var-name&gt; <p>&lt;var-value&gt;10&lt;/var-value&gt; <p>&lt;/var&gt; <p>&lt;/field&gt; <p>&lt;/form&gt; <p>&lt;/formset&gt; <p><b>注： </b>注意validation.xml文件中的<b>/createUser</b>和<b>/updateUser</b>是struts-config.xml文件中action的path路径。 <p>如果我们查看struts源码，可以很清楚的看到<b>ValidatorForm/DynaValidatorForm</b>与<b>ValidatorActionForm/DynaValidatorActionForm</b>之间的区别 <p>ValidatorForm 中的方法 <p>* <b>@return </b>validation key - the form element's name in this case <p><b>public </b>String getValidationKey(ActionMapping mapping, <p>HttpServletRequest request) { <p><b>return </b>mapping.getAttribute(); // 返回formbean的名字 <p>} <p>Validator<b>ActionForm</b> 中的方法 <p>* <b>@return </b>validation key - the action element's 'path' attribute in this * case <p><b>public </b>String getValidationKey(ActionMapping mapping, <p>HttpServletRequest request) { <p><b>return </b>mapping.getPath(); // 返回action的路径 <p>} <p>7 ． 上面的验证是在服务器端进行，如需要在客户端进行js验证，需要在页面上配置： <p><b>① </b>&lt;html:form action="/ createUser" onsubmit="return validate<b>UserForm</b>(this);"&gt; <p>格式为 return validate + formbean名称(首字母大写) + (this) <p>用来在提交本页面时执行相应的js验证代码。 <p><b>② </b>用来生成本页面的 js 验证代码。 有两种方法： <p><b>⑴ </b>一是 在页面上声明 <p>&lt;%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %&gt; <p>&lt;html:javascript formName="<b>userForm</b>" dynamicJavascript="<b>true</b>" staticJavascript="<b>true</b>"/&gt; <p>因为dynamicJavascript/staticJavascript在<b>JavascriptValidatorTag</b>.java中默认为true，所以上面也可以直接写：&lt;html:javascript formName="<b>userForm</b>"/&gt; <p>struts-html.tld <p>&lt;tag&gt; <p>&lt;name&gt;javascript&lt;/name&gt; <p>&lt;tag-class&gt;org.apache.struts.taglib.html.<b>JavascriptValidatorTag</b>&lt;/tag-class&gt; <p>&lt;/tag&gt; <p><b>注： </b>在客户端执行的js验证如果不通过，会alert出对话框进行提示，服务器 端 的验证(在页面上可以用&lt;html:errors/&gt;来显示出错信息)就不会执行。 <p>注意<b>只有</b>dynamicJavascript="<b>true</b>" + staticJavascript="<b>true</b>" 才能生成完整的 js 验证代码 ，如果把任何一个设为"false"提交页面时都会产生js错误，除非我们采用下面<b>⑵</b><b></b>的方法进行声明。 <p><b>⑵ </b> <p>Ⅰ 在本页面上声明 <p>&lt;%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %&gt; <p>&lt;html:javascript formName="<b>userForm</b>" dynamicJavascript="<b>true</b>" staticJavascript="<b>false</b>"/&gt; <p>&lt;script language="Javascript1.1" src="staticJavascript.jsp"/&gt;&lt;/script&gt; <p>Ⅱ 定义staticJavascript.jsp的内容为 <p>&lt;%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %&gt; <p>&lt;html:javascript dynamicJavascript="<b>false</b>" staticJavascript="<b>true</b>"/&gt; <p><b>注： </b>dynamicJavascript 表示是否在页面内生成动态的js，staticJavascript属性代表是否在页面内生成静态js。 如staticJavascript设为"true"，则validator-rules.xml文件中的规则检查生成的js代码都会生成到本页面内。这样本页面会越来越大，一般最好是将staticJavascript设为"false"， 将validator-rules.xml生成的js代码填充到一个指定的jsp页面(staticJavascript.jsp)中去。 <p><b>附： </b> <p><b>只有 </b>dynamicJavascript="<b>true</b>" + staticJavascript="<b>true</b>" 才能生成完整的 js 验证代码 ，下面是<b>⑵</b> Ⅰ 中dynamicJavascript="<b>true</b>"生成的参考代码： <p>var bCancel = false; <p>function validateUserForm(form) { <p>if (bCancel) { <p>return true; <p>} else { <p>var formValidationResult; <p>// 调用staticJavascript.jsp中staticJavascript="true"生成的js代码 <p>formValidationResult = <b>validateByte</b>(form) &amp;&amp; <b>validateEmail</b>(form); <p>return (formValidationResult); <p>} <p>} <p>// validator-rules.xml 中定义了&lt;validator name="byte"  <p>// jsFunctionName=" ByteValidations "/&gt; <p>// 则生成js函数名称为 <b>formbean </b><b>名称 + 下划线 + jsFunctionName </b> <p>function <b>userForm_ByteValidations</b>() { <p>this.a0 = new Array("byteValue", "Byte must be a byte.", new Function ("varName", " return this[varName];")); <p>} <p>// validator-rules.xml 文件中没有定义jsFunctionName，&lt;validator name=" email "/&gt; <p>// 则生成js函数名称为 <b>formbean </b><b>名称 + 下划线 + validator name </b> <p>function <b>userForm_email</b>() { <p>this.a0 = new Array("email", "Email is an invalid e-mail address.", new Function ("varName", " return this[varName];")); <p>} <p>下面 是<b>⑵</b> Ⅱ 中 staticJavascript.jsp 中 staticJavascript="<b>true</b>" 生成的参考代码： <p>function <b>validateByte</b>(form) { <p>// …… <p>// 调用 <b>userForm_ </b><b>ByteValidations </b>() <p>// …… <p>} <p>function <b>validateEmail</b>(form) { <p>// …… <p>// 调用 <b>userForm_ </b><b>email </b>() <p>// …… <p>} <p>&nbsp; <p>&nbsp; <p><b>转载</b>  <p><a href="http://www.blogjava.net/xiaodaoxiaodao/archive/2007/05/31/121264.html">http://www.blogjava.net/xiaodaoxiaodao/archive/2007/05/31/121264.html </a></p>]]></description><category>Java</category><comments>http://www.augweb.net/blog/post/88.html#comment</comments><wfw:comment>http://www.augweb.net/blog/</wfw:comment><wfw:commentRss>http://www.augweb.net/blog/feed.asp?cmt=88</wfw:commentRss><trackback:ping>http://www.augweb.net/blog/cmd.asp?act=tb&amp;id=88&amp;key=29219b68</trackback:ping></item><item><title>struts+spring+hibernate下通用分页功能的实现</title><author>lorrons@gmail.com (lorron)</author><link>http://www.augweb.net/blog/post/87.html</link><pubDate>Sun, 28 Sep 2008 04:53:46 +0800</pubDate><guid>http://www.augweb.net/blog/post/87.html</guid><description><![CDATA[<p>1、定义通用分页model<br>package cn.com.bank.mmpf.model; <p>import cn.com.bank.mmpf.util.Constants; <p>/**<br> * Created by IntelliJ IDEA.<br> * User: willsu<br> * Date: 2005-6-10<br> * Time: 16:51:22<br> * To change this template use File | Settings | File Templates.<br> */<br>public class PageControl implements java.io.Serializable{<br>&nbsp;&nbsp;&nbsp; private int pageno=1;&nbsp; //当前页码<br>&nbsp;&nbsp;&nbsp; private int pagesize=Constants.PAGE_SIZE_DEFALUT; //每页行数<br>&nbsp;&nbsp;&nbsp; private int rowcount; //总行数<br>&nbsp;&nbsp;&nbsp; private int pagecount; //总页数<br>&nbsp;&nbsp;&nbsp; private boolean useprevious;//前一页是否能用<br>&nbsp;&nbsp;&nbsp; private boolean usebehind;//后一页是否能用<br>&nbsp;&nbsp;&nbsp; private boolean usepage=true;//是否分页 <p>&nbsp;&nbsp;&nbsp; public int getPageno() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return pageno;<br>&nbsp;&nbsp;&nbsp; } <p>&nbsp;&nbsp;&nbsp; public void setPageno(int pageno) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.pageno = pageno;<br>&nbsp;&nbsp;&nbsp; } <p>&nbsp;&nbsp;&nbsp; public int getPagesize() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return pagesize;<br>&nbsp;&nbsp;&nbsp; } <p>&nbsp;&nbsp;&nbsp; public void setPagesize(int pagesize) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (pagesize==0){//0--&gt;不分页<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; usepage=false;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pagecount=1;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pageno=1;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; useprevious=false;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; usebehind=false;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.pagesize = pagesize;<br>&nbsp;&nbsp;&nbsp; } <p>&nbsp;&nbsp;&nbsp; public int getRowcount() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return rowcount;<br>&nbsp;&nbsp;&nbsp; } <p>&nbsp;&nbsp;&nbsp; public void setRowcount(int rowcount) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.rowcount = rowcount;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(usepage){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pagecount=(rowcount % pagesize ==0 )?(rowcount /pagesize ) : ( rowcount / pagesize +1);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; useprevious=pageno==1?false:true;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; usebehind=pageno==pagecount?false:true;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; } <p>&nbsp;&nbsp;&nbsp; public int getPagecount() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return pagecount;<br>&nbsp;&nbsp;&nbsp; } <p>&nbsp;&nbsp;&nbsp; public void setPagecount(int pagecount) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.pagecount = pagecount;<br>&nbsp;&nbsp;&nbsp; } <p>&nbsp;&nbsp;&nbsp; public boolean isUseprevious() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return useprevious;<br>&nbsp;&nbsp;&nbsp; } <p>&nbsp;&nbsp;&nbsp; public void setUseprevious(boolean useprevious) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.useprevious = useprevious;<br>&nbsp;&nbsp;&nbsp; } <p>&nbsp;&nbsp;&nbsp; public boolean isUsebehind() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return usebehind;<br>&nbsp;&nbsp;&nbsp; } <p>&nbsp;&nbsp;&nbsp; public void setUsebehind(boolean usebehind) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.usebehind = usebehind;<br>&nbsp;&nbsp;&nbsp; } <p>&nbsp;&nbsp;&nbsp; public boolean isUsepage() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return usepage;<br>&nbsp;&nbsp;&nbsp; } <p>&nbsp;&nbsp;&nbsp; public void setUsepage(boolean usepage) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.usepage = usepage;<br>&nbsp;&nbsp;&nbsp; } <p>}<br>2、hibernate分页实现函数--〉放在底层类中<br>&nbsp; public class CommonServiceImpl extends HibernateDaoSupport implements CommonService{<br>&nbsp; 。。。<br>&nbsp;&nbsp; //通用分页处理<br>&nbsp;&nbsp;&nbsp; public List getListForPage(final String hsql,PageControl pageControl) throws Exception<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; List pagelist=null;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Session session=getSession();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pageControl.setRowcount(getTotalCount(session,hsql)); //更新pagecontrol的各种属性 important<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(pageControl.isUsepage()){ //是否分页<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // sql=hsql+ " limit " + (pageNog-1)*page_size + "," +page_size;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // offices= getHibernateTemplate().find(sql);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //被屏蔽掉的是原来的处理<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //以下是改过的处理方法<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Query query=null;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; query=session.createQuery(hsql);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int start=(pageControl.getPageno()-1)*pageControl.getPagesize();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int rowNum=pageControl.getPagesize();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; query.setFirstResult(start);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; query.setMaxResults(rowNum);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pagelist = query.list();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }else{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pagelist=session.find(hsql);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } finally {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; session.close();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return pagelist;<br>&nbsp;&nbsp;&nbsp; } <p>&nbsp;&nbsp; //计算表的总行数<br>&nbsp;&nbsp;&nbsp; private int getTotalCount(Session session, String hql) throws Exception<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Integer amount = new Integer(0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int sql_from = hql.indexOf("from");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int sql_orderby=hql.indexOf("order by");//为了改进<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String countStr="";<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(sql_orderby&gt;0)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; countStr="select count(*) "+hql.substring(sql_from,sql_orderby);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; countStr = "select count(*) "+hql.substring(sql_from); <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Query query = session.createQuery(countStr);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(!query.list().isEmpty()){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; amount = (Integer) query.list().get(0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return amount.intValue();<br>&nbsp;&nbsp;&nbsp; }<br>}<br>3、实际service对象继承commonserviceimpl<br>public class LogServiceImpl extends CommonServiceImpl implements LogService{<br>&nbsp;&nbsp;&nbsp; public List getLogByType(Integer logtype, PageControl pageControl) throws Exception{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String hql="from "+Systemlog.class.getName()+" as a where a.baselogtype.id="+logtype+" order by a.opertime desc";<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return getListForPage(hql,pageControl);<br>&nbsp;&nbsp;&nbsp; }<br>}<br>4、action实现<br>public class LogListAction extends BaseAction{<br>&nbsp;&nbsp;&nbsp; public ActionForward execute(ActionMapping actionMapping, ActionForm actionForm, HttpServletRequest request, HttpServletResponse response) throws Exception<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String forward =Constants.FORWORD_FIAL;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LogService service = (LogService) getWebApplicationContext().getBean(Constants.LOG_SERVICE);//获得service对象<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Object obj=((DynaActionForm) actionForm).get(Constants.PAGE_CONTROL_MODEL);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Object obj1=((DynaActionForm) actionForm).get(Constants.PAGE_FILTER_ID);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Integer filterid=obj1==null?new Integer(1):(Integer)obj1;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PageControl pageControl=obj==null?new PageControl():(PageControl)obj;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; List mainlist=service.getLogByType(filterid,pageControl); //调用分页方法得到list<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; List filterlist=service.loadAll(Baselogtype.class);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ((DynaActionForm) actionForm).set(Constants.PAGE_ENTITY_LIST, mainlist);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ((DynaActionForm) actionForm).set(Constants.PAGE_FILTER_LIST, filterlist);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ((DynaActionForm) actionForm).set(Constants.PAGE_FILTER_ID,filterid);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ((DynaActionForm) actionForm).set(Constants.PAGE_CONTROL_MODEL,pageControl);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; forward = Constants.FORWORD_SUCCESS;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (Exception e) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ActionErrors errors = new ActionErrors();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; errors.add(ActionErrors.GLOBAL_ERROR, new ActionError(Constants.ERROR_LIST,e.getMessage()));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; saveErrors(request, errors);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return actionMapping.findForward(forward);<br>&nbsp;&nbsp;&nbsp; }<br>}<br>5、jsp页面<br>5.1、分页部分代码：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;logic:greaterThan value="0" name="LogListForm" property="pagecontrolmodel.rowcount"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;p align="right" style="font-size:12px"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 共&lt;bean:write name="LogListForm" property="pagecontrolmodel.rowcount"/&gt;行<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;nbsp;共&lt;bean:write name="LogListForm" property="pagecontrolmodel.pagecount"/&gt;页<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;nbsp;每页行数<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;html:select name="LogListForm" property="pagecontrolmodel.pagesize" styleClass="DropDownList" style="width:80px" onchange="refresh()"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;html:option value="0"&gt;不分页&lt;/html:option&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;html:option value="10"&gt;10行&lt;/html:option&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;html:option value="20"&gt;20行&lt;/html:option&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;html:option value="30"&gt;30行&lt;/html:option&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;html:option value="50"&gt;50行&lt;/html:option&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;html:option value="100"&gt;100行&lt;/html:option&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/html:select&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;logic:equal value="true" name="LogListForm" property="pagecontrolmodel.usepage"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;logic:equal value="true" name="LogListForm" property="pagecontrolmodel.useprevious"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;nbsp;&lt;a href="javascript:goto(1)"&gt;首页&lt;/a&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;nbsp;&lt;a href="javascript:goto(&lt;bean:write property="pagecontrolmodel.pageno" name="LogListForm"/&gt;-1)"&gt;前一页&lt;/a&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/logic:equal&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;logic:equal value="false" name="LogListForm" property="pagecontrolmodel.useprevious"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;nbsp;首页<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;nbsp;前一页<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/logic:equal&gt; <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;logic:equal value="true" name="LogListForm" property="pagecontrolmodel.usebehind"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;nbsp;&lt;a href="javascript:goto(&lt;bean:write property="pagecontrolmodel.pageno" name="LogListForm"/&gt;+1)"&gt;后一页&lt;/a&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;nbsp;&lt;a href="javascript:goto(&lt;bean:write property="pagecontrolmodel.pagecount" name="LogListForm"/&gt;)"&gt;末页&lt;/a&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/logic:equal&gt; <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;logic:equal value="false" name="LogListForm" property="pagecontrolmodel.usebehind"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;nbsp;后一页<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;nbsp;末页<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/logic:equal&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;nbsp;跳至&lt;html:text property="pagecontrolmodel.pageno" name="LogListForm" styleClass="TextBox" style="width:20px"/&gt;&lt;input type="button" value="go" onclick="check();"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/logic:equal&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/p&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/logic:greaterThan&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>5.2、分页实现配套javascript<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;script&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; function refresh()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; document.all("LogListForm").submit();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; function check()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var pageno=document.all("pagecontrolmodel.pageno");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(!isInt(pageno.value)){alert("非法页数");return;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var ipageno=parseInt(pageno.value);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var imaxno=parseInt(document.all("pagecontrolmodel.pagecount").value);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(ipageno&lt;1 || ipageno&gt;imaxno){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; alert("页数不在允许的范围内！");return;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; refresh();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; function goto(pageno){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; document.all("pagecontrolmodel.pageno").value=pageno;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; check();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/script&gt;</p>]]></description><category>Java</category><comments>http://www.augweb.net/blog/post/87.html#comment</comments><wfw:comment>http://www.augweb.net/blog/</wfw:comment><wfw:commentRss>http://www.augweb.net/blog/feed.asp?cmt=87</wfw:commentRss><trackback:ping>http://www.augweb.net/blog/cmd.asp?act=tb&amp;id=87&amp;key=7db190cb</trackback:ping></item><item><title>正确的解决用户退出问题―JSP和Struts</title><author>lorrons@gmail.com (lorron)</author><link>http://www.augweb.net/blog/post/86.html</link><pubDate>Sun, 28 Sep 2008 04:32:05 +0800</pubDate><guid>http://www.augweb.net/blog/post/86.html</guid><description><![CDATA[<p></p> <h3>&nbsp;</h3> <p><strong>摘要</strong> <p>在一个有密码保护的Web应用当中，正确妥善的处理用户退出过程并不仅仅只需要调用HttpSession对象的invalidate()方法，因为现在大部分浏览器上都有后退(Back)和前进(Forward)按钮，允许用户后退或前进到一个页面。 <p>在用户退出一个Web应用之后，如果按了后退按钮，浏览器把缓存中的页面呈现给用户，这会使用户产生疑惑，他们会开始担心他们的个人数据是否安全。 <p>实际上，许多Web应用会弹出一个页面，警告用户退出时关闭整个浏览器，以此来阻止用户点击后退按钮。还有一些使用JavaScript，但在某些客户端浏览器中这却不一定起作用。这些解决方案大多数实现都很笨拙，且不能保证在任何情况下都100%有效，同时，它还要求用户有一定的操作经验。 <p>这篇文章以简单的程序示例阐述了正确解决用户退出问题的方案。作者Kevin Le首先描述了一个理想的密码保护Web应用，然后以示例程序解释问题如何产生并讨论解决问题的方案。文章虽然是针对JSP进行讨论阐述，但作者所阐述的概念很容易理解而且能够为其他Web技术所采用。最后最后，作者Kevin Le用Jakarta Struts更为优雅地解决用户退出问题。文中包含JSP和Struts的示例程序 (3,700 words; September 27, 2004) <p>大部分Web应用不会包含像银行账户或信用卡资料那样机密的信息，但是一旦涉及到敏感数据，就需要我们提供某些密码保护机制。例如，在一个工厂当中，工人必须通过Web应用程序访问他们的时间安排、进入他们的培训课程以及查看他们的薪金等等。此时应用SSL(Secure Socket Layer)就有些大材小用了(SSL页面不会在缓存中保存，关于SSL的讨论已经超出本文的范围)。但是这些应用又确实需要某种密码保护措施，否则，工人（在这种情况下，也就是Web应用的使用者）就可以发现工厂中所有员工的私人机密信息。 <p>类似上面的情况还包括位于公共图书馆、医院、网吧等公共场所的计算机。在这些地方，许多用户共同使用几台计算机，此时保护用户的个人数据就显得至关重要。 同时应用程序的良好设计与实现对用户专业知识以及相关培训要求少之又少。 <p>让我们来看一下现实世界中一个完美的Web应用是怎样工作的：  <p>1. 用户在浏览器中输入URL，访问一个页面。  <p>2. Web应用显示一个登陆页面，要求用户输入有效的验证信息。  <p>3. 用户输入用户名和密码。  <p>4. 假设用户提供的验证信息是正确的，经过了验证过程，Web应用允许用户浏览他有权访问的区域。  <p>5. 退出时，用户点击页面的退出按钮，Web应用显示确认页面，询问用户是否真的需要退出。一旦用户点击确定按钮，Session结束，Web应用重新定位到登陆页面。用户现在可以放心的离开而不用担心他的信息会被泄露。  <p>6. 另一个用户坐到了同一台电脑前。他点击后退按钮，Web应用不应该显示上一个用户访问过的任何一个页面。  <p>事实上，Web应用将一直停留在登陆页面上，除非第二个用户提供正确的验证信息，之后才可以访问他有权限的区域。 <p>通过示例程序，文章向您阐述了如何在一个Web应用中实现上面的功能。 <p><strong>一. JSP samples</strong> <p>为了更为有效地向您说明这个解决方案，本文将从展示一个Web应用logoutSampleJSP1中碰到的问题开始。这个示例代表了许多没有正确解决退出过程的Web应用。logoutSampleJSP1包含一下JSP页面：login.jsp, home.jsp, secure1.jsp, secure2.jsp, logout.jsp, loginAction.jsp, 和 logoutAction.jsp。其中页面home.jsp, secure1.jsp, secure2.jsp, 和 logout.jsp是不允许未经认证的用户访问的，也就是说，这些页面包含了重要信息，在用户登陆之前或者退出之后都不应该显示在浏览器中。login.jsp页面包含了用于用户输入用户名和密码的form。logout.jsp页面包含了要求用户确认是否退出的form。loginAction.jsp和logoutAction.jsp作为控制器分别包含了登陆和退出动作的代码。 <p>第二个Web示例应用logoutSampleJSP2展示了如何纠正示例logoutSampleJSP1中的问题。但是第二个示例logoutSampleJSP2自身也是有问题的。在特定情况下，退出问题依然存在。 <p>第三个Web示例应用logoutSampleJSP3对logoutSampleJSP2进行了改进，比较妥善地解决了退出问题。 <p>最后一个Web示例logoutSampleStruts展示了JakartaStruts如何优雅地解决退出问题。 <p>注意：本文所附示例在最新版本的Microsoft Internet Explorer (IE), Netscape Navigator, Mozilla, FireFox和Avant浏览器上测试通过。 <p><strong>二. Login action</strong> <p>Brian Pontarelli的经典文章 《J2EE Security: Container Versus Custom》 讨论了不同的J2EE认证方法。文章同时指出，HTTP协议和基于form的认证方法并不能提供处理用户退出问题的机制。因此，解决方法便是引入用户自定义的安全实现机制，这就提供了更大的灵活性。 <p>在用户自定义的认证方法中，普遍采用的方法是从用户提交的form中获得用户输入的认证信息，然后到诸如LDAP (lightweight directory access protocol)或关系数据库(relational database management system, RDBMS)的安全域中进行认证。如果用户提供的认证信息是有效的，登陆动作在HttpSession对象中保存某个对象。HttpSession存在着保存的对象则表示用户已经登陆到Web应用当中。为了方便起见，本文所附的示例只在HttpSession中保存一个用户名以表明用户已经登陆。清单1是从loginAction.jsp页面中节选的一段代码以此讲解登陆动作： <p>Listing 1 <p>//... <br>//initialize RequestDispatcher object; set forward to home page by default <br>RequestDispatcher rd = request.getRequestDispatcher( "home.jsp" );<br>//Prepare connection and statement <br>rs = stmt.executeQuery( "select password from USER where userName = '" + userName + "'" );<br>if (rs.next()) { <br>//Query only returns 1 record in the result set; <br>//Only 1 password per userName which is also the primary key<br>&nbsp;&nbsp;&nbsp; if (rs.getString( "password" ).equals(password)) { //If valid password <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; session.setAttribute( "User" , userName); //Saves username string in the session object <br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; else { //Password does not match, i.e., invalid user password <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; request.setAttribute( "Error" , "Invalid password." ); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rd = request.getRequestDispatcher( "login.jsp" );<br>&nbsp;&nbsp;&nbsp; }<br>} //No record in the result set, i.e., invalid username <br>&nbsp;&nbsp;&nbsp; else {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; request.setAttribute( "Error" , "Invalid user name." );<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rd = request.getRequestDispatcher( "login.jsp" );<br>&nbsp;&nbsp;&nbsp; }<br>}<br>//As a controller, loginAction.jsp finally either forwards to "login.jsp" or "home.jsp" <br>rd.forward(request, response);<br>//... <p>本文当中所附Web应用示例均以关系型数据库作为安全域，但本问所讲述的内容同样适用于其他任何类型的安全域。 <p><strong>三. Logout action</strong> <p>退出动作包含删除用户名以及调用用户的HttpSession对象的invalidate()方法。清单2是从loginoutAction.jsp中节选的一段代码，以此说明退出动作： <p>Listing 2 <p>//... <br>session.removeAttribute( "User" );<br>session.invalidate();<br>//... <p><strong>四. 阻止未经认证访问受保护的JSP页面</strong> <p>从提交的form中获取用户提交的认证信息并经过验证后，登陆动作仅仅在HttpSession对象中写入一个用户名。退出动作则刚好相反，它从HttpSession中删除用户名并调用HttpSession对象的invalidate()方法。为了使登陆和退出动作真正发挥作用，所有受保护的JSP页面必须首先验证HttpSession中包含的用户名，以便确认用户当前是否已经登陆。如果HttpSession中包含了用户名，就说明用户已经登陆，Web应用会将剩余的JSP页中的动态内容发送给浏览器。否则，JSP页将跳转到登陆页面，login.jsp。页面home.jsp, secure1.jsp, secure2.jsp和 logout.jsp均包含清单3中的代码段： <p>Listing 3  <p>//... <br>String userName = (String) session.getAttribute( "User" );<br>if (null == userName) {<br>&nbsp;&nbsp;&nbsp; request.setAttribute( "Error" , "Session has ended. Please login." );<br>&nbsp;&nbsp;&nbsp; RequestDispatcher rd = request.getRequestDispatcher( "login.jsp" );<br>&nbsp;&nbsp;&nbsp; rd.forward(request, response);<br>}<br>//... <br>//Allow the rest of the dynamic content in this JSP to be served to the browser <br>//... <p>在这个代码段中，程序从HttpSession中检索username字符串。如果username字符串为空，Web应用则自动中止执行当前页面并跳转到登陆页，同时给出错误信息“Session has ended. Please log in.”；如果不为空，Web应用继续执行，把剩余的页面提供给用户，从而使JSP页面的动态内容成为服务对象。 <p><strong>五.运行logoutSampleJSP1</strong> <p>运行logoutSampleJSP1将会出现如下几种情形： <p>• 如果用户没有登陆，Web应用将会正确中止受保护页面home.jsp, secure1.jsp, secure2.jsp和logout.jsp中动态内容的执行。也就是说，假如用户并没有登陆，但是在浏览器地址栏中直接敲入受保护JSP页的地址试图访问，Web应用将自动跳转到登陆页面，同时显示错误信息“Session has ended.Please log in.” <p>• 同样的，当一个用户已经退出，Web应用将会正确中止受保护页面home.jsp, secure1.jsp, secure2.jsp和logout.jsp中动态内容的执行。也就是说，用户退出以后，如果在浏览器地址栏中直接敲入受保护JSP页的地址试图访问，Web应用将自动跳转到登陆页面，同时显示错误信息“Session has ended.Please log in.” <p>• 用户退出以后，如果点击浏览器上的后退按钮返回到先前的页面，Web应用将不能正确保护受保护的JSP页面——在Session销毁后（用户退出）受保护的JSP页会重新显示在浏览器中。然而，点击该页面上的任何链接，Web应用都会跳转到登陆页面，同时显示错误信息“Session has ended.Please log in.” <p><strong>六. 阻止浏览器缓存</strong> <p>上述问题的根源就在于现代大部分浏览器都有一个后退按钮。当点击后退按钮时，默认情况下浏览器不会从Web服务器上重新获取页面，而是简单的从浏览器缓存中重新载入页面。这个问题并不仅限于基于Java(JSP/servlets/Struts) 的Web应用当中，在基于PHP (Hypertext Preprocessor)、ASP、(Active Server Pages)、和.NET的Web应用中也同样存在。 <p>在用户点击后退按钮之后，浏览器到Web服务器（一般来说）或者应用服务器（在java的情况下）再从服务器到浏览器这样通常意义上的HTTP回路并没有建立。仅仅只是用户，浏览器和缓存之间进行了交互。所以即使受保护的JSP页面，例如home.jsp, secure1.jsp, secure2.jsp和logout.jsp包含了清单3上的代码，当点击后退按钮时，这些代码也永远不会执行的。 <p>缓存的好坏，真是仁者见仁智者见智。缓存事实上的确提供了一些便利，但这些便利通常只存在于静态的HTML页面或基于图形或影像的页面。而另一方面，Web应用通常是面向数据的。由于Web应用中的数据频繁变更，所以与为了节省时间从缓存中读取并显示过期的数据相比，提供最新的数据显得尤为重要！ <p>幸运的是，HTTP头信息“Expires”和“Cache-Control”为应用程序服务器提供了一个控制浏览器和代理服务器上缓存的机制。HTTP头信息Expires告诉代理服务器它的缓存页面何时将过期。HTTP1.1规范中新定义的头信息Cache-Control在Web应用当中可以通知浏览器不缓存任何页面。当点击后退按钮时，浏览器发送Http请求道应用服务器以便获取该页面的最新拷贝。如下是使用Cache-Control的基本方法： <p>• no-cache:强制缓存从服务器上获取该页面的最新拷贝  <p>• no-store: 在任何情况下缓存不保存该页面 <p>HTTP1.0规范中的Pragma:no-cache等同于HTTP1.1规范中的Cache-Control:no-cache，同样可以包含在头信息中。 <p>通过使用HTTP头信息的cache控制，第二个示例应用logoutSampleJSP2解决了logoutSampleJSP1的问题。logoutSampleJSP2与logoutSampleJSP1不同表现在如下代码段中，这一代码段加入进所有受保护的页面中： <p>//... <br>response.setHeader( "Cache-Control" , "no-cache" ); <br>//Forces caches to obtain a new copy of the page from the origin server <br>response.setHeader( "Cache-Control" , "no-store" ); <br>//Directs caches not to store the page under any circumstance <br>response.setDateHeader( "Expires" , 0); <br>//Causes the proxy cache to see the page as "stale" <br>response.setHeader( "Pragma" , "no-cache" );<br>//HTTP 1.0 backward compatibility <br>String userName = (String) session.getAttribute( "User" );<br>if (null == userName) {<br>&nbsp;&nbsp;&nbsp; request.setAttribute( "Error" , "Session has ended. Please login." );<br>&nbsp;&nbsp;&nbsp; RequestDispatcher rd = request.getRequestDispatcher( "login.jsp" );<br>&nbsp;&nbsp;&nbsp; rd.forward(request, response);<br>}<br>//... <p>通过设置头信息和检查HttpSession对象中的用户名来确保浏览器不会缓存JSP页面。同时，如果用户未登陆，JSP页面的动态内容不会发送到浏览器，取而代之的将是登陆页面login.jsp。 <p><strong>七. 运行logoutSampleJSP2</strong> <p>运行Web示例应用logoutSampleJSP2后将会看到如下结果： <p>• 当用户退出后试图点击后退按钮，浏览器不会重新显示受保护的页面，它只会显示登陆页login.jsp同时给出提示信息Session has ended. Please log in. • 然而，当按了后退按钮返回的页是处理用户提交数据的页面时，IE和Avant浏览器将弹出如下信息提示：  <p>警告：页面已过期 <p>The page you requested was created using information you submitted in a form. This page is no longer available. As a security divcaution, Internet Explorer does not automatically resubmit your information for you.  <p>Mozilla和FireFox浏览器将会显示一个对话框，提示信息如下： <p>The page you are trying to view contains POSTDATA that has expired from cache. If you resend the data, any action from the form carried out (such as a search or online purchase) will be repeated. To resend the data, click OK. Otherwise, click Cancel.  <p>在IE和Avant浏览器中选择刷新或者在Mozilla和FireFox浏览器中选择重新发送数据后，前一个JSP页面将重新显示在浏览器中。显然的，这病不是我们所想看到的因为它违背了logout动作的目的。发生这一现象时，很可能是一个恶意用户在尝试获取其他用户的数据。然而，这个问题仅仅出现在点击后退按钮后，浏览器返回到一个处理POST请求的页面。 <p><strong>八. 记录最后登陆时间</strong> <p>上述问题的发生是因为浏览器重新提交了其缓存中的数据。这本文的例子中，数据包含了用户名和密码。尽管IE浏览器给出了安全警告信息，但事实上浏览器此时起到了负面作用。 <p>为了解决logoutSampleJSP2中出现的问题，logoutSampleJSP3的login.jsp除了包含username和password的之外，还增加了一个称作lastLogon的隐藏表单域，此表单域将会动态的被初始化为一个long型值。这个long型值是通过调用System.currentTimeMillis()获取到的自1970年1月1日以来的毫秒数。当login.jsp中的form提交时，loginAction.jsp首先将隐藏域中的值与用户数据库中的lastLogon值进行比较。只有当lastLogon表单域中的值大于数据库中的值时Web应用才认为这是个有效的登陆。 <p>为了验证登陆，数据库中lastLogon字段必须用表单中的lastLogon值进行更新。上例中，当浏览器重复提交缓存中的数据时，表单中的lastLogon值不比数据库中的lastLogon值大，因此，loginAction将跳转到login.jsp页面，并显示如下错误信息“Session has ended.Please log in.”清单5是loginAction中节选的代码段： <p>清单5 <p>//... <br>RequestDispatcher rd = request.getRequestDispatcher( "home.jsp" ); <br>//Forward to homepage by default <br>//... <br>if (rs.getString( "password" ).equals(password)) { //If valid password <br>&nbsp;&nbsp;&nbsp; long lastLogonDB = rs.getLong( "lastLogon" );<br>&nbsp;&nbsp;&nbsp; if (lastLogonForm &gt; lastLogonDB) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; session.setAttribute( "User" , userName); <br>&nbsp; //Saves username string in the session object <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; stmt.executeUpdate( "update USER set lastLogon= " + lastLogonForm + " <br>where userName = '" + userName + "'" );<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; else {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; request.setAttribute( "Error" , "Session has ended. Please login." );<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rd = request.getRequestDispatcher( "login.jsp" ); }<br>&nbsp;&nbsp;&nbsp; }<br>else { //Password does not match, i.e., invalid user password <br>&nbsp;&nbsp;&nbsp; request.setAttribute( "Error" , "Invalid password." );<br>&nbsp;&nbsp;&nbsp; rd = request.getRequestDispatcher( "login.jsp" ); <br>}<br>//... <br>rd.forward(request, response);<br>//... <p>为了实现上述方法，你必须记录每个用户的最后登陆时间。对于采用关系型数据库安全域来说，这点可以可以通过在某个表中加上lastLogin字段轻松实现。虽然对LDAP以及其他的安全域来说需要稍微动下脑筋，但最后登陆方法很显然是可以实现的。 <p>表示最后登陆时间的方法有很多。示例logoutSampleJSP3利用了自1970年1月1日以来的毫秒数。这个方法即使在许多人在不同浏览器中用一个用户账号登陆时也是可行的。 <p><strong>九. 运行logoutSampleJSP3</strong> <p>运行示例logoutSampleJSP3将展示如何正确处理退出问题。一旦用户退出，点击浏览器上的后退按钮在任何情况下都不会在浏览器中显示受保护的JSP页面。这个示例展示了如何正确处理退出问题而不需要对用户进行额外的培训。 <p>为了使代码更简练有效，一些冗余的代码可以剔除。一种途径就是把清单4中的代码写到一个单独的JSP页中，其他JSP页面可以通过标签 进行使用 。 <p><strong>十. Struts框架下的退出实现</strong> <p>与直接使用JSP或JSP/servlets进行Web应用开发相比，另一个更好的可选方案是使用Struts。对于一个基于Struts的Web应用来说，添加一个处理退出问题的框架可以优雅地不费气力的实现。这归功于Struts是采用MVC设计模式的，因此可以将模型和视图代码清晰的分离。另外，Java是一个面向对象的语言，支持继承，可以比JSP中的脚本更为容易地实现代码重用。对于Struts来说，清单4中的代码可以从JSP页面中移植到Action类的execute()方法中。 <p>此外，我们还可以定义一个继承Struts Action类的Action基类，其execute()方法中包含了类似清单4中的代码。通过继承，其他Action类可以继承基本类中的通用逻辑来设置HTTP头信息以及检索HttpSession对象中的username字符串。这个Action基类是一个抽象类并定义了一个抽象方法executeAction()。所有继承自Action基类的子类都必须实现exectuteAction()方法而不是覆盖它。通过继承这一机制，所有继承自Action基类的子类都不必再担心退出代码接口。（plumbing实在不知道怎么翻译了，^+^，高手帮帮忙啊！原文：With this inheritance hierarchy in place, all of the base Action's subclasses no longer need to worry about any plumbing logout code.）。他们将只包含正常的业务逻辑代码。清单6是基类的部分代码： <p>清单6 <p>publicabstractclass BaseAction extends Action {<br>&nbsp;&nbsp;&nbsp; public ActionForward execute(ActionMapping mapping, ActionForm form,<br>HttpServletRequest request, HttpServletResponse response) <br>throws IOException, ServletException {<br>response.setHeader( "Cache-Control" , "no-cache" );<br>//Forces caches to obtain a new copy of the page from the origin server <br>response.setHeader( "Cache-Control" , "no-store" ); <br>//Directs caches not to store the page under any circumstance <br>response.setDateHeader( "Expires" , 0); <br>//Causes the proxy cache to see the page as "stale" <br>response.setHeader( "Pragma" , "no-cache" ); <br>//HTTP 1.0 backward compatibility <br>if (!this.userIsLoggedIn(request)) {<br>&nbsp;&nbsp;&nbsp; ActionErrors errors = new ActionErrors();<br>&nbsp;&nbsp;&nbsp; errors.add( "error" , new ActionError( "logon.sessionEnded" ));<br>&nbsp;&nbsp;&nbsp; this.saveErrors(request, errors);<br>&nbsp;&nbsp;&nbsp; return mapping.findForward( "sessionEnded" );<br>}<br>return executeAction(mapping, form, request, response);<br>}<br>protectedabstract ActionForward executeAction(ActionMapping mapping,&nbsp; ActionForm form, <br>HttpServletRequest request, HttpServletResponse response) <br>throws IOException, ServletException; <br>privateboolean userIsLoggedIn(HttpServletRequest request) {<br>if (request.getSession().getAttribute( "User" ) == null) {<br>&nbsp;&nbsp;&nbsp; return false;<br>}<br>return true;<br>}<br>} <p>清单6中的代码与清单4中的很相像，唯一区别是用ActionMapping findForward替代了RequestDispatcher forward。清单6中，如果在HttpSession中未找到username字符串，ActionMapping对象将找到名为sessionEnded的forward元素并跳转到对应的path。如果找到了，子类通过实现executeAction()方法，将执行他们自己的业务逻辑。因此，在struts-web.xml配置文件中为所有继承自Action基类的子类声明个一名为sessionEnded的forward元素并将其指向login.jsp是至关重要的。清单7以secure1 action阐明了这样一个声明： <p>清单7 <p>&lt;action path= "/secure1" <br>type= "com.kevinhle.logoutSampleStruts.Secure1Action" <br>scope= "request" &gt;<br>&lt;forward name= "success" path= "/WEB-INF/jsps/secure1.jsp" /&gt;<br>&lt;forward name= "sessionEnded" path= "/login.jsp" /&gt;<br>&lt;/action&gt; <p>继承自BaseAction类的子类Secure1Action实现了executeAction()方法而不是覆盖它。Secure1Action类不需要执行任何退出代码，如清单8： <p>清单8 <p>publicclass Secure1Action extends BaseAction {<br>&nbsp;&nbsp;&nbsp; public ActionForward executeAction(ActionMapping mapping, ActionForm form,<br>HttpServletRequest request, HttpServletResponse response)<br>throws IOException, ServletException {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HttpSession session = request.getSession(); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (mapping.findForward( "success" ));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>} <p>上面的解决方案是如此的优雅有效，它仅仅只需要定义一个基类而不需要额外的代码工作。将通用的行为方法写成一个继承StrutsAction的基类是者的推荐的，而且这是许多Struts项目的共同经验。 <p><strong>十一. 局限性</strong> <p>上述解决方案对JSP或基于Struts的Web应用都是非常简单而实用的，但它还是有某些局限。在我看来，这些局限并不是至关紧要的。 <p>• 通过取消与浏览器后退按钮有关的缓存机制，一旦用户离开页面而没有对数据进行提交，那么页面将会丢失所有输入的数据。即使点击浏览器的后退按钮返回到刚才的页面也无济于事，因为浏览器会从服务器获取新的空白页面显示出来。一种可能的方法并不是阻止这些JSP页面包含数据数据表格。在基于JSP的解决方案当中，那些JSP页面可以删除在清单4中的代码。在基于Struts的解决方案当中，Action类需要继承自Struts的Action类而非BaseAction类。 <p>• 上面讲述的方法在Opera浏览器中不能工作。事实上没有适用于Opera浏览器的解决方案，因为Opera浏览器与2616 Hypertext Transfer Protocol—HTTP/1.1紧密相关。Section 13.13 of RFC 2616 states:  <p>User agents often have history mechanisms, such as "Back" buttons and history lists, which can be used to redisplay an entity retrieved earlier in a session.  <p>History mechanisms and caches are different. In particular history mechanisms SHOULD NOT try to show a semantically transparent view of the current state of a resource. Rather, a history mechanism is meant to show exactly what the user saw at the time when the resource was retrieved. <p>幸运的是，使用微软的IE和基于Mozilla的浏览器用户多余Opera浏览器。上面讲述的解决方案对大多数用户来说还是有帮助的。另外，无论是否使用上述的解决方案，Opera浏览器仍然存在用户退出问题，就Opera来说没有任何改变。然而，正如RFC2616中所说，通过像上面一样设置头文件指令，当用户点击一个链接时，Opera浏览器不会从缓存中获取页面。 <p><strong>十二. 结论</strong> <p>这篇文章讲述了处理退出问题的解决方案，尽管方案简单的令人惊讶，但在所有情况下都能有效地工作。无论是对JSP还是Struts，所要做的不过是写一段不超过50行的代码以及一个记录用户最后登陆时间的方法。在有密码保护的Web应用中使用这些方案能够确保在任何情况下用户的私人数据不致泄露，同时，也能增加用户的经验。</p>]]></description><category>Java</category><comments>http://www.augweb.net/blog/post/86.html#comment</comments><wfw:comment>http://www.augweb.net/blog/</wfw:comment><wfw:commentRss>http://www.augweb.net/blog/feed.asp?cmt=86</wfw:commentRss><trackback:ping>http://www.augweb.net/blog/cmd.asp?act=tb&amp;id=86&amp;key=9d360515</trackback:ping></item><item><title>MyEclipse 快捷键</title><author>lorrons@gmail.com (lorron)</author><link>http://www.augweb.net/blog/post/85.html</link><pubDate>Sat, 27 Sep 2008 17:22:52 +0800</pubDate><guid>http://www.augweb.net/blog/post/85.html</guid><description><![CDATA[<p>输入sysout 按ALT+/&nbsp;&nbsp;&nbsp;&nbsp; 自动输入System.out.println() <p>MyEclipse 快捷键<br>（1）Ctrl+M切换窗口的大小<br>（2）Ctrl+Q跳到最后一次的编辑处<br>（3）F2当鼠标放在一个标记处出现Tooltip时候按F2则把鼠标移开时Tooltip还会显示即Show Tooltip Description。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; F3跳到声明或定义的地方。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; F5单步调试进入函数内部。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; F6单步调试不进入函数内部，如果装了金山词霸2006则要把“取词开关”的快捷键改成其他的。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; F7由函数内部返回到调用处。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; F8一直执行到下一个断点。<br>（4）Ctrl+Pg~对于XML文件是切换代码和图示窗口<br>（5）Ctrl+Alt+I看Java文件中变量的相关信息<br>（6）Ctrl+PgUp对于代码窗口是打开“Show List”下拉框，在此下拉框里显示有最近曾打开的文件<br>（7）Ctrl+/ 在代码窗口中是这种//~注释。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Ctrl+Shift+/ 在代码窗口中是这种/*~*/注释，在JSP文件窗口中是&lt;!--~--&gt;。<br>（8）Alt+Shift+O(或点击工具栏中的Toggle Mark Occurrences按钮) 当点击某个标记时可使本页面中其他地方的此标记黄色凸显，并且窗口的右边框会出现白色的方块，点击此方块会跳到此标记处。<br>（9）右击窗口的左边框即加断点的地方选Show Line Numbers可以加行号。<br>（10）Ctrl+I格式化激活的元素Format Active Elements。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Ctrl+Shift+F格式化文件Format Document。<br>（11）Ctrl+S保存当前文件。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Ctrl+Shift+S保存所有未保存的文件。<br>（12）Ctrl+Shift+M(先把光标放在需导入包的类名上) 作用是加Import语句。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Ctrl+Shift+O作用是缺少的Import语句被加入，多余的Import语句被删除。<br>（13）Ctrl+Space提示键入内容即Content Assist，此时要将输入法中Chinese(Simplified)IME-Ime/Nonlme Toggle的快捷键（用于切换英文和其他文字）改成其他的。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Ctrl+Shift+Space提示信息即Context Information。<br>（14）双击窗口的左边框可以加断点。<br>（15）Ctrl+D删除当前行。 <p>－－－待续 <p>[以下为转载]<br>Eclipse快捷键大全<br>Ctrl+1 快速修复(最经典的快捷键,就不用多说了)<br>Ctrl+D: 删除当前行 <br>Ctrl+Alt+↓ 复制当前行到下一行(复制增加)<br>Ctrl+Alt+↑ 复制当前行到上一行(复制增加) <p>Alt+↓ 当前行和下面一行交互位置(特别实用,可以省去先剪切,再粘贴了)<br>Alt+↑ 当前行和上面一行交互位置(同上)<br>Alt+← 前一个编辑的页面<br>Alt+→ 下一个编辑的页面(当然是针对上面那条来说了) <p>Alt+Enter 显示当前选择资源(工程,or 文件 or文件)的属性 <p>Shift+Enter 在当前行的下一行插入空行(这时鼠标可以在当前行的任一位置,不一定是最后)<br>Shift+Ctrl+Enter 在当前行插入空行(原理同上条) <p>Ctrl+Q 定位到最后编辑的地方<br>Ctrl+L 定位在某行 (对于程序超过100的人就有福音了)<br>Ctrl+M 最大化当前的Edit或View (再按则反之)<br>Ctrl+/ 注释当前行,再按则取消注释<br>Ctrl+O 快速显示 OutLine<br>Ctrl+T 快速显示当前类的继承结构<br>Ctrl+W 关闭当前Editer<br>Ctrl+K 参照选中的Word快速定位到下一个<br>Ctrl+E 快速显示当前Editer的下拉列表(如果当前页面没有显示的用黑体表示) <p>Ctrl+/(小键盘) 折叠当前类中的所有代码 <p>Ctrl+×(小键盘) 展开当前类中的所有代码 <p>Ctrl+Space 代码助手完成一些代码的插入(但一般和输入法有冲突,可以修改输入法的热键,也可以暂用Alt+/来代替) <p>Ctrl+Shift+E 显示管理当前打开的所有的View的管理器(可以选择关闭,激活等操作) <p>Ctrl+J 正向增量查找(按下Ctrl+J后,你所输入的每个字母编辑器都提供快速匹配定位到某个单词,如果没有,则在stutes line中显示没有找到了,查一个单词时,特别实用,这个功能Idea两年前就有了) <p>Ctrl+Shift+J 反向增量查找(和上条相同,只不过是从后往前查) <p>Ctrl+Shift+F4 关闭所有打开的Editer <p>Ctrl+Shift+X 把当前选中的文本全部变味小写 <p>Ctrl+Shift+Y 把当前选中的文本全部变为小写 <p>Ctrl+Shift+F 格式化当前代码 <p>Ctrl+Shift+P 定位到对于的匹配符(譬如{}) (从前面定位后面时,光标要在匹配符里面,后面到前面,则反之) <p>下面的快捷键是重构里面常用的,本人就自己喜欢且常用的整理一下(注:一般重构的快捷键都是Alt+Shift开头的了) <p>Alt+Shift+R 重命名 (是我自己最爱用的一个了,尤其是变量和类的Rename,比手工方法能节省很多劳动力) <p>Alt+Shift+M 抽取方法 (这是重构里面最常用的方法之一了,尤其是对一大堆泥团代码有用) <p>Alt+Shift+C 修改函数结构(比较实用,有N个函数调用了这个方法,修改一次搞定) <p>Alt+Shift+L 抽取本地变量( 可以直接把一些魔法数字和字符串抽取成一个变量,尤其是多处调用的时候) <p>Alt+Shift+F 把Class中的local变量变为field变量 (比较实用的功能) <p>Alt+Shift+I 合并变量(可能这样说有点不妥Inline)<br>Alt+Shift+V 移动函数和变量(不怎么常用)<br>Alt+Shift+Z 重构的后悔药(Undo)]]></description><category>Java</category><comments>http://www.augweb.net/blog/post/85.html#comment</comments><wfw:comment>http://www.augweb.net/blog/</wfw:comment><wfw:commentRss>http://www.augweb.net/blog/feed.asp?cmt=85</wfw:commentRss><trackback:ping>http://www.augweb.net/blog/cmd.asp?act=tb&amp;id=85&amp;key=def38232</trackback:ping></item><item><title>Eclipse使用技巧</title><author>lorrons@gmail.com (lorron)</author><link>http://www.augweb.net/blog/post/84.html</link><pubDate>Sat, 27 Sep 2008 16:53:00 +0800</pubDate><guid>http://www.augweb.net/blog/post/84.html</guid><description><![CDATA[<p><strong>Template：Alt + .</strong> <p>&nbsp;&nbsp;&nbsp; 修改处：Window-&gt;Preference-&gt;Workbench-&gt;Keys-&gt;Command-&gt;Edit-&gt;Content Assist. <p>&nbsp;&nbsp;&nbsp; 个人习惯：Shift+SPACE（空白）。 <p>&nbsp;&nbsp;&nbsp; 简易说明：编辑程序代码时，打sysout +Template启动键，就会自动出现：System.out.println（）； . <p>&nbsp;&nbsp;&nbsp; 设定Template的格式：窗口-&gt;喜好设定-&gt;Java-&gt;编辑器-&gt;模板。 <p><strong>&nbsp;&nbsp;&nbsp; 程序代码自动排版：Ctrl+Shift+F</strong> <p>&nbsp;&nbsp;&nbsp; 修改处：窗口-&gt;喜好设定-&gt;工作台-&gt;按键-&gt;程序代码-&gt;格式。 <p>&nbsp;&nbsp;&nbsp; 个人习惯：Alt+Z. <p>&nbsp;&nbsp;&nbsp; 自动排版设定：窗口-&gt;喜好设定-&gt;Java-&gt;程序代码格式制作程序。 <p>&nbsp;&nbsp;&nbsp; 样式页面-&gt;将插入tab（而非空格键）以内缩，该选项取消勾选，下面空格数目填4，这样在自动编排时会以空格4作缩排。 <p><strong>&nbsp;&nbsp;&nbsp; 快速执行程序：Ctrl + F11</strong> <p>&nbsp;&nbsp;&nbsp; 个人习惯：ALT+X <p>&nbsp;&nbsp;&nbsp; 修改处：窗口-&gt;喜好设定-&gt;工作台-&gt;按键-&gt;执行-&gt;启动前一次的启动作业。 <p>&nbsp;&nbsp;&nbsp; 简易说明：第一次执行时，它会询问您执行模式，设置好后，以后只要按这个热键，它就会快速执行。 <p>……我觉得很顺手^___^ <p><strong>&nbsp;&nbsp;&nbsp; 自动汇入所需要的类别：Ctrl+Shift+O</strong> <p>&nbsp;&nbsp;&nbsp; 简易说明： <p>&nbsp;&nbsp;&nbsp; 假设我们没有Import任何类别时，当我们在程序里打入： <p>&nbsp;&nbsp;&nbsp; BufferedReader buf =new BufferedReader（new InputStreamReader（System.in））； <p>&nbsp;&nbsp;&nbsp; 此时Eclipse会警示说没有汇入类别，这时我们只要按下Ctrl+Shift+O，它就会自动帮我们Import类别。 <p><strong>&nbsp;&nbsp;&nbsp; 查看使用类别的原始码：Ctrl+鼠标左键点击</strong> <p>&nbsp;&nbsp;&nbsp; 简易说明：可以看到您所使用类别的原始码。 <p><strong>&nbsp;&nbsp;&nbsp; 将选取的文字批注起来：Ctrl+/</strong> <p>&nbsp;&nbsp;&nbsp; 简易说明：Debug时很方便。 <p>&nbsp;&nbsp;&nbsp; 修改处：窗口-&gt;喜好设定-&gt;工作台-&gt;按键-&gt;程序代码-&gt;批注 <p>&nbsp;&nbsp;&nbsp; 将选取的文字取消批注：Ctrl+简易说明：同上。 <p>&nbsp;&nbsp;&nbsp; 修改处：窗口-&gt;喜好设定-&gt;工作台-&gt;按键-&gt;程序代码-&gt;取消批注 <p><strong>&nbsp;&nbsp;&nbsp; 视景切换：Ctrl+F8</strong> <p>&nbsp;&nbsp;&nbsp; 个人习惯：Alt+S. <p>&nbsp;&nbsp;&nbsp; 修改处：窗口-&gt;喜好设定-&gt;工作台-&gt;按键-&gt;窗口-&gt;下一个视景。 <p>&nbsp;&nbsp;&nbsp; 简易说明：可以方便我们快速切换编辑、除错等视景。 <p>&nbsp;&nbsp;&nbsp; 3.0里Ctrl+Alt+H可以看到调用当前member的方法，而且可以一层一层上去。 <p>&nbsp;&nbsp;&nbsp; Ctrl+O可以快速切到其他方法。 <p><strong>&nbsp;&nbsp;&nbsp; 密技篇：</strong> <p>&nbsp;&nbsp;&nbsp; 一套Eclipse可同时切换，英文、繁体、简体显示： <p>&nbsp;&nbsp;&nbsp; 1.首先要先安装完中文化包。 <p>&nbsp;&nbsp;&nbsp; 2.在桌面的快捷方式后面加上参数即可， <p>&nbsp;&nbsp;&nbsp; 英文-&gt; -nl "zh_US" <p>&nbsp;&nbsp;&nbsp; 繁体-&gt; -nl "zh_TW" <p>&nbsp;&nbsp;&nbsp; 简体-&gt; -nl "zh_CN". <p>&nbsp;&nbsp;&nbsp; （其它语系以此类推） <p>&nbsp;&nbsp;&nbsp; 像我2.1.2中文化后，我在我桌面的Eclipse快捷方式加入参数-n1 "zh_US". <p>&nbsp;&nbsp;&nbsp; "C：\Program Files\eclipse\eclipse.exe" -n "zh_US" <p>&nbsp;&nbsp;&nbsp; 接口就会变回英文语系噜。 <p>&nbsp;&nbsp;&nbsp; 利用Eclipse，在Word编辑文书时可不必将程序代码重新编排： <p>&nbsp;&nbsp;&nbsp; 将Eclipse程序编辑区的程序代码整个复制下来（Ctrl+C），直接贴（Ctrl+V）到Word或WordPad上，您将会发现在Word里的程序代码格式，跟Eclipse所设定的完全一样，包括字型、缩排、关键词颜色。我曾试过JBuilder 、GEL、NetBeans……使用复制贴上时，只有缩排格式一样，字型、颜色等都不会改变。</p>]]></description><category>Java</category><comments>http://www.augweb.net/blog/post/84.html#comment</comments><wfw:comment>http://www.augweb.net/blog/</wfw:comment><wfw:commentRss>http://www.augweb.net/blog/feed.asp?cmt=84</wfw:commentRss><trackback:ping>http://www.augweb.net/blog/cmd.asp?act=tb&amp;id=84&amp;key=9bd34407</trackback:ping></item><item><title>由MyEclipse内存不足谈谈JVM内存</title><author>lorrons@gmail.com (lorron)</author><link>http://www.augweb.net/blog/post/83.html</link><pubDate>Sat, 27 Sep 2008 05:17:37 +0800</pubDate><guid>http://www.augweb.net/blog/post/83.html</guid><description><![CDATA[<p>如果没有进行设置的话，在使用MyEclipse的经常出现如下图所示内存不足的提示。<br><img alt="myeclipse.png" src="http://www.javatang.com/wp-content/myeclipse.png"><br>提示中说的很明白：“MyEclipse has detected that less than 5% of the 64MB of Perm Gen (Non-heap memory) space remains.”意思是说当前只有小于5%的非堆内存是空闲的。所以我们只要将这个值设置大一些就可以了。 <p>提示中给出了设置的参数： <ol> <li>-vmargs -Xms128M -Xmx512M -XX:PermSize=64M -XX:MaxPermSize=128M</li></ol> <p>这里有几个问题：<br>1. 各个参数的含义什么？<br>2. 为什么有的机器我将-Xmx和-XX:MaxPermSize都设置为512M之后Eclipse可以启动，而有些机器无法启动？<br>3. 为何将上面的参数写入到eclipse.ini文件Eclipse没有执行对应的设置？ <p>下面我们一一进行回答 <p><strong>1. 各个参数的含义什么？</strong> <p>参数中-vmargs的意思是设置JVM参数，所以后面的其实都是JVM的参数了，我们首先了解一下JVM内存管理的机制，然后再解释每个参数代表的含义。 <blockquote> <li><strong>堆(Heap)和非堆(Non-heap)内存</strong><br>按照官方的说法：“Java 虚拟机具有一个堆，堆是运行时数据区域，所有类实例和数组的内存均从此处分配。堆是在 Java 虚拟机启动时创建的。”“在JVM中堆之外的内存称为非堆内存(Non-heap memory)”。可以看出JVM主要管理两种类型的内存：堆和非堆。简单来说堆就是Java代码可及的内存，是留给开发人员使用的；非堆就是JVM留给自己用的，所以方法区、JVM内部处理或优化所需的内存(如JIT编译后的代码缓存)、每个类结构(如运行时常数池、字段和方法数据)以及方法和构造方法的代码都在非堆内存中。  <li><strong>堆内存分配</strong><br>JVM初始分配的内存由-Xms指定，默认是物理内存的1/64；JVM最大分配的内存由-Xmx指定，默认是物理内存的1/4。默认空余堆内存小于40%时，JVM就会增大堆直到-Xmx的最大限制；空余堆内存大于70%时，JVM会减少堆直到-Xms的最小限制。因此服务器一般设置-Xms、-Xmx相等以避免在每次GC 后调整堆的大小。  <li><strong>非堆内存分配</strong><br>JVM使用-XX:PermSize设置非堆内存初始值，默认是物理内存的1/64；由XX:MaxPermSize设置最大非堆内存的大小，默认是物理内存的1/4。  <li><strong>JVM内存限制(最大值)</strong><br>首先JVM内存限制于实际的最大物理内存(废话！呵呵)，假设物理内存无限大的话，JVM内存的最大值跟操作系统有很大的关系。简单的说就32位处理器虽然可控内存空间有4GB,但是具体的操作系统会给一个限制，这个限制一般是2GB-3GB（一般来说Windows系统下为1.5G-2G，Linux系统下为2G-3G），而64bit以上的处理器就不会有限制了。 </li></blockquote> <p><strong>2. 为什么有的机器我将-Xmx和-XX:MaxPermSize都设置为512M之后Eclipse可以启动，而有些机器无法启动？</strong> <p>通过上面对JVM内存管理的介绍我们已经了解到JVM内存包含两种：堆内存和非堆内存，另外JVM最大内存首先取决于实际的物理内存和操作系统。所以说设置VM参数导致程序无法启动主要有以下几种原因： <blockquote> <p>1) 参数中-Xms的值大于-Xmx，或者-XX:PermSize的值大于-XX:MaxPermSize； <p>2) -Xmx的值和-XX:MaxPermSize的总和超过了JVM内存的最大限制，比如当前操作系统最大内存限制，或者实际的物理内存等等。说到实际物理内存这里需要说明一点的是，如果你的内存是1024MB，但实际系统中用到的并不可能是1024MB，因为有一部分被硬件占用了。 </p></blockquote> <p><strong>3. 为何将上面的参数写入到eclipse.ini文件Eclipse没有执行对应的设置？</strong> <p>那为什么同样的参数在快捷方式或者命令行中有效而在eclipse.ini文件中是无效的呢？这是因为我们没有遵守eclipse.ini文件的设置规则： <blockquote> <p>参数形如“项 值”这种形式，中间有空格的需要换行书写，如果值中有空格的需要用双引号包括起来。比如我们使用-vm C:\Java\jre1.6.0\bin\javaw.exe参数设置虚拟机，在eclipse.ini文件中要写成这样： <ol> <li>-vm  <li>C:\Java\jre1.6.0\bin\javaw.exe</li></ol></blockquote> <p>按照上面所说的，最后参数在eclipse.ini中可以写成这个样子： <ol> <li>-vmargs  <li>-Xms128M  <li>-Xmx512M  <li>-XX:PermSize=64M  <li>-XX:MaxPermSize=128M</li></ol> <p>实际运行的结果可以通过Eclipse中“Help”-“About Eclipse SDK”窗口里面的“Configuration Details”按钮进行查看。 <p>另外需要说明的是，Eclipse压缩包中自带的eclipse.ini文件内容是这样的： <ol> <li>-showsplash  <li>org.eclipse.platform  <li>--launcher.XXMaxPermSize  <li>256m  <li>-vmargs  <li>-Xms40m  <li>-Xmx256m</li></ol> <p>其中–launcher.XXMaxPermSize（注意最前面是两个连接线）跟-XX:MaxPermSize参数的含义基本是一样的，我觉得唯一的区别就是前者是eclipse.exe启动的时候设置的参数，而后者是eclipse所使用的JVM中的参数。其实二者设置一个就可以了，所以这里可以把–launcher.XXMaxPermSize和下一行使用#注释掉。 <p>参考资料：<br><a href="http://blog.csdn.net/calvinxiu/archive/2007/05/18/1614473.aspx">JDK5.0垃圾收集优化之–Don’t Pause</a><br><a href="http://www.javaeye.com/topic/38142?page=1">提问：如何超越JVM内存限制？</a><br><a href="http://gceclub.sun.com.cn/Java_Docs/html/zh_CN/api/java/lang/management/MemoryMXBean.html">MemoryMXBean (Java 2 Platform SE 5.0)</a><br><a href="http://hi.baidu.com/nickshen3/blog/item/83d89852ba1ee60d0cf3e30b.html">MyEclipse/Eclipse的内存优化与内存不足的解决办法</a><br><a href="http://www.matrix.org.cn/thread.shtml?forumId=25&amp;topicId=c14f5fc6-81c0-11db-babc-9753a314dd4b">eclipse.ini文件的问题</a><br><a href="http://zhidao.baidu.com/question/36893010.html?si=1">eclipse 为什么报错</a>]]></description><category>Java</category><comments>http://www.augweb.net/blog/post/83.html#comment</comments><wfw:comment>http://www.augweb.net/blog/</wfw:comment><wfw:commentRss>http://www.augweb.net/blog/feed.asp?cmt=83</wfw:commentRss><trackback:ping>http://www.augweb.net/blog/cmd.asp?act=tb&amp;id=83&amp;key=3429523f</trackback:ping></item></channel></rss>
