<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-171648533238476397</id><updated>2012-02-16T21:34:07.015+08:00</updated><category term='生活'/><category term='Swing'/><category term='未来'/><category term='SwingWorker'/><category term='大自然'/><category term='现实环境'/><category term='随笔'/><category term='照片'/><category term='GlassFish'/><category term='Hibernate'/><category term='情衷'/><category term='救苦救难'/><category term='音乐'/><category term='NetBeans'/><category term='Java'/><category term='操作系统'/><category term='work'/><title type='text'>平步星云</title><subtitle type='html'>平步星云......&lt;br /&gt;
没有国界边疆，没有烽火硝烟，没有不动产，没有灾难和痛苦，不再你的我的！</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>49</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-1943745577838168161</id><published>2010-02-11T17:38:00.001+08:00</published><updated>2010-06-25T15:58:30.887+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='现实环境'/><title type='text'>再见 Blogspot</title><content type='html'>I have moved to &lt;a href="http://hi.baidu.com/quest2run"&gt;Baidu&lt;/a&gt;&lt;br /&gt;I will miss you ...&lt;br /&gt;&lt;br /&gt;Good luck!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-1943745577838168161?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/1943745577838168161/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=1943745577838168161' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/1943745577838168161'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/1943745577838168161'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2010/02/blogspot.html' title='再见 Blogspot'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-5498834794269945009</id><published>2010-02-11T13:28:00.001+08:00</published><updated>2010-02-11T13:28:53.367+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='情衷'/><category scheme='http://www.blogger.com/atom/ns#' term='音乐'/><title type='text'>如果生命只剩一天</title><content type='html'>&lt;pre&gt;Okay, hvis du fik at vide du havde en dag tilbage at leve i&lt;br /&gt;hvad ville du så gøre?&lt;br /&gt;好吧，如果生命只剩一天，你会做什么？&lt;br /&gt;Hvad jeg ville gøre?&lt;br /&gt;那我呢？&lt;br /&gt;Jeg tror jeg ville..&lt;br /&gt;如果是我，&lt;br /&gt;hæve lidt penge på min firma konto&lt;br /&gt;我会再从我公司的帐户取些钱，&lt;br /&gt;løb ned og shop den bil jeg altid havde tænkt på&lt;br /&gt;去买那辆心仪已久的车。&lt;br /&gt;vink når jeg så min nabo, hallo&lt;br /&gt;我的邻居挥挥手，嘿&lt;br /&gt;yo, bilen er ny og 24 tommer allo&lt;br /&gt;这可是辆2.4的新车&lt;br /&gt;Jeg ville ha den pige jeg elsker ved min side&lt;br /&gt;我会去找那个我一直心仪的女孩&lt;br /&gt;Køre ud mod vandet&lt;br /&gt;带她去海边&lt;br /&gt;Og ik ta noget forgivet&lt;br /&gt;管别人怎么说呢&lt;br /&gt;Jeg ville ringe til gamle venner og kærester&lt;br /&gt;我会打电话给我的哥们和女朋友&lt;br /&gt;fortælle dem at de har gjort mig til den jeg er&lt;br /&gt;告诉他们，是他们让我找回我自己&lt;br /&gt;kig mig i bakspejlet&lt;br /&gt;照照镜子&lt;br /&gt;og sig "hey det' godt nok"&lt;br /&gt;说一声：嘿，还挺帅！&lt;br /&gt;sæddet tilbage, vinduet ned og volumen op&lt;br /&gt;斜靠在椅之上，望着大敞的窗户，把收音机音量调到最大&lt;br /&gt;jeg ville gi en ****&lt;br /&gt;我可不想现在和女人上床&lt;br /&gt;hvorfor jeg var her&lt;br /&gt;那我在这干什么&lt;br /&gt;bare smile og nyde, at det var jeg&lt;br /&gt;只想笑，享受着真实的自我&lt;br /&gt;jeg ville samle mine venner og familie op&lt;br /&gt;我会叫上所有的朋友和家人，&lt;br /&gt;og køre videre ud mod vandet i en samlet flok&lt;br /&gt;一起去海边&lt;br /&gt;så ville jeg tænkte på om jeg havde givet nok igen&lt;br /&gt;然后好好想想是不是已经回报&lt;br /&gt;til dem der har givet mig så meget af dem&lt;br /&gt;所有已为我付出太多的人&lt;br /&gt;jeg ville pakere bilen midt ude på vejen&lt;br /&gt;我想要把车停在马路中央&lt;br /&gt;og der sku være musik, yo, min egen&lt;br /&gt;音乐响起，没错，我自己的音乐&lt;br /&gt;og alle ville smile og bounce med hinanden&lt;br /&gt;所有人都又笑又跳&lt;br /&gt;barbarque og kæmpe bål på stranden&lt;br /&gt;当然还要有海边烧烤&lt;br /&gt;jeg ville sige til mine brødre at jeg er stolt af dem&lt;br /&gt;我会告诉我的兄弟们我真的为他们骄傲&lt;br /&gt;at de sku forstå hvor meget jeg virkelig holder af dem&lt;br /&gt;他们一定明白我有多在乎他们&lt;br /&gt;jeg ville sige til min mor og far at jeg elsker dem&lt;br /&gt;我会告诉我的老爸老妈，我真的爱他们&lt;br /&gt;og spørge dem om de ik sku prøve at finde sammen igen&lt;br /&gt;然后再问问什么时候他们能重新在一起&lt;br /&gt;fortælle mine venner at jeg tror på&lt;br /&gt;我会告诉我的朋友们&lt;br /&gt;vores kærlighed er større end man kan sætte ord på&lt;br /&gt;我们之间，尽在不言中&lt;br /&gt;og jeg ville finde min kvinde og sige til hende&lt;br /&gt;我会找到真正属于我的姑娘然后对她说&lt;br /&gt;at jeg havde lyst til at leve videre i hende&lt;br /&gt;我就想这样，一直躺在她怀里&lt;br /&gt;og solen ville gå ned over vandet&lt;br /&gt;阳光洒在水面上&lt;br /&gt;mens jeg røg en sidste blå kings&lt;br /&gt;我抽着最后一支烟&lt;br /&gt;drak et sidste glas rødvin&lt;br /&gt;喝着最后一杯酒&lt;br /&gt;vind i håret&lt;br /&gt;风掠过我的头发&lt;br /&gt;rockstar briller på&lt;br /&gt;也掠过我的“rockstar”眼镜&lt;br /&gt;23 år 23岁了&lt;br /&gt;vi ses mit dannebrog&lt;br /&gt;我想看看我们的国旗&lt;br /&gt;En dag tilbage&lt;br /&gt;如果生命只剩一天&lt;br /&gt;lev mens du gør det&lt;br /&gt;不要停歇&lt;br /&gt;elsk mens du tør det&lt;br /&gt;勇敢去爱&lt;br /&gt;En dag tilbage&lt;br /&gt;如果生命只剩一天&lt;br /&gt;lev mens du gør det&lt;br /&gt;不要停歇&lt;br /&gt;elsk mens du tør det&lt;br /&gt;勇敢去爱&lt;br /&gt;En dag tilbage&lt;br /&gt;如果生命只剩一天&lt;br /&gt;lev mens du gør det&lt;br /&gt;不要停歇&lt;br /&gt;elsk mens du tør det&lt;br /&gt;勇敢去爱&lt;br /&gt;En dag tilbage&lt;br /&gt;如果生命只剩一天&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-5498834794269945009?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/5498834794269945009/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=5498834794269945009' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/5498834794269945009'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/5498834794269945009'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2010/02/blog-post.html' title='如果生命只剩一天'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-9001755603536163378</id><published>2010-01-03T17:33:00.004+08:00</published><updated>2010-01-03T17:40:04.362+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='work'/><title type='text'>This is American?</title><content type='html'>No people in the street at Christmas eve&lt;br /&gt;A few restaurants open at Christmas and New Year day&lt;br /&gt;Wear shorts in winter&lt;br /&gt;...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-9001755603536163378?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/9001755603536163378/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=9001755603536163378' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/9001755603536163378'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/9001755603536163378'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2010/01/this-is-american.html' title='This is American?'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-5456179478393530788</id><published>2009-11-25T16:26:00.003+08:00</published><updated>2009-11-29T01:42:52.129+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='生活'/><title type='text'>[转]最健康的作息时间表</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_bpUunzIgcNA/SxFhENTYjPI/AAAAAAAAATk/R7krJGADDxI/s1600/lifetime.jpeg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 399px; height: 400px;" src="http://4.bp.blogspot.com/_bpUunzIgcNA/SxFhENTYjPI/AAAAAAAAATk/R7krJGADDxI/s400/lifetime.jpeg" alt="" id="BLOGGER_PHOTO_ID_5409211352367009010" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;7:30：起床。英国威斯敏斯特大学的研究人员发现，那些在早上5:22―7:21 分起床的人，&lt;br /&gt;其血液中有一种能引起心脏病的物质含量较高，因此，在7:21之后起床对身体健康更加有益。&lt;br /&gt;打开台灯。“一醒来，就将灯打开，这样将会重新调整体内的生物钟，调整睡眠和醒来模式。&lt;br /&gt;”拉夫堡大学睡眠研究中心教授吉姆·霍恩说。&lt;br /&gt;喝一杯水。水是身体内成千上万化学反应得以进行的必需物质。早上喝一杯清水，&lt;br /&gt;可以补充晚上的缺水状态。&lt;br /&gt;&lt;br /&gt;7:30―8:00：在早饭之前刷牙。“在早饭之前刷牙可以防止牙齿的腐蚀，因为刷牙之后，&lt;br /&gt;可以在牙齿外面涂上一层含氟的保护层。要么，就等早饭之后半小时再刷牙。&lt;br /&gt;”英国牙齿协会健康和安全研究人员戈登·沃特金斯说。&lt;br /&gt;&lt;br /&gt;8:00―8:30：吃早饭。“早饭必须吃，因为它可以帮助你维持血糖水平的稳定。&lt;br /&gt;”伦敦大学国王学院营养师凯文·威尔伦说。早饭可以吃燕麦粥等，&lt;br /&gt;这类食物具有较低的血糖指数。&lt;br /&gt;&lt;br /&gt;8:30―9:00：避免运动。来自布鲁奈尔大学的研究人员发现，&lt;br /&gt;在早晨进行锻炼的运动员更容易感染疾病，因为免疫系统在这个时间的功能最弱。&lt;br /&gt;步行上班。马萨诸塞州大学医学院的研究人员发现，每天走路的人，&lt;br /&gt;比那些久坐不运动的人患感冒病的几率低25%。&lt;br /&gt;&lt;br /&gt;9:30：开始一天中最困难的工作。纽约睡眠中心的研究人员发现，&lt;br /&gt;大部分人在每天醒来的一两个小时内头脑最清醒。&lt;br /&gt;&lt;br /&gt;10:30：让眼睛离开屏幕休息一下。如果你使用电脑工作，&lt;br /&gt;那么每工作一小时，就让眼睛休息3分钟。&lt;br /&gt;&lt;br /&gt;11:00：吃点水果。这是一种解决身体血糖下降的好方法。&lt;br /&gt;吃一个橙子或一些红色水果，这样做能同时补充体内的铁含量和维生素C含量。&lt;br /&gt;&lt;br /&gt;13:00：在面包上加一些豆类蔬菜。你需要一顿可口的午餐，并且能够缓慢地释放能量。&lt;br /&gt;“烘烤的豆类食品富含纤维素，番茄酱可以当作是蔬菜的一部分。”维伦博士说。&lt;br /&gt;&lt;br /&gt;14:30―15:30：午休一小会儿。雅典的一所大学研究发现，那些每天中午午休30分钟或更长时间，每周至少午休3次的人，因心脏病死亡的几率会下降37%。&lt;br /&gt;&lt;br /&gt;16:00：喝杯酸奶。这样做可以稳定血糖水平。在每天三餐之间喝些酸牛奶，有利于心脏健康。&lt;br /&gt;&lt;br /&gt;17:00―19:00：锻炼身体。根据体内的生物钟，这个时间是运动的最佳时间，舍菲尔德大学运动学医生瑞沃·尼克说。&lt;br /&gt;&lt;br /&gt;19:30：晚餐少吃点。晚饭吃太多，会引起血糖升高，并增加消化系统的负担，影响睡眠。晚饭应该多吃蔬菜，少吃富含卡路里和蛋白质的食物。吃饭时要细嚼慢咽。&lt;br /&gt;&lt;br /&gt;21:45：看会电视。这个时间看会儿电视放松一下，有助于睡眠，但要注意，尽量不要躺在床上看电视，这会影响睡眠质量。&lt;br /&gt;&lt;br /&gt;23:00：洗个热水澡。“体温的适当降低有助于放松和睡眠。”拉夫堡大学睡眠研究中心吉姆·霍恩教授说。&lt;br /&gt;&lt;br /&gt;23:30：上床睡觉。如果你早上7点30起床，现在入睡可以保证你享受8小时充足的睡眠。&lt;br /&gt;     任何试图更改生物钟的行为，都将给身体留下莫名其妙的疾病，20、30年之后再后悔，已经来不及了。&lt;br /&gt;一、晚上9-11点为免疫系统（淋巴）排毒时间，此段时间应安静或听音乐。&lt;br /&gt;&lt;br /&gt;二、晚间11-凌晨1点，肝的排毒，需在熟睡中进行。&lt;br /&gt;&lt;br /&gt;三、凌晨1-3点，胆的排毒，亦同。&lt;br /&gt;&lt;br /&gt;四、凌晨3-5点，肺的排毒。此即为何咳嗽的人在这段时间咳得最剧烈，因排毒动作已走到肺；不应用止咳药，以免抑制废积物的排除。&lt;br /&gt;&lt;br /&gt;五、凌晨5-7点，大肠的排毒，应上厕所排便。&lt;br /&gt;&lt;br /&gt;六、凌晨7-9点，小肠大量吸收营养的时段，应吃早餐。疗病者最好早吃，在６点半前，养生者在７点半前，不吃早餐者应改变习惯，即使拖到9、10点吃都比不吃好。&lt;br /&gt;&lt;br /&gt;七、半夜至凌晨4点为脊椎造血时段，必须熟睡，不宜熬夜。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;　    记住身体健康作息时间表，安排好你的生活，让你的人生丰富多彩！&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-5456179478393530788?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/5456179478393530788/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=5456179478393530788' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/5456179478393530788'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/5456179478393530788'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2009/11/blog-post.html' title='[转]最健康的作息时间表'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_bpUunzIgcNA/SxFhENTYjPI/AAAAAAAAATk/R7krJGADDxI/s72-c/lifetime.jpeg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-9099072873531617048</id><published>2009-11-24T11:34:00.004+08:00</published><updated>2009-11-24T11:48:25.523+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>旅途中仓促引入 的bug</title><content type='html'>需求：当 endTime 比当前时间超过 20 年时，将 expiration date 置为空。&lt;br /&gt;&lt;br /&gt;错误地将 date 要么减 20 年，要么为null:&lt;br /&gt;&lt;br /&gt;      Calendar endTime = response.getConsumerService().getEndTime();&lt;br /&gt;      if (endTime != null) {&lt;br /&gt;          // roll endTime back 20 years&lt;br /&gt;          CalendarUtil.truncateDay(endTime).roll(Calendar.YEAR, -20);&lt;br /&gt;       &lt;br /&gt;          if (endTime.after(CalendarUtil.truncateDay(Calendar.getInstance()))) {&lt;br /&gt;              // If the expiration date of the current subscription received from ECWSis greater than 20 years, make this null&lt;br /&gt;              endTime = null;&lt;br /&gt;          }&lt;br /&gt;      }&lt;br /&gt;      currentSubscriptionDto.setExpirationDate(endTime);&lt;br /&gt;&lt;br /&gt;正确的逻辑应该为：&lt;br /&gt;      Calendar endTime = response.getConsumerService().getEndTime();&lt;br /&gt;      if (endTime != null) {&lt;br /&gt;          Calendar clonedEndTime = (Calendar)endTime.clone();&lt;br /&gt;       &lt;br /&gt;          // roll clonedEndTime back 20 years&lt;br /&gt;          CalendarUtil.truncateDay(clonedEndTime ).roll(Calendar.YEAR, -20);&lt;br /&gt;       &lt;br /&gt;          if (clonedEndTime .after(CalendarUtil.truncateDay(Calendar.getInstance()))) {&lt;br /&gt;              // If the expiration date of the current subscription received from ECWSis greater than 20 years, make this null&lt;br /&gt;              endTime = null;&lt;br /&gt;          }&lt;br /&gt;      }&lt;br /&gt;      currentSubscriptionDto.setExpirationDate(endTime);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;原本高兴地在机场第一次 bug fixing, 可是时间仓促，也是因为 Date 和 BigInteger,  BigDecimal 一样，思考起来一点也不直观。&lt;br /&gt;&lt;br /&gt;慎加注意！&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-9099072873531617048?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/9099072873531617048/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=9099072873531617048' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/9099072873531617048'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/9099072873531617048'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2009/11/bug.html' title='旅途中仓促引入 的bug'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-679783427554738185</id><published>2008-11-19T22:46:00.004+08:00</published><updated>2008-11-19T23:03:09.415+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='NetBeans'/><title type='text'>NetBeans 6.5 出来了！</title><content type='html'>&lt;a href="http://www.netbeans.org/downloads/"&gt;&lt;img src="http://www.netbeans.org/images/collateral/65/netbeans-button-110x32.gif" alt="Download NetBeans!" width="110" border="0" height="32" /&gt;&lt;/a&gt;&lt;br /&gt;尽管这一版 6.5 一直在“鼓吹”给 PHP 的朋友听，&lt;br /&gt;但是NetBeans team 还是没有忘本，有关JAVA IDE 的特征也不少：&lt;br /&gt;&lt;a href="http://wiki.netbeans.org/NewAndNoteWorthy"&gt;NetBeans IDE 6.5 Release Client - New and Noteworthy&lt;/a&gt;&lt;a href="http://www.netbeans.org/community/releases/65/"&gt;&lt;br /&gt;6.5 Release Information&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;下面这些是我个人比较喜欢的：&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Automatic Compile on Save&lt;/li&gt;&lt;li&gt;Improved Eclipse project import and synchronization&lt;/li&gt;&lt;li&gt;Java Call Hierarchy&lt;/li&gt;&lt;li&gt;Analyze Javadoc&lt;/li&gt;&lt;li&gt;CamelCase code completion &lt;/li&gt;&lt;li&gt;Customize formatting settings per project&lt;/li&gt;&lt;li&gt;Enhanced support for Spring, Hibernate&lt;/li&gt;&lt;li&gt;New multi-threaded debugging with improved UI and work-flow&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Have fun!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-679783427554738185?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/679783427554738185/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=679783427554738185' title='7 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/679783427554738185'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/679783427554738185'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2008/11/netbeans-65.html' title='NetBeans 6.5 出来了！'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-6031146870129978775</id><published>2008-11-16T23:06:00.008+08:00</published><updated>2008-11-17T00:29:40.023+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='NetBeans'/><title type='text'>JAVA 1.6.0_10 -Xmx</title><content type='html'>依次执行如下命令&lt;br /&gt;&lt;br /&gt;C:\Documents and Settings\pprun&gt;ver&lt;br /&gt;&lt;br /&gt;Microsoft Windows XP [版本 5.1.2600]&lt;br /&gt;&lt;br /&gt;C:\Documents and Settings\pprun&gt;java -version&lt;br /&gt;java version "1.6.0_10"&lt;br /&gt;Java(TM) SE Runtime Environment (build 1.6.0_10-b33)&lt;br /&gt;Java HotSpot(TM) Client VM (build 11.0-b15, mixed mode, sharing)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;C:\Documents and Settings\pprun&gt;java -Xmx&lt;span style="color: rgb(255, 0, 0);"&gt;2048m&lt;/span&gt; -version&lt;br /&gt;Error occurred during initialization of VM&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;Could not reserve enough space for object heap&lt;/span&gt;&lt;br /&gt;Could not create the Java virtual machine.&lt;br /&gt;&lt;br /&gt;2 G 内存，很新鲜吗？&lt;br /&gt;我刚加了一条，才百多块。&lt;br /&gt;然而，直到我试到 &lt;span style="color: rgb(0, 153, 0); font-weight: bold;"&gt;1446&lt;/span&gt; 这个可爱的幸运数字时，才成功：&lt;br /&gt;C:\Documents and Settings\pprun&gt;java -Xmx&lt;span style="color: rgb(255, 0, 0);"&gt;1447m&lt;/span&gt; -version&lt;br /&gt;Error occurred during initialization of VM&lt;br /&gt;Could not reserve enough space for object heap&lt;br /&gt;Could not create the Java virtual machine.&lt;br /&gt;&lt;br /&gt;C:\Documents and Settings\pprun&gt;java -Xmx&lt;span style="color: rgb(0, 153, 0);"&gt;1446m&lt;/span&gt; -version&lt;br /&gt;java version "1.6.0_10"&lt;br /&gt;Java(TM) SE Runtime Environment (build 1.6.0_10-b33)&lt;br /&gt;Java HotSpot(TM) Client VM (build 11.0-b15, mixed mode)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;我立即切换到 Ubunut8.04,进行了一下测试:&lt;br /&gt;&lt;br /&gt;pprun@pprun-t61:~$ uname -r&lt;br /&gt;2.6.24-21-generic&lt;br /&gt;pprun@pprun-t61:~$ sudo lsb_release -a&lt;br /&gt;No LSB modules are available.&lt;br /&gt;Distributor ID:    Ubuntu&lt;br /&gt;Description:    Ubuntu 8.04.1&lt;br /&gt;Release:    8.04&lt;br /&gt;Codename:    hardy&lt;br /&gt;&lt;br /&gt;pprun@pprun-t61:~$ java -Xmx3072m -version&lt;br /&gt;java version "1.6.0_10"&lt;br /&gt;Java(TM) SE Runtime Environment (build 1.6.0_10-b33)&lt;br /&gt;Java HotSpot(TM) Server VM (build 11.0-b15, mixed mode)&lt;br /&gt;&lt;br /&gt;pprun@pprun-t61:~$ java -Xmx3722m -version&lt;br /&gt;java version "1.6.0_10"&lt;br /&gt;Java(TM) SE Runtime Environment (build 1.6.0_10-b33)&lt;br /&gt;Java HotSpot(TM) Server VM (build 11.0-b15, mixed mode)&lt;br /&gt;&lt;br /&gt;pprun@pprun-t61:~$ java -Xmx&lt;span style="color: rgb(255, 0, 0);"&gt;3723m&lt;/span&gt; -version&lt;br /&gt;Error occurred during initialization of VM&lt;br /&gt;Could not reserve enough space for object heap&lt;br /&gt;Could not create the Java virtual machine.&lt;br /&gt;&lt;br /&gt;是不是 JAVA 也赞成 Windows XP 黑屏？&lt;br /&gt;竟然不能够分配超过 &lt;span style="color: rgb(0, 153, 0);"&gt;1446m &lt;span style="color: rgb(0, 0, 0);"&gt;(1.446g) 内存堆！&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-6031146870129978775?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/6031146870129978775/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=6031146870129978775' title='3 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/6031146870129978775'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/6031146870129978775'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2008/11/java-16010-xmx.html' title='JAVA 1.6.0_10 -Xmx'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-1815585992487207569</id><published>2008-09-17T08:23:00.001+08:00</published><updated>2008-09-17T08:24:17.825+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='现实环境'/><title type='text'>雷曼兄弟破产</title><content type='html'>病根在贪得无厌的利益最大化的追求&lt;br /&gt; &lt;br /&gt;因为大家迷失了方向和目的，只顾追求最大的利益，而丧失了价值评判的标准。当一切的一切都以利益为标准的时候，灭亡和灾难就很难完全地避免了。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-1815585992487207569?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/1815585992487207569/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=1815585992487207569' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/1815585992487207569'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/1815585992487207569'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2008/09/blog-post_17.html' title='雷曼兄弟破产'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-8006879667461435388</id><published>2008-09-15T22:49:00.003+08:00</published><updated>2008-09-15T22:56:35.217+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='大自然'/><title type='text'>人类染色体 (转)</title><content type='html'>&lt;table width="100%" bgcolor="#666666" cellpadding="2" cellspacing="1"&gt; &lt;tbody&gt; &lt;tr bgcolor="#ededdc"&gt; &lt;td valign="top" width="77"&gt; &lt;p&gt;&lt;strong&gt;染色体序号&lt;/strong&gt;&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="122"&gt; &lt;p&gt;&lt;strong&gt;碱基对数目（亿）&lt;/strong&gt;&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="162"&gt; &lt;p&gt;&lt;strong&gt;基因数目（包括假基因）&lt;/strong&gt;&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="300"&gt; &lt;p&gt;&lt;strong&gt;特点&lt;/strong&gt;&lt;/p&gt; &lt;/td&gt; &lt;/tr&gt; &lt;tr bgcolor="#ededdc"&gt; &lt;td valign="top" width="77"&gt; &lt;p&gt;&lt;a href="http://www.ebiotrade.com/newsf/2006-5/200651991537.htm" target="_blank"&gt;&lt;u&gt;&lt;font style="color: rgb(0, 102, 204);"&gt;1&lt;/font&gt;&lt;/u&gt;&lt;/a&gt;&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="122"&gt; &lt;p&gt;2.23&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="162"&gt; &lt;p&gt;3141(991假基因)&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="300"&gt; &lt;p&gt;第一大染色体&lt;/p&gt; &lt;/td&gt; &lt;/tr&gt; &lt;tr bgcolor="#ededdc"&gt; &lt;td valign="top" width="77"&gt; &lt;p&gt;&lt;a href="http://www.ebiotrade.com/newsf/2005-4/200548100858.htm" target="_blank"&gt;&lt;u&gt;&lt;font style="color: rgb(0, 102, 204);"&gt;2&lt;/font&gt;&lt;/u&gt;&lt;/a&gt;&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="122"&gt; &lt;p&gt;2.37&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="162"&gt; &lt;p&gt;1574&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="300"&gt; &lt;p&gt; 第二大染色体，含有能编码人体最大蛋白基因：由3.3万多个AA组成的激酶&lt;/p&gt; &lt;/td&gt; &lt;/tr&gt; &lt;tr bgcolor="#ededdc"&gt; &lt;td valign="top" width="77"&gt; &lt;p&gt;&lt;a href="http://www.ebiotrade.com/newsf/2006-4/200642891437.htm"&gt;&lt;u&gt;&lt;font style="color: rgb(0, 102, 204);"&gt; 3&lt;/font&gt;&lt;/u&gt;&lt;/a&gt;&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="122"&gt; &lt;p&gt;1.99&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="162"&gt; &lt;p&gt;1600&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="300"&gt; &lt;p&gt; 第三大染色体，在单个染色体水平发现的蛋白质编码基因最多，其中包括许多重要的chemokine受体基因簇，复合人类癌症基因，比如FHIT&lt;/p&gt; &lt;/td&gt; &lt;/tr&gt; &lt;tr bgcolor="#ededdc"&gt; &lt;td valign="top" width="77"&gt; &lt;p&gt;&lt;a href="http://www.ebiotrade.com/newsf/2005-4/200548100858.htm"&gt;&lt;u&gt;&lt;font style="color: rgb(0, 102, 204);"&gt; 4&lt;/font&gt;&lt;/u&gt;&lt;/a&gt;&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="122"&gt; &lt;p&gt;1.86&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="162"&gt; &lt;p&gt;2585&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="300"&gt; &lt;p&gt; 可能包含与亨廷顿氏病、多囊肾、肌肉萎缩症、沃夫─贺许宏氏症（一种因４号染色体短臂缺失导致的先天智障）等罕见疾病相关的基因&lt;/p&gt; &lt;/td&gt; &lt;/tr&gt; &lt;tr bgcolor="#ededdc"&gt; &lt;td valign="top" width="77"&gt; &lt;p&gt;5&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="122"&gt; &lt;p&gt;1.78&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="162"&gt; &lt;p&gt;923&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="300"&gt; &lt;p&gt;包含了许多染色体内部副本，是基因密度最低点的染色体之一&lt;/p&gt; &lt;/td&gt; &lt;/tr&gt; &lt;tr bgcolor="#ededdc"&gt; &lt;td valign="top" width="77"&gt; &lt;p&gt;&lt;a href="http://www.ebiotrade.com/newsf/2003-10/L2003102494520.htm" target="_blank"&gt;&lt;u&gt;&lt;font style="color: rgb(0, 102, 204);"&gt;6&lt;/font&gt;&lt;/u&gt;&lt;/a&gt;&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="122"&gt; &lt;p&gt;1.66&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="162"&gt; &lt;p&gt;2190&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="300"&gt; &lt;p&gt; 包含了导致遗传性血色素沉着病、帕金森氏症、癫痫等疾病的基因。这一染色体上基因的异常也是造成精神分裂症、癌症和心脏病等多种遗传性疾病的原因。也包含了一些MHC。&lt;/p&gt; &lt;/td&gt; &lt;/tr&gt; &lt;tr bgcolor="#ededdc"&gt; &lt;td valign="top" width="77"&gt; &lt;p&gt;&lt;a href="http://www.ebiotrade.com/newsf/2003-4/L2003413142831.htm"&gt;&lt;u&gt;&lt;font style="color: rgb(0, 102, 204);"&gt; 7&lt;/font&gt;&lt;/u&gt;&lt;/a&gt;&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="122"&gt; &lt;p&gt;1.58&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="162"&gt; &lt;p&gt;1455&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="300"&gt; &lt;p&gt; 第一个等臂染色体，其测序成功有助于研究治疗囊性纤维化、孤独症、耳聋、抽动——秽语综合征、视网膜色素变性、肾母细胞瘤、白血病和淋巴瘤等多种癌症以及其他疾病。&lt;/p&gt; &lt;/td&gt; &lt;/tr&gt; &lt;tr bgcolor="#ededdc"&gt; &lt;td valign="top" width="77"&gt; &lt;p&gt;8&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="122"&gt; &lt;p&gt;1.46&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="162"&gt; &lt;p&gt;1887&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="300"&gt; &lt;p&gt;含有大脑和免疫功能的遗传基因，极有可能与人类进化密切相关&lt;/p&gt; &lt;/td&gt; &lt;/tr&gt; &lt;tr bgcolor="#ededdc"&gt; &lt;td valign="top" width="77"&gt; &lt;p&gt;9&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="122"&gt; &lt;p&gt;1.09&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="162"&gt; &lt;p&gt;1575&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="300"&gt; &lt;p&gt;95个基因与疾病有关，其中之一可抑制肿瘤形成&lt;/p&gt; &lt;/td&gt; &lt;/tr&gt; &lt;tr bgcolor="#ededdc"&gt; &lt;td valign="top" width="77"&gt; &lt;p&gt;10&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="122"&gt; &lt;p&gt;1.32&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="162"&gt; &lt;p&gt;1246&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="300"&gt; &lt;p&gt; 85个基因与疾病有关。这些基因的突变可能引发乳腺癌、前列腺癌和脑癌等。还有一些基因与复杂的代谢疾病和精神疾病有关，例如I型糖尿病、精神分裂症和阿耳茨海默氏症等。&lt;/p&gt; &lt;/td&gt; &lt;/tr&gt; &lt;tr bgcolor="#ededdc"&gt; &lt;td valign="top" width="77"&gt; &lt;p&gt;&lt;a href="http://www.ebiotrade.com/newsf/2006-3/200632491926.htm" target="_blank"&gt;&lt;u&gt;&lt;font style="color: rgb(0, 102, 204);"&gt;11&lt;/font&gt;&lt;/u&gt;&lt;/a&gt;&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="122"&gt; &lt;p&gt;1.35&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="162"&gt; &lt;p&gt;2289&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="300"&gt; &lt;p&gt; 人类856个嗅觉受体基因中40%以上是定位在这个染色体上，还有86个未知分子机制的相关基因，包括几个mendelian traits、癌症和易感基因位点。&lt;/p&gt; &lt;/td&gt; &lt;/tr&gt; &lt;tr bgcolor="#ededdc"&gt; &lt;td valign="top" width="77"&gt; &lt;p&gt;&lt;a href="http://www.ebiotrade.com/newsf/2006-3/200631790819.htm" target="_blank"&gt;&lt;u&gt;&lt;font style="color: rgb(0, 102, 204);"&gt;12&lt;/font&gt;&lt;/u&gt;&lt;/a&gt;&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="122"&gt; &lt;p&gt;1.31&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="162"&gt; &lt;p&gt;1400&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="300"&gt; &lt;p&gt; 有一个目前在人类基因组上发现的最大的连锁不平衡，还有若干在特定类型的癌症、运动失调症、以及还可能包括“阿尔茨海默氏症”在内的疾病中发生突变的基因。&lt;/p&gt; &lt;/td&gt; &lt;/tr&gt; &lt;tr bgcolor="#ededdc"&gt; &lt;td valign="top" width="77"&gt; &lt;p&gt;&lt;a href="http://www.ebiotrade.com/newsf/2004-4/L200441101948.htm" target="_blank"&gt;&lt;u&gt;&lt;font style="color: rgb(0, 102, 204);"&gt;13&lt;/font&gt;&lt;/u&gt;&lt;/a&gt;&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="122"&gt; &lt;p&gt;0.96&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="162"&gt; &lt;p&gt;929&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="300"&gt; &lt;p&gt; 染色体密度小（6.5gene./Mb），包括与乳腺癌相关的BRCA2基因，和与眼癌、精神分裂症有关的基因。&lt;/p&gt; &lt;/td&gt; &lt;/tr&gt; &lt;tr bgcolor="#ededdc"&gt; &lt;td valign="top" width="77"&gt; &lt;p&gt;&lt;a href="http://www.ebiotrade.com/newsf/2003-1/L20031312029.htm" target="_blank"&gt;&lt;u&gt;&lt;font style="color: rgb(0, 102, 204);"&gt;14&lt;/font&gt;&lt;/u&gt;&lt;/a&gt;&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="122"&gt; &lt;p&gt;0.87&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="162"&gt; &lt;p&gt;1050&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="300"&gt; &lt;p&gt; 有大约60多个与遗传疾病密切相关的基因，其中包括一个此前已被发现与阿尔茨海默症有联系的基因。还有另2个对于人体免疫系统具有重要意义基因以及一些与其它病症有关的基因&lt;/p&gt; &lt;/td&gt; &lt;/tr&gt; &lt;tr bgcolor="#ededdc"&gt; &lt;td valign="top" width="77"&gt; &lt;p&gt;&lt;a href="http://www.ebiotrade.com/newsf/2006-3/2006331151247.htm" target="_blank"&gt;&lt;u&gt;&lt;font style="color: rgb(0, 102, 204);"&gt;15&lt;/font&gt;&lt;/u&gt;&lt;/a&gt;&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="122"&gt; &lt;p&gt;0.82&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="162"&gt; &lt;p&gt;945&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="300"&gt; &lt;p&gt; 是目前已知的7个大片段扩增的人类染色体之一，这一染色体复制的不寻常之处就在于这种片段扩增集中在两个相隔甚远的区域——15号染色体长臂近端和远端，而不是沿染色体分布，其中远端区域包含了可引起Prader-Willi 和 Angelman综合症的基因缺失。而且大部分染色体之间的复制都有一个共同的祖先。&lt;/p&gt; &lt;/td&gt; &lt;/tr&gt; &lt;tr bgcolor="#ededdc"&gt; &lt;td valign="top" width="77"&gt; &lt;p&gt;&lt;a href="http://www.ebiotrade.com/newsf/2004-12/2004122493735.htm" target="_blank"&gt;&lt;u&gt;&lt;font style="color: rgb(0, 102, 204);"&gt;16&lt;/font&gt;&lt;/u&gt;&lt;/a&gt;&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="122"&gt; &lt;p&gt;0.79 （78,884,754）&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="162"&gt; &lt;p&gt;880&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="300"&gt; &lt;p&gt; 是DNA修复基因所在之处。对16号染色体分析的结果还会对重金属的解毒和运输有重要意义&lt;/p&gt; &lt;/td&gt; &lt;/tr&gt; &lt;tr bgcolor="#ededdc"&gt; &lt;td valign="top" width="77"&gt; &lt;p&gt;&lt;a href="http://www.ebiotrade.com/newsf/2006-4/200642191602.htm" target="_blank"&gt;&lt;u&gt;&lt;font style="color: rgb(0, 102, 204);"&gt;17&lt;/font&gt;&lt;/u&gt;&lt;/a&gt;&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="122"&gt; &lt;p&gt;0.79 (78,839,971)&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="162"&gt; &lt;p&gt;1540&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="300"&gt; &lt;p&gt; 很特殊的染色体，包括多种与疾病有关的基因例如确定出的第一个乳腺癌基因BRCA1、神经纤维瘤基因NF1、与修复DNA损伤有关的 TP53基因、SMS（Smith-Magenis综合症）和CMT1A&lt;/p&gt; &lt;/td&gt; &lt;/tr&gt; &lt;tr bgcolor="#ededdc"&gt; &lt;td valign="top" width="77"&gt; &lt;p&gt;&lt;a href="http://www.ebiotrade.com/newsf/2005-9/200592392342.htm" target="_blank"&gt;&lt;u&gt;&lt;font style="color: rgb(0, 102, 204);"&gt;18&lt;/font&gt;&lt;/u&gt;&lt;/a&gt;&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="122"&gt; &lt;p&gt; &lt;/p&gt;&lt;br /&gt;&lt;/td&gt; &lt;td valign="top" width="162"&gt; &lt;p&gt; &lt;/p&gt;&lt;br /&gt;&lt;/td&gt; &lt;td valign="top" width="300"&gt; &lt;p&gt; 只有三种染色体异常（形成三倍体）的人可以长大，这在其中包含了18号染色体。另外还有许多遗传疾病是由于18号染色体的三倍体或非整倍而造成的。尽管基因密度低，但它所有哺乳动物进化上保守的非编码蛋白区域所占比例与整个基因组范围的平均值相接近。&lt;/p&gt; &lt;/td&gt; &lt;/tr&gt; &lt;tr bgcolor="#ededdc"&gt; &lt;td valign="top" width="77"&gt; &lt;p&gt;&lt;a href="http://www.ebiotrade.com/newsf/2004-4/L200441101948.htm" target="_blank"&gt;&lt;u&gt;&lt;font style="color: rgb(0, 102, 204);"&gt;19&lt;/font&gt;&lt;/u&gt;&lt;/a&gt;&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="122"&gt; &lt;p&gt;0.56&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="162"&gt; &lt;p&gt;1782&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="300"&gt; &lt;p&gt; 包括与遗传性高胆固醇和抗胰岛素糖尿病相关的基因，人体遭到辐射或其他环境污染，控制DNA修复的基因也在该染色体上&lt;/p&gt; &lt;/td&gt; &lt;/tr&gt; &lt;tr bgcolor="#ededdc"&gt; &lt;td valign="top" width="77"&gt; &lt;p&gt;&lt;a href="http://www.ebiotrade.com/newsf/2001-12/L2001122111581.htm" target="_blank"&gt;&lt;u&gt;&lt;font style="color: rgb(0, 102, 204);"&gt;20&lt;/font&gt;&lt;/u&gt;&lt;/a&gt;&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="122"&gt; &lt;p&gt;0.59&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="162"&gt; &lt;p&gt;727&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="300"&gt; &lt;p&gt; 是被“破译”的第一对具有典型长短臂结构的人类染色体，为糖尿病、肥胖症、小儿湿疹等疾病的治疗找到了新方法。该染色体上还有一个基因能增加部分人群因疯牛病感染新型克雅氏症的危险，这将增进人们对该疾病的了解。&lt;/p&gt; &lt;/td&gt; &lt;/tr&gt; &lt;tr bgcolor="#ededdc"&gt; &lt;td valign="top" width="77"&gt; &lt;p&gt;&lt;a href="http://www.ebiotrade.com/newsf/2000-5/71.htm" target="_blank"&gt;&lt;u&gt;&lt;font style="color: rgb(0, 102, 204);"&gt;21&lt;/font&gt;&lt;/u&gt;&lt;/a&gt;&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="122"&gt; &lt;p&gt;0.34&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="162"&gt; &lt;p&gt;284&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="300"&gt; &lt;p&gt; 最短的染色体，发现许多与疾病相关的基因均分布在这一染色体上，特别是先天愚型、早老性痴呆、癫痫等一些神经系统的疾病。&lt;/p&gt; &lt;/td&gt; &lt;/tr&gt; &lt;tr bgcolor="#ededdc"&gt; &lt;td valign="top" width="77"&gt; &lt;p&gt;22&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="122"&gt; &lt;p&gt;0.33&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="162"&gt; &lt;p&gt;679&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="300"&gt; &lt;p&gt; 与先天性心脏病、免疫功能低下、精神分裂症、智力低下、出生缺陷以及许多恶性肿瘤如白血病等有关&lt;/p&gt; &lt;/td&gt; &lt;/tr&gt; &lt;tr bgcolor="#ededdc"&gt; &lt;td valign="top" width="77"&gt; &lt;p&gt;&lt;a href="http://www.ebiotrade.com/newsf/2005-3/2005318124534.htm" target="_blank"&gt;&lt;u&gt;&lt;font style="color: rgb(0, 102, 204);"&gt;X&lt;/font&gt;&lt;/u&gt;&lt;/a&gt;&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="122"&gt; &lt;p&gt;1.50&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="162"&gt; &lt;p&gt;1098&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="300"&gt; &lt;p&gt; X染色体上一旦出现某个基因，就不会在进化中再失去它。同时X染色体与遗传性疾病高度相关，还有许多与智力缺陷有关的基因以及人类基因组中称为DMD的最大基因&lt;/p&gt; &lt;/td&gt; &lt;/tr&gt; &lt;tr bgcolor="#ededdc"&gt; &lt;td valign="top" width="77"&gt; &lt;p&gt;Y&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="122"&gt; &lt;p&gt;0.23&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="162"&gt; &lt;p&gt;78&lt;/p&gt; &lt;/td&gt; &lt;td valign="top" width="300"&gt; &lt;p&gt; 这个一向被认为很脆弱的性染色体内部存在一些“回文结构”，可能有着基因修复作用，使它在一定程度上能够自我修复有害的基因变异。这一成果增进了人们对男性不育症的了解，有助于研究更好的诊断和治疗方法。它还将重新激起有关性别的进化历程的争论。&lt;/p&gt; &lt;/td&gt; &lt;/tr&gt; &lt;/tbody&gt; &lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-8006879667461435388?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/8006879667461435388/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=8006879667461435388' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/8006879667461435388'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/8006879667461435388'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2008/09/blog-post_9146.html' title='人类染色体 (转)'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-5283919839668117857</id><published>2008-08-29T17:24:00.003+08:00</published><updated>2008-08-29T17:48:46.926+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate'/><title type='text'>关于 hjpetstore 的源码</title><content type='html'>承蒙大家对 hjpetstore 的喜爱，最近有不少同学请求该工程的源码。&lt;br /&gt;为了方便大家获得，我把流程说一下：&lt;br /&gt;1. 点击本博客右边的导航栏上 -&gt; 我的开源工程 | &lt;a href="https://hjpetstore.dev.java.net/"&gt;hjpetstore&lt;/a&gt; &lt;br /&gt;2. 如果你还没有注册 java.net 的成员，请加入！　（这里可是 Java 宝库）&lt;br /&gt;3. 回到 hjpetstore 工程首页，在左边的导航栏上点击 CVS&lt;br /&gt;4. 里头就是关于怎么 checkout 的指令&lt;br /&gt;5. 如果你用的是 Netbeans 作为开发环境， checkout 出来后更方便些，调整 server 设置和 lib 的路径后，就可以编译了。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;另外，感兴趣的同学，可以申请成为项目的成员（各类成员都欢迎），我们的目标是更好的工作！&lt;br /&gt;我由于任务繁重，现在没有太多时间来更新它，比如 Hibernate 和 Spring 新的版本的新特征！&lt;br /&gt;另外有外国的朋友曾请求我把系列文章翻译成英文，但我哪有那个空 :)&lt;br /&gt;&lt;br /&gt;祝大家工作愉快！&lt;br /&gt;&lt;br /&gt;Pprun&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-5283919839668117857?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/5283919839668117857/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=5283919839668117857' title='3 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/5283919839668117857'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/5283919839668117857'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2008/08/hjpetstore.html' title='关于 hjpetstore 的源码'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-2032470089506544797</id><published>2008-08-26T21:28:00.004+08:00</published><updated>2008-08-27T08:47:40.110+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='照片'/><title type='text'>Photos from Beijing 2008 Olympic Games, Day 12</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_bpUunzIgcNA/SLQF--MkF8I/AAAAAAAAANw/EVObt97jdxo/s1600-h/1.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_bpUunzIgcNA/SLQF--MkF8I/AAAAAAAAANw/EVObt97jdxo/s400/1.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5238818845944453058" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_bpUunzIgcNA/SLQF_H5N-TI/AAAAAAAAAN4/HHcXQZnu72Y/s1600-h/2.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_bpUunzIgcNA/SLQF_H5N-TI/AAAAAAAAAN4/HHcXQZnu72Y/s400/2.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5238818848547666226" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_bpUunzIgcNA/SLQF_QS7qlI/AAAAAAAAAOA/vKDT19WWxmU/s1600-h/3.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_bpUunzIgcNA/SLQF_QS7qlI/AAAAAAAAAOA/vKDT19WWxmU/s400/3.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5238818850803001938" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_bpUunzIgcNA/SLQF_9LvKbI/AAAAAAAAAOI/4FAzieW1mZY/s1600-h/4.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_bpUunzIgcNA/SLQF_9LvKbI/AAAAAAAAAOI/4FAzieW1mZY/s400/4.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5238818862852417970" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_bpUunzIgcNA/SLQGCoWchLI/AAAAAAAAAOQ/t1i3XbFSN74/s1600-h/5.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_bpUunzIgcNA/SLQGCoWchLI/AAAAAAAAAOQ/t1i3XbFSN74/s400/5.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5238818908799796402" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_bpUunzIgcNA/SLQHOYTmFjI/AAAAAAAAAOY/nwbkdfXs-Xw/s1600-h/6.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_bpUunzIgcNA/SLQHOYTmFjI/AAAAAAAAAOY/nwbkdfXs-Xw/s400/6.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5238820210162931250" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_bpUunzIgcNA/SLQHOubZOcI/AAAAAAAAAOg/-72C2A0E15E/s1600-h/7.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_bpUunzIgcNA/SLQHOubZOcI/AAAAAAAAAOg/-72C2A0E15E/s400/7.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5238820216101222850" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_bpUunzIgcNA/SLQHOzRNRbI/AAAAAAAAAOo/RDs95auj-Yw/s1600-h/8.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_bpUunzIgcNA/SLQHOzRNRbI/AAAAAAAAAOo/RDs95auj-Yw/s400/8.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5238820217400673714" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_bpUunzIgcNA/SLQHPJiXwtI/AAAAAAAAAOw/pdRNgaJXehI/s1600-h/9.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_bpUunzIgcNA/SLQHPJiXwtI/AAAAAAAAAOw/pdRNgaJXehI/s400/9.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5238820223378244306" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_bpUunzIgcNA/SLQHPyUntYI/AAAAAAAAAO4/Uy3rSOymAWw/s1600-h/10.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_bpUunzIgcNA/SLQHPyUntYI/AAAAAAAAAO4/Uy3rSOymAWw/s400/10.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5238820234326422914" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_bpUunzIgcNA/SLQIlIy6i-I/AAAAAAAAAPA/barGVssZ81k/s1600-h/11.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_bpUunzIgcNA/SLQIlIy6i-I/AAAAAAAAAPA/barGVssZ81k/s400/11.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5238821700647947234" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_bpUunzIgcNA/SLQIlbh6c0I/AAAAAAAAAPI/eG4lNynBhkQ/s1600-h/12.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_bpUunzIgcNA/SLQIlbh6c0I/AAAAAAAAAPI/eG4lNynBhkQ/s400/12.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5238821705676911426" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_bpUunzIgcNA/SLQIlrQq3FI/AAAAAAAAAPQ/MlZG9cZoYW4/s1600-h/13.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_bpUunzIgcNA/SLQIlrQq3FI/AAAAAAAAAPQ/MlZG9cZoYW4/s400/13.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5238821709899553874" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_bpUunzIgcNA/SLQIl7QVpgI/AAAAAAAAAPY/Pf2xosgCX_k/s1600-h/14.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_bpUunzIgcNA/SLQIl7QVpgI/AAAAAAAAAPY/Pf2xosgCX_k/s400/14.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5238821714193131010" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_bpUunzIgcNA/SLQImjmTTSI/AAAAAAAAAPg/eiJdPTxplAo/s1600-h/15.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_bpUunzIgcNA/SLQImjmTTSI/AAAAAAAAAPg/eiJdPTxplAo/s400/15.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5238821725022670114" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_bpUunzIgcNA/SLQJu6CaVfI/AAAAAAAAAPo/06YS_NTcu5o/s1600-h/16.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_bpUunzIgcNA/SLQJu6CaVfI/AAAAAAAAAPo/06YS_NTcu5o/s400/16.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5238822967996732914" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_bpUunzIgcNA/SLQJvJu3KRI/AAAAAAAAAPw/X3fDp3_F0-E/s1600-h/17.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_bpUunzIgcNA/SLQJvJu3KRI/AAAAAAAAAPw/X3fDp3_F0-E/s400/17.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5238822972209703186" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_bpUunzIgcNA/SLQJvQv1gBI/AAAAAAAAAP4/x8CN9BTTzWg/s1600-h/18.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_bpUunzIgcNA/SLQJvQv1gBI/AAAAAAAAAP4/x8CN9BTTzWg/s400/18.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5238822974092836882" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_bpUunzIgcNA/SLQJv6Uv7TI/AAAAAAAAAQA/KEywXZRCDEo/s1600-h/19.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_bpUunzIgcNA/SLQJv6Uv7TI/AAAAAAAAAQA/KEywXZRCDEo/s400/19.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5238822985253514546" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_bpUunzIgcNA/SLQJwQSXtEI/AAAAAAAAAQI/neV5VBycGmE/s1600-h/20.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_bpUunzIgcNA/SLQJwQSXtEI/AAAAAAAAAQI/neV5VBycGmE/s400/20.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5238822991149118530" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_bpUunzIgcNA/SLQKsW5YEpI/AAAAAAAAAQQ/T0jrVfP-t3g/s1600-h/21.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_bpUunzIgcNA/SLQKsW5YEpI/AAAAAAAAAQQ/T0jrVfP-t3g/s400/21.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5238824023715484306" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_bpUunzIgcNA/SLQKspzkUUI/AAAAAAAAAQY/I2D797u0KoA/s1600-h/22.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_bpUunzIgcNA/SLQKspzkUUI/AAAAAAAAAQY/I2D797u0KoA/s400/22.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5238824028791394626" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_bpUunzIgcNA/SLQKtOkaMtI/AAAAAAAAAQg/DDs0VfQnYjI/s1600-h/23.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_bpUunzIgcNA/SLQKtOkaMtI/AAAAAAAAAQg/DDs0VfQnYjI/s400/23.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5238824038659928786" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_bpUunzIgcNA/SLQKtTczH9I/AAAAAAAAAQo/tIirT1qMCmE/s1600-h/24.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_bpUunzIgcNA/SLQKtTczH9I/AAAAAAAAAQo/tIirT1qMCmE/s400/24.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5238824039970185170" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_bpUunzIgcNA/SLQKtocTChI/AAAAAAAAAQw/LQSXmyympic/s1600-h/25.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_bpUunzIgcNA/SLQKtocTChI/AAAAAAAAAQw/LQSXmyympic/s400/25.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5238824045605227026" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_bpUunzIgcNA/SLQLvVQOVlI/AAAAAAAAAQ4/Naf1rk9zFMQ/s1600-h/26.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_bpUunzIgcNA/SLQLvVQOVlI/AAAAAAAAAQ4/Naf1rk9zFMQ/s400/26.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5238825174325679698" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_bpUunzIgcNA/SLQLv3kDavI/AAAAAAAAARA/vVigp_veBNo/s1600-h/27.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_bpUunzIgcNA/SLQLv3kDavI/AAAAAAAAARA/vVigp_veBNo/s400/27.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5238825183535655666" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_bpUunzIgcNA/SLQLyXVAnyI/AAAAAAAAARI/pEfEU5ZWEjA/s1600-h/28.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_bpUunzIgcNA/SLQLyXVAnyI/AAAAAAAAARI/pEfEU5ZWEjA/s400/28.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5238825226422230818" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_bpUunzIgcNA/SLQLzAn_bCI/AAAAAAAAARQ/dbSmaJGHKY4/s1600-h/29.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_bpUunzIgcNA/SLQLzAn_bCI/AAAAAAAAARQ/dbSmaJGHKY4/s400/29.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5238825237507697698" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-2032470089506544797?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/2032470089506544797/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=2032470089506544797' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/2032470089506544797'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/2032470089506544797'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2008/08/photos-from-beijing-olympic-games-day.html' title='Photos from Beijing 2008 Olympic Games, Day 12'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_bpUunzIgcNA/SLQF--MkF8I/AAAAAAAAANw/EVObt97jdxo/s72-c/1.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-8651688643690808256</id><published>2008-07-21T11:34:00.003+08:00</published><updated>2008-07-21T11:40:12.218+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='操作系统'/><title type='text'>Ubuntu 8.04 语言环境和字符编码</title><content type='html'>一. Ubuntu默认的中文字符编码&lt;br /&gt;在/etc/environment中看到：&lt;br /&gt;$sudo gedit /etc/environment&lt;br /&gt;LANG="zh_CN.UTF-8"&lt;br /&gt;LANGUAGE="zh_CN:zh:en_US:en"&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;二. 添加中文字符编码的方法&lt;br /&gt;1. 直接使用locale-gen命令：&lt;br /&gt;$ sudo locale-gen zh_CN.GB18030&lt;br /&gt;$ cd /usr/lib/locale/&lt;br /&gt;  可以看到生成了一个zh_CN.gb18030文件夹&lt;br /&gt;$ gedit /var/lib/locales/supported.d/local&lt;br /&gt;  文件中多了一行：zh_CN.GB18030 GB18030&lt;br /&gt;&lt;br /&gt;2. 通过修改/var/lib/locales/supported.d/local文件&lt;br /&gt;$ sudo gedit /var/lib/locales/supported.d/local&lt;br /&gt;zh_CN.UTF-8 UTF-8&lt;br /&gt;en_US.UTF-8 UTF-8&lt;br /&gt;&lt;br /&gt;增加一行：&lt;br /&gt;zh_CN.GBK GBK&lt;br /&gt;后保存后退出。&lt;br /&gt;&lt;br /&gt;$ sudo dpkg-reconfigure locales&lt;br /&gt;&lt;br /&gt;Generating locales...&lt;br /&gt;  ...&lt;br /&gt;  en_US.UTF-8... done&lt;br /&gt;  en_ZA.UTF-8... done&lt;br /&gt;  en_ZW.UTF-8... done&lt;br /&gt;  zh_CN.GBK... done&lt;br /&gt;  zh_CN.UTF-8... up-to-date&lt;br /&gt;  ...&lt;br /&gt;Generation complete.&lt;br /&gt;&lt;br /&gt;即可生成相应文件：/usr/lib/locale/zh_CN.gbk/&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-8651688643690808256?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/8651688643690808256/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=8651688643690808256' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/8651688643690808256'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/8651688643690808256'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2008/07/ubuntu-804.html' title='Ubuntu 8.04 语言环境和字符编码'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-7774244065695867317</id><published>2008-07-12T22:38:00.002+08:00</published><updated>2008-07-12T22:48:31.751+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='操作系统'/><title type='text'>复制粘贴功能无法使用</title><content type='html'>已经好长时间没有使用 M$ Windows 了，前两天由于用到一个银行的网上转帐，只有Windows版本的软件，所以又启动了它。&lt;br /&gt;发现好多东西都不是那么顺眼了，装了一个最新的 FireFox 3.0，突然发现 ctrl-c, ctrl-v 不能用了，我试试很多次，以为是这个3.0有问题，卸载重新FireFox2.x，还是这样，试试其他应用程序，都一样。怎么办呢？&lt;br /&gt;到网上找了找，原来我刚进来就又中毒了。&lt;br /&gt;&lt;br /&gt;解决办法：&lt;br /&gt;&lt;br /&gt;重新注册以下DLL文件&lt;br /&gt;regsvr32 Shdocvw.dll &lt;br /&gt;regsvr32 Shell32.dll　（注意这个命令，先不用输） &lt;br /&gt;regsvr32 Oleaut32.dll &lt;br /&gt;regsvr32 Actxprxy.dll &lt;br /&gt;regsvr32 Mshtml.dll &lt;br /&gt;regsvr32 Urlmon.dll &lt;br /&gt;第二个命令可以先不用输，输完这些命令后重新启动windows，如果发现无效，再重新输入一遍，这次输入第二个命令。&lt;br /&gt;&lt;br /&gt;现在好了，但是希望我以后还是少用 Windows, 因为它总是浪费我的宝贵时间！&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-7774244065695867317?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/7774244065695867317/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=7774244065695867317' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/7774244065695867317'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/7774244065695867317'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2008/07/blog-post.html' title='复制粘贴功能无法使用'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-6319843910501080186</id><published>2008-06-01T22:34:00.006+08:00</published><updated>2008-06-01T22:57:09.874+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>列出 JVM／JRE 当前的所有系统属性</title><content type='html'>使用一行代码即可得知：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public static void main(String[] args) {&lt;br /&gt; System.getProperties().list(System.out);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;以下是我的输出：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;-- listing properties --&lt;br /&gt;java.runtime.name=Java(TM) SE Runtime Environment&lt;br /&gt;sun.boot.library.path=/usr/lib/jvm/java-6-sun-1.6.0.06/jre/...&lt;br /&gt;java.vm.version=10.0-b22&lt;br /&gt;java.vm.vendor=Sun Microsystems Inc.&lt;br /&gt;java.vendor.url=http://java.sun.com/&lt;br /&gt;path.separator=:&lt;br /&gt;java.vm.name=Java HotSpot(TM) 64-Bit Server VM&lt;br /&gt;file.encoding.pkg=sun.io&lt;br /&gt;user.country=CN&lt;br /&gt;sun.java.launcher=SUN_STANDARD&lt;br /&gt;sun.os.patch.level=unknown&lt;br /&gt;java.vm.specification.name=Java Virtual Machine Specification&lt;br /&gt;user.dir=/home/****/code/NetBeansProjects/Main&lt;br /&gt;java.runtime.version=1.6.0_06-b02&lt;br /&gt;java.awt.graphicsenv=sun.awt.X11GraphicsEnvironment&lt;br /&gt;java.endorsed.dirs=/usr/lib/jvm/java-6-sun-1.6.0.06/jre/...&lt;br /&gt;os.arch=amd64&lt;br /&gt;java.io.tmpdir=/tmp&lt;br /&gt;line.separator=&lt;br /&gt;&lt;br /&gt;java.vm.specification.vendor=Sun Microsystems Inc.&lt;br /&gt;os.name=Linux&lt;br /&gt;sun.jnu.encoding=UTF-8&lt;br /&gt;java.library.path=/usr/lib/jvm/java-6-sun-1.6.0.06/jre/...&lt;br /&gt;java.specification.name=Java Platform API Specification&lt;br /&gt;java.class.version=50.0&lt;br /&gt;sun.management.compiler=HotSpot 64-Bit Server Compiler&lt;br /&gt;os.version=2.6.24-17-generic&lt;br /&gt;user.home=/home/****&lt;br /&gt;user.timezone=&lt;br /&gt;java.awt.printerjob=sun.print.PSPrinterJob&lt;br /&gt;file.encoding=UTF-8&lt;br /&gt;java.specification.version=1.6&lt;br /&gt;user.name=****&lt;br /&gt;java.class.path=/home/****/code/NetBeansProjects/Mai...&lt;br /&gt;java.vm.specification.version=1.0&lt;br /&gt;sun.arch.data.model=64&lt;br /&gt;java.home=/usr/lib/jvm/java-6-sun-1.6.0.06/jre&lt;br /&gt;java.specification.vendor=Sun Microsystems Inc.&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;user.language=zh&lt;/span&gt;&lt;br /&gt;java.vm.info=mixed mode&lt;br /&gt;java.version=1.6.0_06&lt;br /&gt;java.ext.dirs=/usr/lib/jvm/java-6-sun-1.6.0.06/jre/...&lt;br /&gt;sun.boot.class.path=/usr/lib/jvm/java-6-sun-1.6.0.06/jre/...&lt;br /&gt;java.vendor=Sun Microsystems Inc.&lt;br /&gt;file.separator=/&lt;br /&gt;java.vendor.url.bug=http://java.sun.com/cgi-bin/bugreport...&lt;br /&gt;sun.cpu.endian=little&lt;br /&gt;sun.io.unicode.encoding=UnicodeLittle&lt;br /&gt;sun.desktop=gnome&lt;br /&gt;sun.cpu.isalist=&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;请注意，在此配置下，如果想读写日期格式：dd-MMM-YYYY (01-Jun-2008)，&lt;br /&gt;是会出错的，如果在不修改源码的情况下，需要修改系统属性：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;java -Duser.language=en ...&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-6319843910501080186?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/6319843910501080186/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=6319843910501080186' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/6319843910501080186'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/6319843910501080186'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2008/06/jvmjre.html' title='列出 JVM／JRE 当前的所有系统属性'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-3454389855239969239</id><published>2008-05-22T22:38:00.004+08:00</published><updated>2008-05-22T22:47:15.560+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='随笔'/><title type='text'>没有灾难和痛苦</title><content type='html'>&lt;span&gt;如果可以平步星云......&lt;br /&gt;那么可以，没有国界边疆，没有战争，没有不动产，&lt;span style="font-weight: bold; color: rgb(51, 204, 0);"&gt;没有灾难和痛苦&lt;/span&gt;，不再你的我的！&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;是啊，没有灾难和痛苦&lt;/span&gt;，对生命才是最重要的！&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-3454389855239969239?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/3454389855239969239/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=3454389855239969239' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/3454389855239969239'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/3454389855239969239'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2008/05/blog-post_22.html' title='没有灾难和痛苦'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-6079524021388060662</id><published>2008-05-17T13:56:00.006+08:00</published><updated>2008-12-11T01:08:07.477+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='救苦救难'/><title type='text'>因为爱, 奇迹正在赶过来!</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_bpUunzIgcNA/SDJRngAdp0I/AAAAAAAAAJQ/XYXyBPwcyIM/s1600-h/white_rose.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://4.bp.blogspot.com/_bpUunzIgcNA/SDJRngAdp0I/AAAAAAAAAJQ/XYXyBPwcyIM/s400/white_rose.jpg" alt="" id="BLOGGER_PHOTO_ID_5202310258614970178" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;因为爱&lt;br /&gt;------&lt;br /&gt;歌手：群星&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;因为船才到达彼岸&lt;br /&gt;因为冷候鸟才飞向南&lt;br /&gt;因为有瞬间阴霾阳光才更灿烂&lt;br /&gt;因为寒冬春天才回暖&lt;br /&gt;因为你眉头才放宽&lt;br /&gt;因为我跌倒了有人搀&lt;br /&gt;因为所有的付出总会得到偿还&lt;br /&gt;因为我们笑着过难关&lt;br /&gt;就因为爱希望绽放华彩&lt;br /&gt;就因为爱能拨云见日未来永值得期待&lt;br /&gt;就因为爱就因为爱&lt;br /&gt;所有的生命才收获了圆满&lt;br /&gt;就因为爱彼此无声依赖&lt;br /&gt;就因为爱至少还有一个信念不会更改&lt;br /&gt;就因为爱就因为爱&lt;br /&gt;奇迹正在赶过来&lt;br /&gt;因为天海才特别蓝&lt;br /&gt;因为灯黑夜从不暗淡&lt;br /&gt;因为同携手作伴不会感觉孤单&lt;br /&gt;因为心疼才要更勇敢&lt;br /&gt;因为你努力有何难&lt;br /&gt;因为我将会为你承担&lt;br /&gt;因为面对着风雨从不袖手旁观&lt;br /&gt;因为我们共撑一把伞&lt;br /&gt;就因为爱希望绽放华彩&lt;br /&gt;就因为爱能拨云见日未来永值得期待&lt;br /&gt;就因为爱就因为爱&lt;br /&gt;所有的生命才收获了圆满&lt;br /&gt;就因为爱彼此无声依赖&lt;br /&gt;就因为爱至少还有一个信念不会更改&lt;br /&gt;就因为爱就因为爱&lt;br /&gt;奇迹正在赶过来&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-6079524021388060662?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/6079524021388060662/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=6079524021388060662' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/6079524021388060662'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/6079524021388060662'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2008/05/blog-post_17.html' title='因为爱, 奇迹正在赶过来!'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_bpUunzIgcNA/SDJRngAdp0I/AAAAAAAAAJQ/XYXyBPwcyIM/s72-c/white_rose.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-1748054157776030186</id><published>2008-05-13T22:54:00.006+08:00</published><updated>2008-12-11T01:08:07.982+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='救苦救难'/><title type='text'>伸出援助之手给困难的灾区人民</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_bpUunzIgcNA/SCmtdgAdpwI/AAAAAAAAAIw/vagKry-c4NE/s1600-h/loving_shap.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_bpUunzIgcNA/SCmtdgAdpwI/AAAAAAAAAIw/vagKry-c4NE/s400/loving_shap.jpg" alt="" id="BLOGGER_PHOTO_ID_5199877967095637762" border="0" /&gt;&lt;/a&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_bpUunzIgcNA/SCmyaQAdpxI/AAAAAAAAAI4/ssmkwA29PFg/s1600-h/earthquake.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://2.bp.blogspot.com/_bpUunzIgcNA/SCmyaQAdpxI/AAAAAAAAAI4/ssmkwA29PFg/s400/earthquake.jpg" alt="" id="BLOGGER_PHOTO_ID_5199883408819201810" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;一方有难八方支援 四川省地震救灾捐款方式&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;中国红十字会总会救灾专用账号和热线&lt;br /&gt;&lt;/strong&gt;        网址：http://www.redcross.org.cn&lt;br /&gt;&lt;p&gt;　　开户单位：中国红十字会总会&lt;/p&gt; &lt;p&gt;　　人民币开户行：中国工商银行北京分行东四南支行&lt;/p&gt; &lt;p&gt;　　人民币账号：0200001009014413252&lt;/p&gt; &lt;p&gt;　　外币开户行：中信银行酒仙桥支行&lt;/p&gt; &lt;p&gt;　　外币账号：7112111482600000209&lt;/p&gt; &lt;p&gt;　　热线电话：(8610)65139999&lt;/p&gt; &lt;p&gt;　　捐款有如下几种途径：&lt;/p&gt; &lt;p&gt;　　&lt;strong&gt;银行汇款&lt;/strong&gt;：账号见上文&lt;/p&gt; &lt;p&gt;　　&lt;strong&gt;邮局汇款：&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;　　地址：北京市东城区北新桥三条8号&lt;/p&gt; &lt;p&gt;　　邮编：100007&lt;/p&gt; &lt;p&gt;　　（通过银行、邮局和网上捐款在捐款时请注明捐款人姓名、通信地址、捐款意向如：四川地震捐款等信息，以便邮寄捐赠收据和感谢信）&lt;/p&gt; &lt;p&gt;　　&lt;strong&gt;通过短信捐款&lt;/strong&gt;：中国移动、中国联通手机用户以及中国电信、中国网通小灵通用户均可编辑短信1或2，发送至1069999301，即向“红十字救援行动”捐款1元钱或2元钱。&lt;/p&gt; &lt;p&gt;　　&lt;/p&gt; &lt;p&gt;　　&lt;strong&gt;通过短信咨询&lt;/strong&gt;：中国移动、中国联通手机用户以及中国电信、中国网通小灵通用户均可编辑短信“中国红十字会”，发送至12114，即可了解中国红十字会有关情况。&lt;/p&gt; &lt;p&gt;　　中国红十字基金会同时也接受社会各界捐赠：&lt;/p&gt; &lt;p&gt;　　地址： 北京市东城区东单北大街干面胡同53号&lt;/p&gt; &lt;p&gt;　　邮编：100010&lt;/p&gt; &lt;p&gt;　　&lt;strong&gt;银行汇款：&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;　　户名： 中国红十字基金会&lt;/p&gt; &lt;p&gt;　　开户银行： 中国银行北京分行&lt;/p&gt; &lt;p&gt;　　账号： 800100921908091001&lt;/p&gt; &lt;p&gt;　　开户银行：中国工商银行北京东四南支行&lt;/p&gt; &lt;p&gt;　　账号：0200001019014483874&lt;/p&gt; &lt;p&gt;　　开户银行：中国建设银行北京朝内大街支行&lt;/p&gt; &lt;p&gt;　　账号：11001070300059000427&lt;/p&gt; &lt;p&gt;　　外币开户银行：中国银行&lt;/p&gt; &lt;p&gt;　　账号： 800100086608091014&lt;/p&gt; &lt;p&gt;　　捐款热线电话： 010-65124154 010-65129947 010-65599176&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-1748054157776030186?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/1748054157776030186/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=1748054157776030186' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/1748054157776030186'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/1748054157776030186'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2008/05/blog-post.html' title='伸出援助之手给困难的灾区人民'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_bpUunzIgcNA/SCmtdgAdpwI/AAAAAAAAAIw/vagKry-c4NE/s72-c/loving_shap.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-8227304416459635696</id><published>2008-04-30T00:51:00.001+08:00</published><updated>2008-04-30T00:54:38.447+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='音乐'/><title type='text'>最远的你是我最近的爱</title><content type='html'>演唱：车继铃&lt;br /&gt;&lt;br /&gt;夜已沉默心事向谁说&lt;br /&gt;不肯回头所有的爱都错过&lt;br /&gt;别笑我懦弱我始终不能猜透&lt;br /&gt;为何人生淡漠&lt;br /&gt;风雨之后无所谓拥有&lt;br /&gt;萍水相逢你却给我那么多&lt;br /&gt;你挡住寒冬温暖只保留给我&lt;br /&gt;风霜寂寞凋落在你怀中&lt;br /&gt;人生风景在游走&lt;br /&gt;每当孤独我回首&lt;br /&gt;你的爱总在不远地方等着我&lt;br /&gt;岁月如流在穿梭&lt;br /&gt;喜怒哀乐我深锁&lt;br /&gt;只因有你在天涯尽头等着我&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-8227304416459635696?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://city.y321.com/other/zydn.mp3' title='最远的你是我最近的爱'/><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/8227304416459635696/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=8227304416459635696' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/8227304416459635696'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/8227304416459635696'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2008/04/blog-post.html' title='最远的你是我最近的爱'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-6610847310023645335</id><published>2008-03-06T14:18:00.004+08:00</published><updated>2008-03-06T14:35:07.978+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate'/><title type='text'>Hibernate 3.2 移植: SQL函数返回类型改变</title><content type='html'>In alignment with the JPA specification the &lt;span style="font-family: courier new;"&gt;count, sum and avg&lt;/span&gt;&lt;span style="font-weight: bold;"&gt; &lt;/span&gt;function now defaults to return types as specified by the specification. This can result in &lt;span style="font-family: courier new;"&gt;ClassCastException &lt;/span&gt;at runtime if you used aggregation in HQL queries.&lt;br /&gt;&lt;br /&gt;Actually the spec says&lt;br /&gt;&lt;br /&gt;The Java type that is contained in the result of a query using an aggregate function is as follows[33]:&lt;br /&gt;• &lt;span style="font-family: courier new;"&gt;COUNT &lt;/span&gt;returns Long.&lt;br /&gt;• &lt;span style="font-family: courier new;"&gt;MAX, MIN&lt;/span&gt; return the type of the state-field to which they are applied.&lt;br /&gt;• &lt;span style="font-family: courier new;"&gt;AVG &lt;/span&gt;returns Double.&lt;br /&gt;• &lt;span style="font-family: courier new;"&gt;SUM &lt;/span&gt;returns Long when applied to state-fields of integral types (other than BigInteger); Double&lt;br /&gt;when applied to state-fields of floating point types; BigInteger when applied to state-fields&lt;br /&gt;of type BigInteger; and BigDecimal when applied to state-fields of type BigDecimal.&lt;br /&gt;&lt;br /&gt;http://www.hibernate.org/250.html#A44&lt;br /&gt;http://opensource.atlassian.com/projects/hibernate/browse/HHH-1538&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-6610847310023645335?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/6610847310023645335/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=6610847310023645335' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/6610847310023645335'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/6610847310023645335'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2008/03/hibernate-32-sql.html' title='Hibernate 3.2 移植: SQL函数返回类型改变'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-8945301964112702542</id><published>2008-02-03T13:29:00.001+08:00</published><updated>2008-12-11T01:08:08.326+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='救苦救难'/><title type='text'>伸出援助之手给困难的灾区人民</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_bpUunzIgcNA/R6VR-RTjiNI/AAAAAAAAAIo/DOLyo2Li8dc/s1600-h/loving+shap.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://4.bp.blogspot.com/_bpUunzIgcNA/R6VR-RTjiNI/AAAAAAAAAIo/DOLyo2Li8dc/s400/loving+shap.jpg" alt="" id="BLOGGER_PHOTO_ID_5162622678089304274" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;一方有难，八方支援。 抗击冰雪捐款方式。&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;&lt;span&gt;&lt;span style="color: rgb(76, 66, 12);"&gt;&lt;span style="font-weight: bold;font-size:180%;" &gt;&lt;span style="color: rgb(255, 0, 0);"&gt;中华慈善总会&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-weight: bold; color: rgb(255, 0, 0);"&gt;筹募部电话：&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style="color: rgb(76, 66, 12);"&gt;电 话：(010)66055848、&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style="color: rgb(76, 66, 12);"&gt;传 真：(010)66083264&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style="color: rgb(76, 66, 12);"&gt;联系人：苏辉 王玲&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span style="color: rgb(76, 66, 12);"&gt;&lt;span style="color: rgb(255, 0, 0);font-size:130%;" &gt;&lt;span style="font-weight: bold;"&gt;接受捐款账号及地址如下:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span style="color: rgb(76, 66, 12);"&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;&lt;strong&gt;银行汇款:&lt;/strong&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style="color: rgb(76, 66, 12);"&gt;&lt;b&gt;人民币捐款帐户&lt;/b&gt; &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style="color: rgb(76, 66, 12);"&gt;开户单位：中华慈善总会 &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style="color: rgb(76, 66, 12);"&gt;帐号：0200002809014450409&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style="color: rgb(76, 66, 12);"&gt;开 户 行：中国工商银行北京西四支行 &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style="color: rgb(76, 66, 12);"&gt;&lt;b&gt;外币捐款帐户&lt;/b&gt; &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style="color: rgb(76, 66, 12);"&gt;开户单位：中华慈善总会 &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style="color: rgb(76, 66, 12);"&gt;帐号：00100914908091014 &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style="color: rgb(76, 66, 12);"&gt;开户行：中国银行总行营业部[北京市复兴门内大街1号]&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span style="color: rgb(76, 66, 12);"&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;&lt;strong&gt;邮局汇款:&lt;/strong&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style="color: rgb(76, 66, 12);"&gt;&lt;b&gt;中华慈善总会地址：&lt;/b&gt; &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style="color: rgb(76, 66, 12);"&gt;北京市西城区二龙路甲33号新龙大厦 &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style="color: rgb(76, 66, 12);"&gt;邮编：100032&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span style="color: rgb(76, 66, 12);"&gt;&lt;span style="color: rgb(255, 51, 0);"&gt;&lt;strong&gt;网上募捐:&lt;/strong&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style="color: rgb(76, 66, 12);"&gt;&lt;span style="color: rgb(255, 51, 0);"&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/span&gt;&lt;a href="http://www.chinacharity.cn/wzzxmjsyservlet" target="_blank"&gt;中华慈善网网上募捐地址&lt;/a&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style="color: rgb(76, 66, 12);"&gt;&lt;strong&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;短信捐助:&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style="color: rgb(76, 66, 12);"&gt;&lt;strong&gt;&lt;/strong&gt;编辑MJ 到10660085(仅限联通用户 2 元/次)&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-8945301964112702542?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/8945301964112702542/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=8945301964112702542' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/8945301964112702542'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/8945301964112702542'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2008/02/blog-post.html' title='伸出援助之手给困难的灾区人民'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_bpUunzIgcNA/R6VR-RTjiNI/AAAAAAAAAIo/DOLyo2Li8dc/s72-c/loving+shap.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-8872875077678380767</id><published>2008-02-02T10:28:00.000+08:00</published><updated>2008-02-02T12:33:53.744+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='NetBeans'/><title type='text'>Closures in Java 7: YES vs. NO</title><content type='html'>Java 前辈(&lt;a style="font-weight: bold;" href="http://blogs.sun.com/jag"&gt;James Gosling&lt;/a&gt;, &lt;a rel="nofollow" href="http://www.javapuzzlers.com/"&gt;&lt;b&gt;Joshua Bloch&lt;/b&gt;&lt;/a&gt;, &lt;a href="http://gafter.blogspot.com/"&gt;&lt;span style="font-weight: bold;"&gt;Neal Gafter&lt;/span&gt;&lt;/a&gt;, ...)们现在正在热论“闭包”这一主题:&lt;br /&gt;&lt;br /&gt;&lt;a class="moz-txt-link-freetext" href="http://blogs.sun.com/jag/entry/closures"&gt;http://blogs.sun.com/jag/entry/closures&lt;/a&gt;&lt;br /&gt;&lt;a class="moz-txt-link-freetext" href="http://java.dzone.com/news/james-brings-closure-debate"&gt;http://java.dzone.com/news/james-brings-closure-debate&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;我个人的观点是 "NO", 因为这将使 JSL (Java 语言规范)逼近1000页, 并且，&lt;br /&gt;到现在我仍然在这一恐惧中：我用来学习 Java 5 Generic 的时间比曾经用来学习 Java 语言时间还长，可是让我现在设计出一个使用 “泛型”的框架，我心中没底。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-8872875077678380767?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/8872875077678380767/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=8872875077678380767' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/8872875077678380767'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/8872875077678380767'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2008/02/closures-in-java-7-yes-or-no.html' title='Closures in Java 7: YES vs. NO'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-1742609252894241853</id><published>2007-12-05T11:21:00.000+08:00</published><updated>2008-02-12T11:23:34.627+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='情衷'/><category scheme='http://www.blogger.com/atom/ns#' term='音乐'/><title type='text'>约定</title><content type='html'>&lt;span style="font-weight: bold;"&gt;       王菲&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;   还记得当天旅馆的门牌&lt;br /&gt;还留住笑著离开的神态&lt;br /&gt;当天整个城市那样轻快&lt;br /&gt;沿路一起走半哩长街&lt;br /&gt;还记得街灯照出一脸黄&lt;br /&gt;还燃亮那份微温的便档&lt;br /&gt;剪影的你轮廓太好看&lt;br /&gt;凝住眼泪才敢细看&lt;br /&gt;忘掉天地彷佛也想不起自己&lt;br /&gt;仍未忘相约看漫天黄叶远飞&lt;br /&gt;就算会与你分离凄绝的戏&lt;br /&gt;要决心忘记我便记不起&lt;br /&gt;明日天地只恐怕认不出自己&lt;br /&gt;仍未忘跟你&lt;span style="color: rgb(0, 0, 0);"&gt;约定&lt;/span&gt;假如没有死&lt;br /&gt;就算你壮阔胸膛不敌天气&lt;br /&gt;两鬓斑白都可认得你&lt;br /&gt;还记得当天吉他的和弦&lt;br /&gt;还明白每段旋律的伏线&lt;br /&gt;当天街角流过你声线&lt;br /&gt;沿路旅程如歌褪变&lt;br /&gt;就算你壮阔胸膛不敌天气&lt;br /&gt;两鬓斑白都可认得你&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-1742609252894241853?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/1742609252894241853/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=1742609252894241853' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/1742609252894241853'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/1742609252894241853'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2007/12/blog-post.html' title='约定'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-9129667678153033769</id><published>2007-09-18T10:40:00.001+08:00</published><updated>2008-12-11T01:08:08.996+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='NetBeans'/><title type='text'>NetBeans 6.0 beta1 终于出来了！</title><content type='html'>经过“漫长”的等待，beta1 终于出来了！其实我一直在用它的最近的 daily build, 因为 M10 实在是太不稳定了。&lt;br /&gt;&lt;div&gt;beta1 给人的第一印象是，更换了主题（桌面 icon, welcome 页，向导图案），使用的是接近于 Vista 类似的蓝绿色调，给人以清新的感觉！&lt;br /&gt;加紧试用吧！&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_bpUunzIgcNA/Ru86uiJaeQI/AAAAAAAAAE8/Ly1jrQe_DGw/s1600-h/nb6.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://2.bp.blogspot.com/_bpUunzIgcNA/Ru86uiJaeQI/AAAAAAAAAE8/Ly1jrQe_DGw/s400/nb6.png" alt="" id="BLOGGER_PHOTO_ID_5111368673203484930" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-9129667678153033769?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://dlc.sun.com.edgesuite.net/netbeans/download/6_0/beta1/' title='NetBeans 6.0 beta1 终于出来了！'/><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/9129667678153033769/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=9129667678153033769' title='2 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/9129667678153033769'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/9129667678153033769'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2007/09/netbeans-60-beta1.html' title='NetBeans 6.0 beta1 终于出来了！'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_bpUunzIgcNA/Ru86uiJaeQI/AAAAAAAAAE8/Ly1jrQe_DGw/s72-c/nb6.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-5649995965020888980</id><published>2007-08-25T11:15:00.000+08:00</published><updated>2007-08-25T11:24:55.274+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='NetBeans'/><title type='text'>SUN 将股票代码 SUNW 换为 JAVA</title><content type='html'>作为SUN公司战略计划的一部分，其将老的股票代码SUNW退修，而取而代之 JAVA,&lt;br /&gt;作为JAVA开发者，我们在高兴之余，你还想详细了解其 "java everywhere" 战略计划吗？&lt;br /&gt;请看SUN总裁的BLOG（对，为数不多的CEO会写博客，Jonathan Schwartz 就是其中的一位，&lt;br /&gt;而且他还留着马尾辫子。个性与成功并不矛盾！）&lt;br /&gt;&lt;br /&gt;http://blogs.sun.com/jonathan/entry/java_is_everywhere&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-5649995965020888980?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/5649995965020888980/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=5649995965020888980' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/5649995965020888980'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/5649995965020888980'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2007/08/sun-sunw-java.html' title='SUN 将股票代码 SUNW 换为 JAVA'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-5072407594529084050</id><published>2007-08-15T15:57:00.000+08:00</published><updated>2008-12-11T01:08:09.377+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GlassFish'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='NetBeans'/><title type='text'>Hibernate Jpetstore 之五 部署</title><content type='html'>文档内容&lt;br /&gt;&lt;ul&gt;&lt;li&gt;概览&lt;/li&gt;&lt;li&gt;获得工程代码&lt;/li&gt;&lt;li&gt;配置&lt;/li&gt;&lt;ul&gt;&lt;li&gt;数据库初始化&lt;/li&gt;&lt;ul&gt;&lt;li&gt;MySQL 5.x&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Oracle 9i, 10g, HsqlDB, Postgres 及其它&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;应用服务器初始化&lt;/li&gt;&lt;ul&gt;&lt;li&gt;本地数据源（非JNDI 数据源）&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;ul&gt;&lt;li&gt;Tomcat 5.x,&lt;/li&gt;&lt;li&gt;Sun Application Server8.x, 9.x / GlassFish 1.x, 2.x&lt;/li&gt;&lt;li&gt;Jetty 6.1.3&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;JNDI 数据源&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;ul&gt;&lt;li&gt;Sun Application Server8.x, 9.x / GlassFish 1.x, 2.x&lt;/li&gt;&lt;li&gt;JBoss 4.0.4 +&lt;/li&gt;&lt;li&gt;Jetty 6.1.3&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;li&gt;部署并运行&lt;/li&gt;&lt;li&gt;总结&lt;/li&gt;&lt;/ul&gt; PS: &lt;span style="font-style: italic; font-weight: bold;"&gt;为什么这个系列的最后一篇这么长时间才出来？原因是，我跟大家说过，工程的所有源代码最终将发布。所以我要找一个合适的地方上载。&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; font-weight: bold;"&gt; 这个过程还是比较烦的，况且老外们的工作效率普通不如我们，每次交流至少等上一周左右才有回应。试想申请、审批，确认，上载等过程，其实令我这个急性子试 图想把自己家里的电脑搬到主机托管中心，申请一个域名了事！&lt;br /&gt;&lt;br /&gt;&lt;/span&gt; 还好，它终于出来了 (&lt;a href="https://hjpetstore.dev.java.net/"&gt;hjpetstore&lt;/a&gt;)！但愿没让你失望。&lt;br /&gt;&lt;br /&gt;在阅读本篇文章之前，请先仔细阅读前面系列的相关内容。&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;概览&lt;/h2&gt;对于传统的J2EE 项目，当项目开发完后，其工作并未结束，紧接着的部署过程其实是很令开发者头痛的，特别是象重量级的应用服务 WebLogic, WebSphere 等。还好 NetBeans 现在抬简化了这一过程。&lt;br /&gt;我们这个例子是基于无存在数据库的方案，所以在我们演示结果前，我们将要导入一些数据。但首先我们得创建相应的数据库用户和数据库方案(Schema).&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;获得工程代码&lt;/h2&gt;1.从 &lt;a href="https://hjpetstore.dev.java.net/"&gt;hjpetstore&lt;/a&gt; 得到工程源代码，具体的步骤网站上有说明，在 NetBeans 中就很简单了：&lt;br /&gt;&lt;br /&gt;CVS | checkout:&lt;br /&gt;cvs root: :pserver:username@cvs.dev.java.net:/cvs     (这个 username 是你必须到 java.net 上注册的用户名称，目前 anonymous 好象不能工作了)&lt;br /&gt;password:&lt;br /&gt;&lt;br /&gt;下一页中， module: hjpetstore 下载完后，NetBeans 会问你是否打开该工程，选择是。&lt;br /&gt;&lt;br /&gt;2. 你可能需要调整一下lib 的位置，这是 NetBeans 的一个缺陷，保存的路径不是相对路径。&lt;br /&gt;右击工程 | properties&lt;br /&gt;点 Libraries，在Compile 页中将所有 .jar 文件 选中后 'remove'，&lt;br /&gt;再加入下载下来的WEB-INF/lib 目录下的所有 jar 文件&lt;br /&gt;&lt;br /&gt;3. 确保 Clean And Build project 成功&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;配置&lt;/h2&gt;&lt;h3&gt;数据库初始化&lt;/h3&gt;我这里只介绍 MySql  的 配置，其它的数据库配置列作 TBD. (待做，其实大部分脚本已经在工程中了，等待你的加入吧！因为我不是一个数据库专家，也没有太多时间去研究这个。）我成功配置过oracle 和 hsqldb.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(255, 0, 0);"&gt;注 意：因为下面的脚本会删除 'hjpetstore'数据库用户及其所有资源，请确保用户 'hjpetstore' (oracle) 或数据库 hjpetstore (mysql) 目前没被使用，如果使用了，请修改数据库脚本。所以最好的办法是使用你的个人数据库来作演示。&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;MySQL 5.x&lt;/h4&gt;&lt;br /&gt;1. 创建用户hjpetstore 和 数据库 hjpetstore&lt;br /&gt;&lt;br /&gt;# 在命令行下以 root 身份运行创建脚本&lt;br /&gt;# $hjpetstore 是用真实的工程路径代替&lt;br /&gt;# 其它值根据你的设置作相应的改变，比如你如果连非本机的数据库，那 'localhost'  就是那个机器在 ip 了&lt;br /&gt;&gt; mysql -h localhost -u root -p &lt; $hjpetstore\conf\jpetstore_mysql.sql Enter password: ******** 如果程序的输出显示了 hjpetstore, 则表明成功了： Database information_schema &lt;span style="font-weight: bold; color: rgb(102, 102, 204);"&gt;&lt;br /&gt;hjpetstore&lt;/span&gt;&lt;br /&gt;mysql&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;或者，如果有mysql query browser 的话，用它直接运行如下命令也可：&lt;br /&gt;-- frist drop database hjpetstore and user hjpetstore&lt;br /&gt;drop database if exists hjpetstore;&lt;br /&gt;&lt;br /&gt;create database hjpetstore;&lt;br /&gt;&lt;br /&gt;-- create user hjpetstore and give the password  hjpetstore&lt;br /&gt;grant all privileges on hjpetstore.* to hjpetstore identified by 'hjpetstore';&lt;br /&gt;&lt;br /&gt;show databases;&lt;br /&gt;&lt;br /&gt;2.  得用 hibernate.hbm2ddl.auto 自动生成数据库方案&lt;br /&gt;确保 web/WEB-INF/dataAccessContext-hibernate.xml 中 设置了&lt;prop key="hibernate.hbm2ddl.auto"&gt; update&lt;/prop&gt;&lt;br /&gt;&lt;br /&gt;这个属性的具体含义，我在前面的系列中已经讲过了，在产品初始化，你就可以安全地把它注释掉。&lt;br /&gt;&lt;br /&gt;3. 在 NetBeans 右击工程 Run project&lt;br /&gt;这一步将所有的数据库表创建出来, 只是没有数据。&lt;br /&gt;&lt;br /&gt;4. 加裁数据&lt;br /&gt;使用 NetBeans Sql Editor&lt;br /&gt;4.1 注册mysql 驱动&lt;br /&gt;Runtime | DataBases 右击 -&gt; new Driver&lt;br /&gt;Add ... -&gt; 导航到工程WEB-INF/lib/下的 mysql-connector-java-3.1.12-bin 点 OK&lt;br /&gt;&lt;br /&gt;4.2 创建连接&lt;br /&gt;右击刚注册的驱动 MySql (Connector/J driver) -&gt; Connect using ....&lt;br /&gt;Database URL: jdbc:mysql://localhost:3306/hjpetstore?useUnicode=true&amp;characterEncoding=UTF-8&lt;br /&gt;user name: hjpetstore&lt;br /&gt;password: hjpetstore&lt;br /&gt;&lt;br /&gt;点 Ok 后，在Databases 下应该会出现一个新的连接。&lt;br /&gt;&lt;br /&gt;4.3 执行 SQL 脚本&lt;br /&gt;1. 在 Files 窗口中导航到 db/mhsql/jpetstore-mysql-dataload.sql 并双击打开它&lt;br /&gt;2. 在编辑器的工具条中 Connection: 选择 刚创建的数据库连接：jdbc:mysql://localhost:3306/hjpetstore?useUnicode=true&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;ampamp;characterEncoding=UTF-8&lt;br /&gt;3. 点击编辑器工具条上，紧挨着下拉框的 run sql&lt;br /&gt;&lt;br /&gt;确保没有显示错误信息。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Oracle 9i, 10g, HsqlDB, Postgres 及其它&lt;/h4&gt;&lt;br /&gt;数据库脚本都已经在工程中了，你所要做的就是利用这些数据库提供的工具创建一个用户 'hjpetstore',&lt;br /&gt;之后的步骤与上述相同。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;应用服务器初始化&lt;/h3&gt;&lt;h4&gt;本地数据源（非JNDI 数据源）&lt;/h4&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Tomcat 5.x,&lt;/span&gt;&lt;br /&gt;事实上，工程默认是使用 Tomcat 服务器的，所以现在你根本不需要改动什么就可以运行工程了。&lt;br /&gt;有关数据源的配置是在 web/META-INF/ context.xml 文件中&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Sun Application Server8.x, 9.x / GlassFish 1.x, 2.x &lt;/span&gt;&lt;br /&gt;同样的配置，只不过要生成一个 sun-web.xml  文件，&lt;br /&gt;很好，NetBeans 会帮你自动产生，如下：&lt;br /&gt;右击工程 -&gt; Run | Server: 选择注册的Sun App Server (如果你还没注册 Sun App Server 的话，你需要先注册一下，具体步骤见相关文档)&lt;br /&gt;&lt;br /&gt;此时，文件已经产生，右击工程 -&gt; Run Project&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Jetty 6.1.3&lt;/span&gt;&lt;br /&gt;所有的配置文件已经在 WEB-INF 下了： jetty-web.xml, jetty-env.xml, 所以要做的只剩下将dist 上下生成的 hibernateJpetstore.war&lt;br /&gt;放到 Jetty 的部署目录，还好这个目录跟 Tomcat 的目录同名叫 webapps&lt;br /&gt;&lt;br /&gt;在 Jetty 目录下运行:&lt;br /&gt;java -jar start.jar&lt;br /&gt;然后在浏览器中请求: http://localhost:8080/hjpetstore/&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;JNDI 数据源&lt;/h4&gt;&lt;br /&gt;使用JNDI数据源当然是为了使用其 JTA(包容器管理的事务及其数据库连接池的实现），&lt;br /&gt;只需要按正确的名称 jdbc/hjpetstore 在管理界面配好数据库连接池和相应的数据源，运行起来还是挺方便的,&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Sun Application Server8.x, 9.x / GlassFish 1.x, 2.x&lt;/span&gt;&lt;br /&gt;1. 首先按照这篇文章介绍的步骤正确配置 mysql 数据源连接池&lt;br /&gt;(中文) http://pprun.blogspot.com/2007/05/glassfishsun-app-server.html&lt;br /&gt;(English) http://enpprun.blogspot.com/2007/05/problem-in-setting-mysql-xa-datasource.html&lt;br /&gt;注意，我文章中介绍的是使用root/root 作为用户名/密码，此时可以设置成hjpetstore/hjpetstore&lt;br /&gt;&lt;br /&gt;2. 配置数据源&lt;br /&gt;在应用服务器的 管理 界面 导航Resources | JDBC | JDBC Resources&lt;br /&gt;点击右边主页面中的 new 后进入配置页面，填入：&lt;br /&gt;JNDI Name: jdbc/hjpetstore&lt;br /&gt;Pool Name: 选择前面配置的数据源:连接池：mysql&lt;br /&gt;完成后点击 Ok&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;JBoss 4.0.4 +&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;1. 使用 JBoss 也许是冲着所谓的 #1 应用服务器而来的吧，但其配置有一些变化：&lt;br /&gt;第一它实现了自己的一套日志方式，所以需要把 web.xml 中的&lt;br /&gt;&lt;listener&gt;&lt;br /&gt;&lt;listener-class&gt;org.springframework.web.util.Log4jConfigListener&lt;/listener-class&gt;&lt;br /&gt;&lt;/listener&gt;&lt;br /&gt;注释掉。&lt;br /&gt;&lt;br /&gt;2. 它的数据源的配法也不相同，只需要将相应的数据库的配置文件(如：mysql-ds.xml ，内容见随后)放到&lt;br /&gt;jboss-4.0.4.GA\server\default\deploy 目录下，&lt;br /&gt;再在 jboss-4.0.4.GA\server\default\conf\login-config.xml 中加入:&lt;br /&gt;&lt;pre&gt;    &amp;lt;application-policy name = "MySqlDbRealm"&amp;gt;&lt;br /&gt;&amp;lt;authentication&amp;gt;&lt;br /&gt;&amp;lt;login-module code&lt;br /&gt;= "org.jboss.resource.security.ConfiguredIdentityLoginModule" flag =&lt;br /&gt;"required"&amp;gt;&lt;br /&gt;&amp;lt;module-option name ="principal"&amp;gt;hjpetstore&amp;lt;/module-option&amp;gt;&lt;br /&gt;&amp;lt;module-option name ="userName"&amp;gt;hjpetstore&amp;lt;/module-option&amp;gt;&lt;br /&gt;&amp;lt;module-option name ="password"&amp;gt;hjpetstore&amp;lt;/module-option&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;module-option name&lt;br /&gt;="managedConnectionFactoryName"&amp;gt;jboss.jca:service=LocalTxCM,name=hjpetstore-mysql&amp;lt;/module-option&amp;gt;&lt;br /&gt;&amp;lt;/login-module&amp;gt;&lt;br /&gt;&amp;lt;/authentication&amp;gt;&lt;br /&gt;&amp;lt;/application-policy&amp;gt;&lt;br /&gt;&lt;/pre&gt;   mysql-ds.xml 相应的内容如下：&lt;br /&gt;&lt;pre&gt;    &amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;datasources&amp;gt;&lt;br /&gt;&amp;lt;local-tx-datasource&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;jndi-name&amp;gt;hjpetstore-mysql&amp;lt;/jndi-name&amp;gt;&lt;br /&gt;&amp;lt;connection-url&amp;gt;jdbc:mysql://localhost:3306/hjpetstore&amp;lt;/connection-url&amp;gt;&lt;br /&gt;&amp;lt;driver-class&amp;gt;com.mysql.jdbc.Driver&amp;lt;/driver-class&amp;gt;&lt;br /&gt;&amp;lt;user-name&amp;gt;hjpetstore&amp;lt;/user-name&amp;gt;&lt;br /&gt;&amp;lt;password&amp;gt;hjpetstore&amp;lt;/password&amp;gt;&lt;br /&gt;&amp;lt;exception-sorter-class-name&amp;gt;org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter&amp;lt;/exception-sorter-class-name&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- should only be used on drivers after 3.22.1 with "ping" support&lt;br /&gt;&lt;br /&gt;&amp;lt;valid-connection-checker-class-name&amp;gt;org.jboss.resource.adapter.jdbc.vendor.MySQLValidConnectionChecker&amp;lt;/valid-connection-checker-class-name&amp;gt;&lt;br /&gt;--&amp;gt;&lt;br /&gt;&amp;lt;!-- sql to call when&lt;br /&gt;connection is created&lt;br /&gt;&lt;br /&gt;&amp;lt;new-connection-sql&amp;gt;some arbitrary sql&amp;lt;/new-connection-sql&amp;gt;&lt;br /&gt; --&amp;gt;&lt;br /&gt;&amp;lt;!-- sql to call on an&lt;br /&gt;existing pooled connection when it is obtained from pool -&lt;br /&gt;MySQLValidConnectionChecker is preferred for newer drivers&lt;br /&gt;&lt;br /&gt;&amp;lt;check-valid-connection-sql&amp;gt;some arbitrary&lt;br /&gt;sql&amp;lt;/check-valid-connection-sql&amp;gt;&lt;br /&gt;&lt;br /&gt; --&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- corresponding&lt;br /&gt;type-mapping in the standardjbosscmp-jdbc.xml (optional for ejb) --&amp;gt;&lt;br /&gt;&amp;lt;metadata&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;type-mapping&amp;gt;mySQL&amp;lt;/type-mapping&amp;gt;&lt;br /&gt;&amp;lt;/metadata&amp;gt;&lt;br /&gt;&amp;lt;/local-tx-datasource&amp;gt;&lt;br /&gt;&amp;lt;/datasources&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;3. 还有，就是JBoss 的 JNDI 的名称有些怪：&lt;br /&gt;&lt;pre&gt;    &amp;lt;bean id="dataSource"&lt;br /&gt;class="org.springframework.jndi.JndiObjectFactoryBean"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- JBoss&lt;br /&gt;--&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;property name="jndiName" value="java:/hjpetstore-mysql"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- other standard Java EE server&lt;br /&gt;&lt;br /&gt;&amp;lt;property name="jndiName"&lt;br /&gt;value="java:comp/env/jdbc/hjpetstore"&amp;gt;&lt;br /&gt;--&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;看到区别了吗？它只需要java:/hjpetstore-mysql&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Jetty 6.1.3&lt;/span&gt;&lt;br /&gt;目前，还未测试成功！&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;部署并运行&lt;/h2&gt;&lt;br /&gt;在 NetBeans 中，只需要在 工程属性中选定所要运行的 服务器后，点 Run Project  即可运行在本地数据源配置上。&lt;br /&gt;此外，还可以按照服务指定的自动部署目录，将生成的 dist/hibernateJpetstore.war 文件放到该目录，&lt;br /&gt;如果服务器已经运行，一切就 ok 了，如果没有，启动服务器即可。&lt;br /&gt;&lt;br /&gt;如果要运行在 JNDI 配置上，则需要改一下 web.xml :&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;!--&lt;br /&gt;- Location of the XML file that defines the root&lt;br /&gt;application context.&lt;br /&gt;- Applied by ContextLoaderServlet.&lt;br /&gt;--&amp;gt;&lt;br /&gt;&amp;lt;context-param&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;param-name&amp;gt;contextConfigLocation&amp;lt;/param-name&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- local datasource --&amp;gt;&lt;br /&gt;&amp;lt;param-value&amp;gt;&lt;br /&gt;/WEB-INF/dataAccessContext-hibernate.xml&lt;br /&gt;/WEB-INF/applicationContext.xml&lt;br /&gt;&amp;lt;/param-value&amp;gt;&lt;br /&gt;&amp;lt;!-- jndi datasource and JTA (for a transactional&lt;br /&gt;JNDI DataSource)&lt;br /&gt;&lt;br /&gt;&amp;lt;param-value&amp;gt;&lt;br /&gt;&lt;br /&gt;/WEB-INF/dataAccessContext-hibernate-jndi.xml&lt;br /&gt;/WEB-INF/applicationContext.xml&lt;br /&gt;&amp;lt;/param-value&amp;gt;&lt;br /&gt;--&amp;gt;&lt;br /&gt;&amp;lt;/context-param&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;这几行配置说的应该很明白了，上面的是默认情况下的本地数据源，如果使用JNDI数据源，是这样了:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;context-param&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;param-name&amp;gt;contextConfigLocation&amp;lt;/param-name&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- jndi datasource and JTA (for a&lt;br /&gt;transactional JNDI DataSource)      --&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;param-value&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/WEB-INF/dataAccessContext-hibernate-jndi.xml&lt;br /&gt;/WEB-INF/applicationContext.xml&lt;br /&gt;&lt;br /&gt;&amp;lt;/param-value&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/context-param&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;只要按照上述的步骤配置好了应用服务器的数据源，现在运行的效果应该跟本地数据源是一样的。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;总结&lt;/h2&gt;&lt;br /&gt;NetBeans 对于 Java EE 的开发是全面的，除了几个服务器还未集成进来之外，其它的功能已经走在了所有IDE的最前列，&lt;br /&gt;但这也不防碍开发者使用这些未集成的服务器，因为大部分服务器都支持热部署，当NetBeans 给你的工程生成了 WAR 文件后，&lt;br /&gt;剩下的就是“将它放入热部署目录”了。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;看运行在 Jetty6.1.3 上的效果 (注意脚注部分显示，当前运行在什么服务器上):&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_bpUunzIgcNA/RsQSbKLv0eI/AAAAAAAAAEc/VADoU4S28o8/s1600-h/hjpetstore_poweredby_jetty.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://2.bp.blogspot.com/_bpUunzIgcNA/RsQSbKLv0eI/AAAAAAAAAEc/VADoU4S28o8/s400/hjpetstore_poweredby_jetty.png" alt="" id="BLOGGER_PHOTO_ID_5099220935889637858" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-5072407594529084050?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/5072407594529084050/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=5072407594529084050' title='6 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/5072407594529084050'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/5072407594529084050'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2007/08/hibernate-jpetstore.html' title='Hibernate Jpetstore 之五 部署'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_bpUunzIgcNA/RsQSbKLv0eI/AAAAAAAAAEc/VADoU4S28o8/s72-c/hjpetstore_poweredby_jetty.png' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-717596545357350885</id><published>2007-08-14T09:24:00.000+08:00</published><updated>2007-08-14T09:42:10.521+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='未来'/><title type='text'>爱因斯坦精神</title><content type='html'>[转载]&lt;br /&gt;听过一个故事：以前有个小孩，很喜欢拉小提琴，却又拉得不怎么样。连他的父母也觉得这孩子没什么天分，因为琴声真的好难听。于是他求教于一位教授，教授 说：“你为什么要拉小提琴呢？你觉得你快乐吗？”小孩子说：“我想成为一个伟大的小提琴家！我觉得我拉小提琴很快乐。”“那你就不用太刻意去学了”教授 说，你只要觉得快乐就好。小孩于是明白了，他以后都只是把拉小提琴当作是一种生活享受。后来，他在物理领域获得了很大成功，成了改变世界的一个伟人。此人 就是爱因斯坦！！&lt;br /&gt;我觉得我们应该学习他：学会放弃，只要你从中获得快乐，那么你就不要计较是否要获得成功。学会坦然处之。&lt;br /&gt;&lt;br /&gt;今年是狭义相对论发表100周年，也是联合国确定的世界物理年，主要纪念伟大的物理学家和社会活动家爱因斯坦对人类所作出的多方面的巨大贡献。爱因斯坦是全身心献身科学和主张科学无国界的理想主义者，是强调科学技术应当以人为本的人道主义者，是具有强烈社会责任感、反对法西斯和主持正义的社会活动家。在人类发展史上，爱因斯坦占有光辉的位置。我们纪念爱因斯坦这位伟人，不仅要了解他在科学上所作出的重要贡献，更要学习他在任何困难条件下都一心为科学而献身的精神，学习他为社会公正和反对法西斯战争而无私无畏的奋斗精神。我们还应当通过爱因斯坦成长的道路，分析产生这样杰出人物的条件，努力为中国青年创造良好的学习和成长的环境，使优秀人才能够脱颖而出，使中国科学能够早日跻身世界先进行列。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;一、爱因斯坦对物理学的重要贡献&lt;/h3&gt;&lt;br /&gt;在20世纪初古典物理学出现危机的关键时刻，爱因斯坦是推动物理学革命思想的一面光辉旗帜。他独自发现了狭义相对论和广义相对论，从根本上改变了传统的绝对时空观念，将时空、物质和作用力通过对称性统一起来。从狭义相对论出发，他提出了质量和能量等价的公式，开辟了原子能的时代。从广义相对论和核能出发，他和一批科学家发展了宇宙构造和起源的模式，他提出的宇宙常数预示了产生排斥力的暗能量的存在。他和普兰克及玻尔一起是量子论的主要奠基人，他提出了集波动性和粒子性于一身的光量子学说，解释了光电效应，促进了量子波动力学的发现。他发展了原子论和统计力学，解释了从布朗运动、固体比热到受激辐射等一系列现象，和玻色合作，建立了玻色—爱因斯坦量子统计理论，预见了玻色凝聚态的存在。他质疑量子力学提出的量子纠缠态，开辟了量子信息学的新领域。他在晚年致力于统一场论，虽然没有取得他预期的结果，但他提出的从高维几何局域对称性出发进行统一相互作用力的思想至今仍指导着基本相互作用大统一理论的发展方向，在他逝世后的半个世纪中，已经在弱电和强相互作用的统一中得到体现。&lt;br /&gt;&lt;br /&gt;他的科学思想远远超越当时的时代，具有非凡的前瞻性和深刻性，以至他许多重要的理论发表以后，短期内得不到物理界的普遍认同。他的科学发现不是天才的灵机一动，而是通过自学掌握了当时最前沿的科学成就，经过多年艰苦的思索才完成的。他在高中最后一年，就已经学习了当时大学还未讲授的电动力学理论，并对和光一起运动会产生什么现象进行了思考，10年以后才发现了狭义相对论。他在1909年开始认识到加速度和重力的等价关系，经过6年的努力和多次的失败，才建立了正确的广义相对论引力方程。&lt;br /&gt;&lt;br /&gt;相对论和量子力学是20世纪最重要的科学发现，不仅为我们提供了从微观夸克到宏观宇宙的物质和运动的图像和规律，丰富了我们的物质观和宇宙观，而且为20 世纪技术的发展提供了科学的基础。虽然爱因斯坦从事的是基础研究，他并不知道这些研究有什么实用价值，但是，越是基本的规律，覆盖的现象越广泛，潜在应用的面越广，产生的价值也越大。在微电子、激光、原子能、GPS、传感器、加速器、信息保密等等广泛应用的技术中都可以看到爱因斯坦研究成果的影响。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;二、爱因斯坦的人生观和社会活动&lt;/h3&gt;&lt;br /&gt;爱因斯坦对他自己的人生观曾经说道：“要追究一个人自己或是一切生物生存的意义或目的，从客观的观点看来，我总觉得是愚蠢可笑的。可是每个人都有一定的理想，这种理想决定着他的努力和判断的方向。就在这个意义上，我从来不把安逸和享乐看作是生活目的本身——这种伦理基础，我叫它猪栏的理想。照亮我的道路，并且不断地给我新的勇气去愉快地正视生活的理想，是善、美和真。要是没有志同道合者之间的亲切感情，要不是全神贯注于客观世界——那个在艺术和科学工作领域里永远达不到的对象，那么在我看来，生活就会是空虚的。人们所努力追求的庸俗的目标——财产、虚荣、奢侈的生活——我总觉得都是可鄙的。”“当我还是一个相当早熟的少年的时候，我就已经深切地意识到，大多数人终生无休止地追逐的那些希望和努力是毫无价值的。而且，我不久就发现了这种追逐的残酷，这在当年较之今天是更加精心地用伪善和漂亮的字句掩饰着的。每个人只是因为有个胃，就注定要参与这种追逐。而且，由于参与这种追逐，他的胃是有可能得到满足的；但是，一个有思想、有感情的人却不能由此而得到满足。”“我每天上百次地提醒自己，我的精神生活和物质生活都依靠别人(包括活着的人和死去的人)的劳动。我必须尽力以同样的分量来报答我领受了的和至今还在领受的东西，我强烈地向往着简朴的生活，并常常为发现自己占有了同胞过多的劳动而难以忍受。”&lt;br /&gt;&lt;br /&gt;他不仅是这样说，也是这样做的。在他创造力最丰富的青年时代，他的生活非常艰苦，经历过歧视和失业，但他从不屈服去追求庸俗的目标，而是全神贯注于科学研究。即使到美国定居以后，他主动要求不要给他很高的薪水，继续过着俭朴的生活。&lt;br /&gt;&lt;br /&gt;在他就职柏林科学院不久，第一次世界大战爆发，他从头开始就公开反对这场战争。他说过：“我反对一切形式的战争，除非那个敌人以毁灭人类作为它的唯一目的”。为此，他遭到了当局的迫害和部分报纸的谴责。德国的失败使德国科学家处于孤立的困难境地。爱因斯坦虽有瑞士国籍，被邀请参加国际物理会议和到其它国家就职，但他认为，科学是全人类共同的事业，不应该因政治原因而孤立德国科学家。在德国科学家不被邀请的情况下，他也拒绝出席会议和离开柏林去他地就职。他说：“我曾对普朗克许下诺言，在这里的环境没恶化到普朗克本人承认我的离开是自然而然的和正确的之前，我不离开柏林。如果我不是迫不得已，而是哪怕是部分地出自物质利益便离开我的政治期望正在那里实现的国家，离开用爱和友谊来温暖我的人们，而在开始堕落的时期我的离开对他们来说可能会加倍地难受……那我就是忘恩负义了。”很可惜，他的民主和社会主义的政治期望并未在战后德国实现，法西斯上台后把他视为犹太人的领袖，加大了迫害的手段，迫使他移居美国。此后，他一直以他个人的威望反对法西斯和关心弱小民族的命运。他对中国人民的苦难深表同情，多次支持中国抗日和中国人民争取民主权利的斗争。&lt;br /&gt;&lt;br /&gt;爱因斯坦多次告诫科学家要履行自己的社会职责。他说：“任何技术的应用都必须以人为本，关怀人的命运。”“要关心如何安排人的劳动和分配财富，以保证科学的成果用于造福人类，而不是用于破坏的那些尚未解决的大问题。”他还说：“国家是为人而存在，而不是相反，科学也是一样。”&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;三、爱因斯坦的教育思想和成长历程&lt;/h3&gt;&lt;br /&gt;爱因斯坦不是一个通常意义下循规蹈矩的好学生，他厌恶那些不尊重学生主动性和独立人格的灌输式教育，他在中学和大学都不为老师所看重。他在自述中写到： “有时，人们把学校简单地看作是一种工具，靠它来把大量的知识传授给成长中的一代。但这种看法是不正确的。知识是死的；而学校却要为活人服务。它应当发展青年人中那些有益于公共福利的品质和才能。但这并不是意味着个性应当消灭，而个人只变成像一只蜜蜂或蚂蚁那样仅仅是社会的一种工具。因为一个由没有个人独创性和个人志愿的规格、统一的个人所组成的社会，将是一个没有发展可能的不幸的社会。相反地，学校的目标应当是培养有独立行动和独立思考的个人，不过他们要把为社会服务看作是自己人生的最高目的。”他还说：“自由行动和自我负责的教育，比起那种依赖训练、外界权威和追求名利的教育来，是多么的优越呀。真正的民主决不是虚幻的空想。”他从小就需要自由的时空和选择来安排自己的学习，他很少听课，利用同学的笔记对付强制的考试，他说：“尽管摆在我们面前的课程本身都是有意义的，可是我仍要花费很大的力气才能基本上学会这些东西。对于像我这样爱好沉思的人来说，大学教育并不总是有益的。无论多好的食物强迫吃下去，总有一天会把胃口和肚子搞坏的。纯真的好奇心的火花会渐渐地熄灭。幸运的是，对我来说，这种智力的低落在我学习年代的幸福结束之后只持续了一年。” “事实上，现代的教学方法还没有把神圣的求知欲完全扼杀掉，这差不多是一个奇迹；因为这株脆弱的幼苗，除了需要鼓励之外，首先需要自由——没有自由它将不可避免地会夭折”。&lt;br /&gt;&lt;br /&gt;给一位教授的求情信这样写到：“亲爱的教授：请原谅一个父亲为了他儿子的事情来打搅您。……我的儿子目前失业，这使他深感难过。他越来越觉得，他的事业已经失败，再也无可挽回。而最使他沮丧的是，他感到自己是我们的负担，因为我们的景况不好……”这位教授是否给过帮助，现在已无从了解，但可以肯定大学的教授们从未认为爱因斯坦是个做学问的人才。&lt;br /&gt;&lt;br /&gt;1902年，在同学格罗斯曼的父亲的帮助下，爱因斯坦获得了瑞士专利局职员的工作，才得以靠微薄的收入维持一家的生活，而在1905年发表的改变20世纪物理学面貌的5篇重要论文则是他业余时间的创作。爱因斯坦在专利局工作到1909年，才有大学聘请他为副教授。对这7年的生活，他回顾到：“在我最富于创造性活动的1902～1909年这几年中，我就不用为生活而操心了。即使完全不提这一点，明确规定技术专利权的工作，对我来说也是一种真正的幸福。它迫使你从事多方面的思考，它对物理的思索也有重大的激励作用。总之，对于我这样的人，一种实际工作的职业就是一种绝大的幸福。因为学院生活会把一个年轻人置于这样一种被动的地位：不得不去写大量科学论文——结果是趋于浅薄，这只有那些具有坚强意志的人才能顶得住。然而大多数实际工作却完全不是这样……作为一个平民，他的日常生活并不靠特殊的智慧。如果他对科学深感兴趣，他就可以在本职工作之外埋头研究他所爱好的问题。不必担心他的努力会毫无成果。”&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;四、留给我们的思考&lt;/h3&gt;&lt;br /&gt;爱因斯坦的一生多姿多彩，光辉伟大。他在艰苦条件下坚持献身科学的理想，他维护正义、反对法西斯和强调以人为本的社会责任感，他不唯上、不唯书、不迷信权威、不惧怕困难、不为世俗名利动心、不受传统制度和观点的束缚，独立自主，自由思考，刨根到底地追求科学真理。敢想敢干，敢于超越!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-717596545357350885?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/717596545357350885/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=717596545357350885' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/717596545357350885'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/717596545357350885'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2007/08/blog-post.html' title='爱因斯坦精神'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-3402019079601914673</id><published>2007-08-10T09:45:00.000+08:00</published><updated>2007-08-10T10:09:28.053+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='NetBeans'/><title type='text'>Java 7 语言级的改动</title><content type='html'>到目前为止，Java7 已经有如下议案：&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;    &lt;li&gt;Language-level XML support (语言级的XML支持)&lt;/li&gt;&lt;br /&gt;    &lt;li&gt;Closures (闭包，目前 Java 匿名类担任部分这一角色)&lt;/li&gt;&lt;br /&gt;    &lt;li&gt;Block constructs (块结构)&lt;/li&gt;&lt;br /&gt;    &lt;li&gt;Strings in switch statements (允许 String 作为 switch 语句的开关值)&lt;/li&gt;&lt;br /&gt;    &lt;li&gt;Language support for BigDecimal (语言级支持 BigDecimal, 目的是减小 double 不够用的压力)&lt;/li&gt;&lt;br /&gt;    &lt;li&gt;Java property support (语言级属性支持，目前我们熟悉了 getter/setter)&lt;/li&gt;&lt;br /&gt;    &lt;li&gt;Lightweight method references (轻量级方法引用，目前如果不通过反射是无法完成对方法引用对象的传递)&lt;/li&gt;&lt;br /&gt;    &lt;li&gt;Extensions to the annotation mechanisms (进一步扩充 annotation - 元数据机制)&lt;/li&gt;&lt;br /&gt;    &lt;li&gt;Java Module System (模块系统，解决头疼的 CLASSPATH 问题)&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;其实我个人关心的是: reified generics (http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5098163)&lt;br /&gt;如果这个未实现的话，设计generics (泛型)类（注意，我没说使用泛型）仍然会是一种痛苦。&lt;br /&gt;&lt;br /&gt;相信随着时间的推移，各种介绍会陆续出现，这些概念也慢慢会一目了然。&lt;br /&gt;&lt;br /&gt;详细信息见 javac 作者的 blog:&lt;br /&gt; Neal Gafter: http://gafter.blogspot.com/&lt;br /&gt; Peter Ahé: http://blogs.sun.com/ahe/&lt;br /&gt;因为 JDK 已经成为了 OpenJDK 了，所以以上两位作者事实上都已经离开了SUN,&lt;br /&gt;开发 javac 的责任留给了 java 社团，也许你就是其中一位了！&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-3402019079601914673?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/3402019079601914673/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=3402019079601914673' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/3402019079601914673'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/3402019079601914673'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2007/08/java-7.html' title='Java 7 语言级的改动'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-8469450098869892885</id><published>2007-07-08T11:52:00.000+08:00</published><updated>2007-07-08T12:40:01.257+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='NetBeans'/><title type='text'>Open NetBeans 6 module project with NetBeans 5.x</title><content type='html'>要打开 NetBeans 6 的源代码工程，最方便的当然是使用配套的最新的开发版，但由于开发版或多或少会不稳定（特别是最近的M10）。所以还是要使用稳定的 release 版本来打开或者开发。&lt;br /&gt;但是由于平台的兼容性问题，在尝试 NetBeans 5.5 来打开从 NetBeans CVS checkout 或下载下来的源代码模块工程时，同样也遇到了问题：在打开对话框中 Project Name 中会以红色显示：&lt;br /&gt;&lt;pre&gt;&lt;span style="font-family:courier new;"&gt;java.io.IOException:&lt;br /&gt;Misconfigured project in ... has no defined "code-name-base"&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;经过一番周折，我打到一个解决办法：&lt;br /&gt;&lt;br /&gt;1. 在 NetBeans 5.x 中注册安装的 NetBeans 6.0 平台 Tools | NetBeans Platform Manager -&gt; Add Platform... , 选择NB6　的安装目录&lt;br /&gt;1.1　在 Harness TAB 中要确保选择第二项 "Harness supplied with Platform", 默认好象是第一项"Harness supplied with IDE" (如果工程使用新的平台中的一些API的话，第一项显然是不对的。)　&lt;br /&gt;1.2　记住 "Platform Name" 的值，因为下面要用到，所以最好拷贝一下。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2. 修改要打开的NetBeans 模块工程的 $工程目录\nbproject\project.xml 文件&lt;br /&gt;&lt;pre&gt;&amp;lt;data xmlns="http://www.netbeans.org/ns/nb-module-project/&lt;br /&gt;这个值在 NetBeans 6 中为 &amp;lt;data xmlns="http://www.netbeans.org/ns/nb-module-project/&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;也就是将新版中使用的命名空间定义"3" 回退到 NetBeans 5.x 使用的 "2"&lt;br /&gt;&lt;br /&gt;3. 在要打开的NetBeans 模块工程的 $工程目录\nbproject\　的目录下，增加 platform.properties 文件, 其内容为:&lt;br /&gt;&lt;pre&gt;nbplatform.active=NetBeans_IDE_6.0_M10_(build_200706281431)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;即让它指向前面记下的　“Platform Name”　的值:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;4. 现在打开试试！　（你们也许还会遇到其它问题，因为我也记不清是否改了其它配置）&lt;br /&gt;&lt;br /&gt;5. 最后，我还遇到一问题，右击工程 | properties&lt;br /&gt;弹出一个对话框说"没找到定义的平台，回退到默认的平台", 我没办法，只有选择是，然后进入到工程属性中后：&lt;br /&gt;Libraries -&gt; NetBeans Platform  把它给改回来&lt;br /&gt;&lt;br /&gt;6. build 试试！&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;好运！&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-8469450098869892885?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/8469450098869892885/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=8469450098869892885' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/8469450098869892885'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/8469450098869892885'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2007/07/open-netbeans-6-module-project-with.html' title='Open NetBeans 6 module project with NetBeans 5.x'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-7312759961775966080</id><published>2007-07-06T23:40:00.000+08:00</published><updated>2007-07-06T23:54:02.020+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='NetBeans'/><title type='text'>小心 Java SE 6 U2</title><content type='html'>Java SE 6 U2 修复了不少关键的BUG，正因为此，我也迫不急待地更新了。&lt;br /&gt;但是，我发现文件选择对话框（JFilechooser）简直慢如蜗牛了。&lt;br /&gt;请参见这里的讨论：&lt;a href="http://www.javalobby.org/java/forums/t98389.html"&gt;javalobby !&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;由于个人习惯，在新版本到来后，就会把老版本删除掉。可这次，我简直太无奈了，&lt;br /&gt;java.sun.com 竟然也找不到 U1 的下载链接了，而笔记本又没带回来！&lt;br /&gt;我不得 Google 一番才在国内的下载网站找到了。&lt;br /&gt;&lt;br /&gt;我使用的操作系统 WindowsXp.&lt;br /&gt;&lt;br /&gt;小心，各位！&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-7312759961775966080?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/7312759961775966080/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=7312759961775966080' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/7312759961775966080'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/7312759961775966080'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2007/07/java-se-6-u2.html' title='小心 Java SE 6 U2'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-6081488355244854122</id><published>2007-07-02T15:42:00.000+08:00</published><updated>2007-07-02T16:24:46.560+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='NetBeans'/><title type='text'>Hibernate 处理大数据量的方案</title><content type='html'>&lt;h3&gt;问题：OutOfMemoryException &lt;/h3&gt;&lt;br /&gt;大家知道，Hibernate 有 一级 cache (Session 级) 和二级 cache (需另外配置，如 ehcache),&lt;br /&gt;以下代码，Hibernate 在处理到大约50000条记录时，就会抛出 &lt;tt class="literal"&gt;OutOfMemoryException&lt;/tt&gt;, 这是因为，Hibernate 把所有新建的 MiniMessage  对象都放在了 Session 级的缓存中了。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Session session = null;&lt;br /&gt;Transaction tx = null;&lt;br /&gt;try {     &lt;br /&gt;session = HibernateUtil.getSessionFactory().openSession();&lt;br /&gt;tx = session.beginTransaction();&lt;br /&gt;for(int i=0; i&amp;lt;300000; i++ ) {          &lt;br /&gt; System.out.println(i + ".................");         &lt;br /&gt; MiniMessage message = new MiniMessage("Hello World" + i);        &lt;br /&gt; session.save(message);&lt;br /&gt;&lt;br /&gt;      }&lt;br /&gt;   &lt;br /&gt;tx.commit();&lt;br /&gt;&lt;br /&gt;} catch (HibernateException he) {  &lt;br /&gt;tx.rollback();     &lt;br /&gt;throw he;&lt;br /&gt;} finally {       &lt;br /&gt;session.close();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;h3&gt;解决办法：&lt;/h3&gt;&lt;br /&gt;使用"批处理”(Batch process)&lt;br /&gt;&lt;pre&gt;Session session = null;&lt;br /&gt;&lt;br /&gt;try {&lt;br /&gt;session = HibernateUtil.getSessionFactory().getCurrentSession();        &lt;br /&gt;Transaction tx = session.beginTransaction();&lt;br /&gt;&lt;br /&gt;       for(int i=0; i&amp;lt;200000; i++ ) {&lt;br /&gt; log.debug(i + ".................");&lt;br /&gt;&lt;br /&gt; MiniMessage message = new MiniMessage("Hello World" + (i+1));&lt;br /&gt; session.save(message);&lt;br /&gt; if ( i % 100 == 0 ) {&lt;br /&gt;  //100, same as the JDBC batch size set in xml file:&lt;br /&gt;  // &amp;lt;property name="hibernate.jdbc.batch_size"&amp;gt;100&amp;lt;/property&amp;gt;&lt;br /&gt;  //flush a batch of inserts and release memory:&lt;br /&gt;  log.debug("fulsh at : " + i + ".................");&lt;br /&gt;&lt;br /&gt;  session.flush();&lt;br /&gt;  session.clear();&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;        &lt;br /&gt;session.getTransaction().commit();&lt;br /&gt;} catch (HibernateException he) {&lt;br /&gt;      &lt;br /&gt;session.getTransaction().rollback();&lt;br /&gt;      &lt;br /&gt;throw he;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;在这种情况下，需要在hibernate.cfg.xml 配置几个参数来达到更好的效果：&lt;br /&gt;&lt;h4&gt;1. 配置批处理的大小&lt;/h4&gt;&lt;br /&gt;&lt;pre&gt; &amp;lt;property name="hibernate.jdbc.batch_size"&amp;gt;100&amp;lt;/property&amp;gt; &lt;/pre&gt;&lt;br /&gt;&lt;h4&gt;2. 放弃二级缓存：&lt;/h4&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  &amp;lt;!-- Disable the second-level cache because the&lt;br /&gt;batch process is one-off process. --&amp;gt;&lt;br /&gt;&lt;br /&gt;   &amp;lt;property&lt;br /&gt;name="hibernate.cache.provider_class"&amp;gt;org.hibernate.cache.NoCacheProvider&amp;lt;/property&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   &amp;lt;property&lt;br /&gt;name="hibernate.cache.use_second_level_cache"&amp;gt;false&amp;lt;/property&amp;gt;&lt;br /&gt;&lt;br /&gt;   &amp;lt;property&lt;br /&gt;name="hibernate.cache.use_query_cache"&amp;gt;false&amp;lt;/property&amp;gt;&lt;br /&gt;&lt;br /&gt;   &amp;lt;property&lt;br /&gt;name="hibernate.cache.use_minimal_puts"&amp;gt;false&amp;lt;/property&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;这样，Hibernate 会在每 100 个插入后，与数据库同步一次，并将一级缓存中的实体对象清除。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-6081488355244854122?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/6081488355244854122/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=6081488355244854122' title='1 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/6081488355244854122'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/6081488355244854122'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2007/07/hibernate.html' title='Hibernate 处理大数据量的方案'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-6741342481831579618</id><published>2007-06-15T11:57:00.000+08:00</published><updated>2007-06-15T12:30:33.711+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='NetBeans'/><title type='text'>Blogsport 又被封了!</title><content type='html'>&lt;span name="zoom"&gt;最近收到一些邮件说没法访问我的博客，&lt;br /&gt;众所周知的原因，但我们大家还是可以绕个弯吧：&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;以下是摘自 GG 派的文章&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;可以同时采用两种方法双管齐下来规避封锁。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;第一个方法是修改host文件：&lt;/span&gt;&lt;br /&gt;首先把自己的或想访问的博客网址按规则添加进下面这个大家共同编辑的wiki页里：&lt;br /&gt;&lt;a href="http://groups.google.com/group/ggpi/web/hostwiki"&gt;http://groups.google.com/group/ggpi/web/hostwiki&lt;/a&gt;&lt;br /&gt;&lt;blockquote&gt;然后用记事本打开C:\WINDOWS\system32\drivers\etc\hosts文件，然后把上面那个页面的内容全部复制进去即可&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;第二个方法：&lt;/span&gt;&lt;br /&gt;首先打开Notepad（或者其他的编辑器），写入如下内容(是程序员都应该明白这个方法的意思)：&lt;br /&gt;&lt;br /&gt;&lt;code&gt;function FindProxyForURL(url,host){&lt;br /&gt;   if(dnsDomainIs(host, ".blogspot.com")){&lt;br /&gt;   return "PROXY 72.14.219.190:80";&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;另存为proxy.pac到C盘的根目录下或者其它地方，然后对FireFox或IE7进行设置：&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Firefox：&lt;/span&gt; 打开Firefox，依次点击&lt;span style="font-weight: bold;"&gt;工具&lt;/span&gt;-&gt;&lt;span style="font-weight: bold;"&gt;选项&lt;/span&gt;-&gt; &lt;span style="font-weight: bold;"&gt;高级&lt;/span&gt;-&gt;&lt;span style="font-weight: bold;"&gt;网络&lt;/span&gt;-&gt;&lt;span style="font-weight: bold;"&gt;设置&lt;/span&gt;...-&gt;选中自动代理配置url，在下面填写：&lt;br /&gt;&lt;code&gt;file:///C:/proxy.pac&lt;/code&gt;&lt;br /&gt;再点：重新载入 ，然后一路确定下去就可以了。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;IE7：&lt;/span&gt;打开IE7，依次点击工具-&gt;Internet选项-&gt;连接-&gt;局域网设置-&gt;选中使用自动配置脚本，在下面填写：&lt;br /&gt;&lt;code&gt;file:///C:/proxy.pac&lt;/code&gt;&lt;br /&gt;再点确定，就可以了。这个方法的巧妙之处在于保证了所有blogspot的子域名可以没有限制的访问（内含 GFW关键字的除外）。问题在于这种方法似乎对某些IE浏览器支持不是很好，经常有问题。&lt;br /&gt;&lt;br /&gt;Cheers!&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-6741342481831579618?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/6741342481831579618/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=6741342481831579618' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/6741342481831579618'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/6741342481831579618'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2007/06/blogsport.html' title='Blogsport 又被封了!'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-8348407469588799409</id><published>2007-06-07T10:28:00.000+08:00</published><updated>2008-12-11T01:08:10.610+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='SwingWorker'/><category scheme='http://www.blogger.com/atom/ns#' term='Swing'/><category scheme='http://www.blogger.com/atom/ns#' term='NetBeans'/><title type='text'>Java 安全拷贝协议 (JSCP: Java Secure Copy Protocol) NetBeans 插件</title><content type='html'>&lt;h3&gt;JSCP NetBeans 插件的作用&lt;/h3&gt;&lt;br /&gt;大家知道，SCP 广泛使用于SSH出现之前的 Unix 之类的平台上，它允许在 Client &lt;-&gt; Server 间进行双向的文件传输（ScpTo, ScpFrom)&lt;br /&gt;&lt;br /&gt;JSCP  NetBeans plugin 作为一个 TopComponet 插入到 NetBeans 的 Navigator 方位，通过 Tools | Java SCP 调用。&lt;br /&gt;&lt;br /&gt;SCP 可进行文件双向传输的&lt;br /&gt;&lt;ul&gt;&lt;li&gt;向支持 SCP 的 Unix/Linux 服务器上传文件（ScpTo）&lt;/li&gt;&lt;li&gt;从支持SCP的 Unix/Linux 服务器获得文件（ScpFrom)&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;这两种工作模式是分别作为 &lt;span style="font-family:monospace;"&gt;JTabbedPane &lt;/span&gt;的 两个 Tab 出现在 JScp 这个 &lt;span style="font-family:monospace;"&gt;TopComponent &lt;/span&gt;中&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;div style="text-align: left;"&gt;&lt;h3&gt;JSCP NetBeans 插件的使用方法&lt;/h3&gt;&lt;div style="text-align: left;"&gt;从NetBeans &lt;a href="http://plugins.netbeans.org/PluginPortal/faces/MainPage.jsp?pluginid=2786"&gt;PluginPortal&lt;/a&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://plugins.netbeans.org/PluginPortal/faces/MainPage.jsp?pluginid=2786"&gt; &lt;/a&gt; 网站上获得一个压缩包，然后解压到一个目录供下面的步骤使用。&lt;br /&gt;&lt;/div&gt; &lt;h3&gt;&lt;a name="5.1"&gt;&lt;/a&gt;安装 .NBM 文件&lt;/h3&gt;&lt;ol&gt;&lt;li&gt;Tools | Update Center&lt;/li&gt;&lt;li&gt;选择 Install Manually Downloaded Modules (.nbm Files) 后，点击 Next&lt;/li&gt;&lt;li&gt;点击 Add... , 在 Select Directory or .nbm Files 对话框中，导航到此插件的两个 .nbm 文件（com-jcraft-jsch.nbm 和 org.pprun-jscp.nbm），同时选中它们后点击 Ok&lt;/li&gt;&lt;li&gt;点击 Next  &lt;/li&gt;&lt;li&gt;点击 Next&lt;/li&gt;&lt;li&gt;点击 Next, 在View Certificates and Install Modules 界面点击 Include 列下面的多选框中打上勾。界面将出现版权及插件签名信息。（如果你希望使用计算机的所有用户都使用这个插件，可以将在 Global 列下打勾）&lt;/li&gt;&lt;li&gt; Finish, 不出意外，将显示插件更新界面。&lt;/li&gt;&lt;li&gt;等到NetBeans 的状态条中显示 Turing on modules... done. 后，点击 Tools 菜单，此时将在菜单最底端看到 Java SCP 菜单项，如下：&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;h3&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_bpUunzIgcNA/RmdvEI3zgXI/AAAAAAAAADY/hKD6I3Qvky0/s1600-h/menu.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_bpUunzIgcNA/RmdvEI3zgXI/AAAAAAAAADY/hKD6I3Qvky0/s400/menu.png" alt="" id="BLOGGER_PHOTO_ID_5073145622147858802" border="0" /&gt;&lt;/a&gt;&lt;/h3&gt;&lt;br /&gt;&lt;/div&gt;&lt;h3&gt;使用说明&lt;/h3&gt; &lt;h4&gt;&lt;a name="5.2.1"&gt;&lt;/a&gt;前提条件：&lt;/h4&gt; &lt;ul&gt;&lt;li&gt;保证网络可以访问到一台支持 SCP/ SSH1 的 Unix/Linux 服务器&lt;/li&gt;&lt;li&gt;保证具有以上服务器上的一个帐户并且对其中的一个目录具有“写”权限（如果你只使用 ScpFrom 的话，此项可选）&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h4&gt;&lt;a name="5.2.2"&gt;&lt;/a&gt;ScpTo (文件上传)&lt;/h4&gt;&lt;br /&gt;（如果还没打开 JScp Window 的话）通过  Tools | Java SCP 打开，它会出现在左下角并停靠在 Navigator 所在的窗口中，如下图所示：&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;LocalFile&lt;/span&gt;       上传的文件，通过右边的按钮来选择&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;User@Host&lt;/span&gt;    用户名和主机名(或IP地址) 的组合&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Password&lt;/span&gt;     上述用户的密码&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;RemoteDir&lt;/span&gt;    上传的文件在服务器上放置的目录&lt;/li&gt;&lt;/ol&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_bpUunzIgcNA/RmdutI3zgWI/AAAAAAAAADQ/z_ukNeEy1Kg/s1600-h/ScpFrom.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_bpUunzIgcNA/RmdutI3zgWI/AAAAAAAAADQ/z_ukNeEy1Kg/s400/ScpFrom.png" alt="" id="BLOGGER_PHOTO_ID_5073145227010867554" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;请注意在输入的过程中，会动态对输入域的值进行校验，如下，桔色的字显示没有指定服务器主机名(或IP地址）：&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_bpUunzIgcNA/Rmdvx43zgYI/AAAAAAAAADg/B7CwA5HwNZ8/s1600-h/warning.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://4.bp.blogspot.com/_bpUunzIgcNA/Rmdvx43zgYI/AAAAAAAAADg/B7CwA5HwNZ8/s400/warning.png" alt="" id="BLOGGER_PHOTO_ID_5073146408126873986" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;如果所有的输入都合法的话，按钮 Scp 将可用，点击它将进行网络传输，进度条指示这一过程:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_bpUunzIgcNA/RmdwWY3zgbI/AAAAAAAAAD4/JGROQtiQf_k/s1600-h/progress.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://2.bp.blogspot.com/_bpUunzIgcNA/RmdwWY3zgbI/AAAAAAAAAD4/JGROQtiQf_k/s400/progress.png" alt="" id="BLOGGER_PHOTO_ID_5073147035192099250" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;如果一切正常，最终进度条将停止指示。反之，如果后台操作出现错误的话，错误将显示：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_bpUunzIgcNA/RmdwBo3zgZI/AAAAAAAAADo/pE1KM2gEZp8/s1600-h/progressError.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_bpUunzIgcNA/RmdwBo3zgZI/AAAAAAAAADo/pE1KM2gEZp8/s400/progressError.png" alt="" id="BLOGGER_PHOTO_ID_5073146678709813650" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;&lt;a name="5.2.3"&gt;&lt;/a&gt;ScpFrom (文件下载)&lt;br /&gt;&lt;/h4&gt;&lt;br /&gt;（如果还没打开 JScp Window 的话）通过  Tools | Java SCP 打开，它会出现在左下角并停靠在 Navigator 所在的窗口中，如下图所示：&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;User@Host&lt;/span&gt;    用户名和主机名(或IP地址) 的组合&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Password&lt;/span&gt;     上述用户的密码&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;RemoteFile&lt;/span&gt;   要下载的服务器上的文件&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;LocalDir&lt;/span&gt;       下载的文件放置的目录，通过右边的按钮来选择&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_bpUunzIgcNA/Rmduko3zgVI/AAAAAAAAADI/9btBs3U3hfU/s1600-h/ScpTo.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_bpUunzIgcNA/Rmduko3zgVI/AAAAAAAAADI/9btBs3U3hfU/s400/ScpTo.png" alt="" id="BLOGGER_PHOTO_ID_5073145080981979474" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;如果所有的输入都合法的话，按钮 Scp 将可用，点击它将进行网络传输。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;a name="6"&gt;&lt;/a&gt;总结&lt;/h3&gt;&lt;br /&gt;自从 NetBeans 5.0 开始，编写基于 NetBeans 的插件或平台应用已经变得非常简单。对于新来者，最大的障碍无非是一些NetBeans专用的术语及早期遗留下来的几个不大好理解的概念。不过还好， NetBeans 自己在快速前进的同时并没有忘记为开发者提供便利。&lt;br /&gt;&lt;a href="http://wiki.netbeans.org/wiki/view/Main"&gt;NetBeans wiki&lt;/a&gt;  是各种信息的大轮盘&lt;br /&gt;&lt;a href="http://www.planetnetbeans.org/"&gt;planetnetbeans&lt;/a&gt; 则是全世界NetBeans开发者的乐园。大家为了 NetBeans 开怀畅谈。&lt;br /&gt;&lt;a href="http://blogs.sun.com/geertjan/" title="Geertjan's Weblog"&gt;Geertjan's Weblog&lt;/a&gt; 不得不看&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-8348407469588799409?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://plugins.netbeans.org/PluginPortal/faces/MainPage.jsp?pluginid=2786' title='Java 安全拷贝协议 (JSCP: Java Secure Copy Protocol) NetBeans 插件'/><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/8348407469588799409/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=8348407469588799409' title='2 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/8348407469588799409'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/8348407469588799409'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2007/06/java-jscp-java-secure-copy-protocol.html' title='Java 安全拷贝协议 (JSCP: Java Secure Copy Protocol) NetBeans 插件'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_bpUunzIgcNA/RmdvEI3zgXI/AAAAAAAAADY/hKD6I3Qvky0/s72-c/menu.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-7162613628218806886</id><published>2007-06-01T14:14:00.000+08:00</published><updated>2007-06-01T14:27:58.836+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GlassFish'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='NetBeans'/><title type='text'>试用GlassFish V2，赢取 52 吋液晶电视机</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://java.sun.com/javaee/community/campaigns/gftv-052007/images/sharpaquos.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px;" src="http://java.sun.com/javaee/community/campaigns/gftv-052007/images/sharpaquos.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;只要下载并试用  &lt;a href="https://glassfish.dev.java.net/"&gt;GlassFish&lt;/a&gt; 或 &lt;a href="http://java.sun.com/javaee/downloads/ea/"&gt;Sun Java System Application Server 9.1 Beta 2&lt;/a&gt; ( Java EE 5 SDK Update 3 Preview 2　或 Java Application Platform SDK Update 3 Preview 2) 并将使用效果反馈给SUN(通过BLOG或直接提交表单)，就有机会羸取上面的52英吋液晶电视机。　&lt;br /&gt;&lt;br /&gt;详细情况见&lt;a href="http://java.sun.com/javaee/community/campaigns/gftv-052007/welcome.jsp"&gt;这&lt;/a&gt;，规则见&lt;a href="http://java.sun.com/javaee/community/campaigns/gftv-052007/contestrules.jsp"&gt;这&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-7162613628218806886?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/7162613628218806886/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=7162613628218806886' title='1 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/7162613628218806886'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/7162613628218806886'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2007/06/glassfish-v2-52.html' title='试用GlassFish V2，赢取 52 吋液晶电视机'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-2500574308082685783</id><published>2007-05-28T17:39:00.000+08:00</published><updated>2007-05-28T17:56:04.031+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='未来'/><title type='text'>[引]袁隆平</title><content type='html'>&lt;a href="http://bbs.military.china.com/jsp/pub/staticFile/htmls/2007/5/1011/8858788_page0.html"&gt;袁隆平给浮躁的社会做出榜样&lt;/a&gt;&lt;br /&gt;&lt;a href="http://news.sohu.com/20070523/n250176285.shtml"&gt;袁隆平身价千亿超盖茨 清心寡欲最青睐便宜货&lt;/a&gt;&lt;br /&gt;&lt;a href="http://218.93.12.5/yjby/ShowArticle.asp?ArticleID=2750"&gt;袁隆平简介&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-2500574308082685783?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/2500574308082685783/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=2500574308082685783' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/2500574308082685783'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/2500574308082685783'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2007/05/blog-post.html' title='[引]袁隆平'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-2183016136008970736</id><published>2007-05-25T09:48:00.000+08:00</published><updated>2007-05-28T09:35:17.335+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='NetBeans'/><title type='text'>软件的脆弱：从二分法查找的BUG说开去</title><content type='html'>大概是在去年的七月份左右，我首先在 &lt;a href="http://www.javalobby.org/java/forums/t73548.html"&gt;javalobby&lt;/a&gt; 上看到这篇。当时也无比震惊，因为JDK (1.5及之前的版本) 中 Arrays.binarySearch(int[] a, int key) 及 Collections.binarySearch(int[] a, int key) (其调用indexedBinarySearch) 存在一个在业界隐藏了几十年的BUG，而这两个方法的作者恰恰是两位高人实现：&lt;br /&gt;&lt;br /&gt;* @author  Josh Bloch&lt;br /&gt;* @author  Neal Gafter&lt;br /&gt;&lt;br /&gt;我想在Java 领域呆的比较长的开发者应该会有所耳闻吧，Josh Bloch 被称之为 "Java 之母"（虽然他是一位男性），因为 java collection 框架，java.math, 泛型 及《Effective Java Programming Language Guide》都出自他之手；而 Neal Gafter 则是 我们每天都用的JAVA编译器 Javac 的实现者。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;我们先看有问题的代码:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public static int binarySearch(int[] a, int key) {&lt;br /&gt;int low = 0;&lt;br /&gt;int high = a.length-1;&lt;br /&gt;&lt;br /&gt;while (low &lt;= high) {              &lt;br /&gt;int mid = (low + high) &gt;&gt; 1;&lt;br /&gt;int midVal = a[mid];&lt;br /&gt;&lt;br /&gt;if (midVal &lt; low =" mid"&gt; key)&lt;br /&gt;high = mid - 1;&lt;br /&gt;else&lt;br /&gt;return mid; // key found&lt;br /&gt;}&lt;br /&gt;return -(low + 1);  // key not found.&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;有问题的代码是这一行：&lt;br /&gt;&lt;pre&gt;int mid = (low + high) &gt;&gt; 1;　&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;大家知道，其等价于：&lt;br /&gt;&lt;pre&gt;int mid =(low + high) / 2;&lt;/pre&gt;&lt;br /&gt;问题是在 low 和 high 都很大时，比如数组的元素达到 2^30 时，low + high 将超过整数的最大值 2^31 -1，此时将造成溢流，溢流后得到的 mid 为负值。&lt;br /&gt;&lt;br /&gt;正确的实现应该为：&lt;br /&gt;&lt;pre&gt;             int mid = low + ((high - low) / 2);&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;或者更加清楚地使用Java的无符号右移操作符:&lt;/span&gt;&lt;pre&gt;            int mid = (low + high) &gt;&gt;&gt; 1;&lt;/pre&gt;&lt;br /&gt;虽然这个问题目前得到解决，我们就能断定这十几行程序就准确无误吗？&lt;br /&gt;但连以上两位作者目前也还表示怀疑。&lt;br /&gt;从行内得知，第一个二分法算法是1946年出现的，而当时被认为“无误”的实现到1962年才出现（也就是说以上十几行代码是经过十几年才得到的）。因为当时的数据量不可能逼近 2 ^ 30的数量级，所以直到去年这个BUG被提交到 &lt;a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5045582"&gt;Java 的 Bug 库&lt;/a&gt;中。可想人类的思维是有缺陷的。&lt;br /&gt;&lt;br /&gt;目前，对于搜索引擎，基因工程领域，这一数量级应该是少见多怪了，所以如果你工作的领域需要处理大量的数据时，请使用 JDK 6.0&lt;br /&gt;&lt;br /&gt;顺便提一句，对于C的实现，可以采用如下实现：&lt;br /&gt;&lt;pre&gt;mid = ((unsigned) (low + high)) &gt;&gt; 1;&lt;br /&gt;&lt;/pre&gt;看到这样的情况，作为程序员，我们应该时刻警惕、保持低调！&lt;br /&gt;&lt;br /&gt;&lt;sup&gt;&lt;/sup&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-2183016136008970736?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/2183016136008970736/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=2183016136008970736' title='5 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/2183016136008970736'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/2183016136008970736'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2007/05/bug.html' title='软件的脆弱：从二分法查找的BUG说开去'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-1291823937412736639</id><published>2007-05-24T20:38:00.000+08:00</published><updated>2007-05-24T20:48:23.968+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='NetBeans'/><title type='text'>NetBeans 5.5.1 发布了</title><content type='html'>在我们大谈特谈 NetBeans 6.0 时，一个中间版本 5.5.1 出来了。&lt;br /&gt;也许是因为6.0 引入了太多的新功能，致使开发周期比以往稍显长些。所以这个中间版本主要是为了跟进最新的产品线：&lt;br /&gt;&lt;ul&gt;&lt;li&gt;支持Java EE 5 Application Server 9.1 (GlassFish v2)&lt;/li&gt;&lt;li&gt;支持Windows Vista&lt;/li&gt;&lt;li&gt;C/C++ Pack 有很大的提升（这可是我亲自感受到的耶)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;还有我们可能不大关心的，但却是目前最完善的，支持J2ME Wireless Toolkit, version 2.5.1　平台&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;感兴趣的话，到这里&lt;a href="http://www.netbeans.info/downloads/index.php"&gt;下载&lt;/a&gt;！&lt;br /&gt;&lt;br /&gt;不过，过不了多久，它将被 NetBeans 6.0 所取代的，也许就在秋天！&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-1291823937412736639?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/1291823937412736639/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=1291823937412736639' title='2 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/1291823937412736639'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/1291823937412736639'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2007/05/netbeans-551.html' title='NetBeans 5.5.1 发布了'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-6690572939674191050</id><published>2007-05-23T18:12:00.000+08:00</published><updated>2008-12-11T01:08:11.387+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='NetBeans'/><title type='text'>NetBeans6 功能介绍: 布置 declaration View 和 Javadoc View</title><content type='html'>此篇文章介绍一个在 NetBeans 6 中同时查看鼠标指针处的源代码和&lt;br /&gt;Javadoc (不再Go to Source .../ Show JavaDoc)&lt;br /&gt;&lt;br /&gt;1. 首先打开它们：Window | Other | Declaration View  和 Window | Other | Javadoc View, 它们都被搁浅在 Output 窗口的位置，但此时只能看到一个窗口的内容，因为无论切换到其中的任何一个，它们都占据整个下端窗口。如下：&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_bpUunzIgcNA/RlQX3AKV8-I/AAAAAAAAACQ/d7N40OUDYh0/s1600-h/decl_doc_1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://4.bp.blogspot.com/_bpUunzIgcNA/RlQX3AKV8-I/AAAAAAAAACQ/d7N40OUDYh0/s400/decl_doc_1.png" alt="" id="BLOGGER_PHOTO_ID_5067701714402276322" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;2. 我们要将它们分开，点击其中任一窗口的上方（类似标题栏区域），按住不放，将其拖向左侧（或右侧也可），当出现一个红色的方框后释放，如下：&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_bpUunzIgcNA/RlQYGwKV8_I/AAAAAAAAACY/KBwpchWvfPM/s1600-h/decl_doc_2.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_bpUunzIgcNA/RlQYGwKV8_I/AAAAAAAAACY/KBwpchWvfPM/s400/decl_doc_2.png" alt="" id="BLOGGER_PHOTO_ID_5067701984985215986" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;释放后的效果如下：&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_bpUunzIgcNA/RlQYPQKV9AI/AAAAAAAAACg/ywrhb2_9JSo/s1600-h/decl_doc_3.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_bpUunzIgcNA/RlQYPQKV9AI/AAAAAAAAACg/ywrhb2_9JSo/s400/decl_doc_3.png" alt="" id="BLOGGER_PHOTO_ID_5067702131014104066" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;这些位置会被记录下来，只要你在设置之后正常退出了。在下次启动 NetBeans 后，你可以看到同样的布局。&lt;br /&gt;&lt;br /&gt;这个截图中显示的是　Integer.toHexString　方法的 Javadoc 和 实现源码。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;(期待下一篇)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-6690572939674191050?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/6690572939674191050/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=6690572939674191050' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/6690572939674191050'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/6690572939674191050'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2007/05/netbeans6-declaration-view-javadoc-view.html' title='NetBeans6 功能介绍: 布置 declaration View 和 Javadoc View'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_bpUunzIgcNA/RlQX3AKV8-I/AAAAAAAAACQ/d7N40OUDYh0/s72-c/decl_doc_1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-7840572668132526000</id><published>2007-05-23T16:32:00.000+08:00</published><updated>2008-12-11T01:08:11.682+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='SwingWorker'/><category scheme='http://www.blogger.com/atom/ns#' term='Swing'/><title type='text'>SwingWorker for you</title><content type='html'>想必大家已经知道 SwingWorker 已经加入到了 javax.swing 包中了。它的前身经过好几个阶段改进的，如果你阅读网上的例子就会发现你阅读的例子跟你下载的包不兼容。&lt;br /&gt;SwingWorker 在被正式加入到JDK6中之前叫做：org.jdesktop.swingworker.SwingWorker.java, 除了这个类之外，还包括 org.jdesktop.swingworker.AccumulativeRunnable.java 和 org.jdesktop.swingworker.SwingPropertyChangeSupport.java. 我并不打算深入介绍这几个类的源码，而是利用实际的例子来描述 SwingWorker 给 GUI 程序带来的便利。&lt;br /&gt;&lt;br /&gt;如果写过GUI程序的开发者肯定对界面的响应度及界面冻结会有所了解。首先我得说明的是，这个问题并不是SWING特有的，所有的GUI框架如果没有处理 好都会存在这种问题，举例来说，&lt;br /&gt;1. 在网络不好的环境下，在 windows 的文件浏览器中请求一个FTP地址或任何服务器的地址时，我们可以看到“灰块”（所谓灰块，是由于界面元素刷新队列被某个长时间的任务给阻塞，造成本该立 即刷新的界面得不到处理，显示出来的效果就是一块被扯得扭曲了的区域。）&lt;br /&gt;2. 用过 PLSQL Developer 的开发者肯定也体会过屏幕冻结的感受吧。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;费话少说，进入我们的 SwingWorker 之旅。&lt;br /&gt;&lt;br /&gt;SwingWorker有几个重要的概念：&lt;br /&gt;&lt;ol&gt;&lt;li&gt;初始线程(Initial threads)    一般来讲是应用的主线程 (运行main 方法的那个线程）　&lt;/li&gt;&lt;li&gt;  工作者线程(Worker Thread)   在主线程中生成的，用于执行那些长时间操作的线程&lt;/li&gt;&lt;li&gt;  事件调度线程(Event Dispath Thread)  所有界面相关的行为都应该在这个线程进行，并且一定要保持快速的响应。&lt;/li&gt;&lt;/ol&gt;如下图是利用 NetBeans Profile 监控到线程：&lt;br /&gt;&lt;ul&gt;&lt;li&gt;main - 初始线程&lt;/li&gt;&lt;li&gt;Our Swingworker #1 - 工作者线程&lt;/li&gt;&lt;li&gt;AWT-Envent-Queue-0 事件调度线程&lt;/li&gt;&lt;li&gt;其它的线程不在我们感兴趣之列&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_bpUunzIgcNA/RlP9PAKV85I/AAAAAAAAABo/THp67_7MOBw/s1600-h/swingWorker_thread.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_bpUunzIgcNA/RlP9PAKV85I/AAAAAAAAABo/THp67_7MOBw/s400/swingWorker_thread.png" alt="" id="BLOGGER_PHOTO_ID_5067672439905186706" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;我们要记住的是:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;所有长时间的操作都不应该放在事件调度线程(EDT-Event Dispatch Thread，专门用来处理与界面响应相关的操作)中，否则界面在这段时间内将变得无法响应。&lt;/li&gt;&lt;li&gt;所有对SWING组件的更新（在其已经被显示出去后）都应当通过EDT来访问，否则有可能造成线程死锁或界面根本没有反映作出的更改。&lt;/li&gt;&lt;/ul&gt;不要被前面这几段弄晕了，只要弄清楚了 Swing 的线程体系，其实大部分工作JDK 已经为你做好了。我们所要做的就是按照范例实现我们的代码。这样就肯定安全可靠。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;我们的例子是一个登录界面，这个界面要求输入用户名与密码，然后点击登录，正常情况下将与中心数据库进行通信。但考虑到文章的长度，我们将使用 Thread.sleep 来演示和长时间的网络操作。&lt;br /&gt;&lt;br /&gt;最终的界面将如下所示，我们这里也不介绍怎样制作界面(是的，我的确是使用 NetBeans 的 Gui Builder 来制作的，但使用了一个自定义的 JImagePanel)&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_bpUunzIgcNA/RlP-AgKV86I/AAAAAAAAABw/KYmX1Bfe2hA/s1600-h/login.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_bpUunzIgcNA/RlP-AgKV86I/AAAAAAAAABw/KYmX1Bfe2hA/s400/login.png" alt="" id="BLOGGER_PHOTO_ID_5067673290308711330" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;如果阅读过别人的代码或自己认真写过SWING方面的代码，在没有使用 SwingWorker 的 GUI 工程中，一定会有如下代码：&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    java.awt.EventQueue.invokeLater(new Runnable() {&lt;br /&gt;        public void run() {&lt;br /&gt;            // 长时间的操作&lt;br /&gt;        }&lt;br /&gt;    });&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;这样做的目的就是为了使长时间的操作在另外的线程中运行。&lt;br /&gt;&lt;br /&gt;为了使用面象对象的方式来处理这种行为，我们现在使用 SwingWorker。下面是我们的例子的代码:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import org.jdesktop.swingworker.SwingWorker;&lt;br /&gt;import org.pprun.interviewofprologic.db.domain.UserBusinessDelegate;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Worker thread for login operation.&lt;br /&gt;* @author pprun&lt;br /&gt;*/&lt;br /&gt;public class LoginSwingWorker extends SwingWorker&lt;boolean, object=""&gt; {&lt;br /&gt;private String username;&lt;br /&gt;private char[] password;&lt;br /&gt;&lt;br /&gt;private Exception exception;&lt;br /&gt;&lt;br /&gt;/** Creates a new instance of LoginSwingWorker */&lt;br /&gt;public LoginSwingWorker(String aUserName, char[] aPassword) {&lt;br /&gt;this.username = aUserName;&lt;br /&gt;this.password = aPassword;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* 所有的后台操作都在这里，如果要动态将处理的数据发出去的话（比如数据库查询的应用），&lt;br /&gt;* 可以在这里调用 publish 方法.&lt;br /&gt;*/&lt;br /&gt;@Override&lt;br /&gt;protected Boolean doInBackground() throws Exception {&lt;br /&gt;try {&lt;br /&gt;    // 我们注释掉了这段代码，取而代之以假想的 Thread.sleep&lt;br /&gt;    // UserBusinessDelegate cbd = UserBusinessDelegate.getInstance();&lt;br /&gt;    // final boolean result = cbd.login(username, password);&lt;br /&gt;&lt;br /&gt;    //return result;&lt;br /&gt;&lt;br /&gt;    try {&lt;br /&gt;        Thread.sleep(5000);&lt;br /&gt;&lt;br /&gt;    } catch (InterruptedException interruptedException) {&lt;br /&gt;        interruptedException.printStackTrace();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;        return true; // 如果想看看登录失败时的效果，return false;&lt;br /&gt;&lt;br /&gt;} catch( Exception anyException ) {&lt;br /&gt;    exception = anyException;&lt;br /&gt;    throw exception;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Returns the exception thrown by the method doInBackground, if any, or&lt;br /&gt;* null if no exception was generated.&lt;br /&gt;* @return The exception generated by the call to doInBackground, or null&lt;br /&gt;*  if no exception was generated.&lt;br /&gt;*/&lt;br /&gt;public Exception getDoInBackgroundException() {&lt;br /&gt;return exception;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/boolean,&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;在触发端，点击 Ok 按钮时：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;private void okJButtonActionPerformed(java.awt.event.ActionEvent evt) {                                 &lt;br /&gt;    // ...&lt;br /&gt;&lt;br /&gt;    loginSwingworker = new LoginSwingWorker(username, password);&lt;br /&gt;&lt;br /&gt;    loginSwingworker.addPropertyChangeListener(this);&lt;br /&gt;    loginSwingworker.execute();&lt;br /&gt;&lt;br /&gt;      // ...&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;属性改变监听器的实现方法，监听在 SwingWorker 中的改变：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public void propertyChange(PropertyChangeEvent pce) {&lt;br /&gt;if (pce.getSource() == loginSwingworker) {&lt;br /&gt;    // property change event coming from the loginSwingworker&lt;br /&gt;    if (pce.getPropertyName().equals("state") &amp;&amp;amp;&lt;br /&gt;            loginSwingworker.getState() == SwingWorker.StateValue.DONE ) {&lt;br /&gt;        // loginSwingWorker 完成，但有可能抛出异常&lt;br /&gt;        loginSwingworker.removePropertyChangeListener( this );&lt;br /&gt;        if (loginSwingworker.getDoInBackgroundException() != null ) {&lt;br /&gt;                 // 抛出异常&lt;br /&gt;            if (true) {&lt;br /&gt;                infoJLabel.setText("Error in login!");&lt;br /&gt;            } else {&lt;br /&gt;       &lt;br /&gt;                infoJLabel.setText("Error in login!");&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;    } else if (loginSwingworker.isCancelled()) {&lt;br /&gt;        // loginSwingowrker 被取消时的代码&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;关于在 Swing 中使用并发的详细资料，参见  &lt;a href="http://java.sun.com/docs/books/tutorial/uiswing/concurrency/index.html"&gt;Concurrency in Swing&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-7840572668132526000?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/7840572668132526000/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=7840572668132526000' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/7840572668132526000'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/7840572668132526000'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2007/05/swingworker-for-you.html' title='SwingWorker for you'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_bpUunzIgcNA/RlP9PAKV85I/AAAAAAAAABo/THp67_7MOBw/s72-c/swingWorker_thread.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-5203850018959686363</id><published>2007-05-22T18:34:00.000+08:00</published><updated>2008-12-11T01:08:12.375+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='NetBeans'/><title type='text'>体验更多 NetBeans 的新功能</title><content type='html'>不喜欢 NetBeans 的开发者往往指出 NetBeans 没有这个功能，没有那个功能。无可厚非，当时他们是对的，但随着时间的推移，现在也许错了：&lt;br /&gt;&lt;br /&gt;1. Last Edit （是近更改按钮，带星号的那个），将你带到最近更改的地方&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_bpUunzIgcNA/RlQLuwKV87I/AAAAAAAAAB4/5kqPXrZ45xc/s1600-h/last+edit.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_bpUunzIgcNA/RlQLuwKV87I/AAAAAAAAAB4/5kqPXrZ45xc/s400/last+edit.png" alt="" id="BLOGGER_PHOTO_ID_5067688378528822194" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2.  Diff SideBar (差异侧条), 根据所在行代码是增加、更改还是删除，在侧条中显示不同的小条，右击可以使用进一步的功能&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_bpUunzIgcNA/RlQMfQKV88I/AAAAAAAAACA/5L0j_Nr2uUo/s1600-h/diff+sidebar.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_bpUunzIgcNA/RlQMfQKV88I/AAAAAAAAACA/5L0j_Nr2uUo/s400/diff+sidebar.png" alt="" id="BLOGGER_PHOTO_ID_5067689211752477634" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;3. JUnit4 支持（也就是现在可以使用基于 JDK 5 Annotation 的单元测试了）&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_bpUunzIgcNA/RlQMuwKV89I/AAAAAAAAACI/DlpU2V4jrcA/s1600-h/JUnit4.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_bpUunzIgcNA/RlQMuwKV89I/AAAAAAAAACI/DlpU2V4jrcA/s400/JUnit4.png" alt="" id="BLOGGER_PHOTO_ID_5067689478040450002" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;4. Find/Replace in Project (全工程范围内搜索)，是的，这个功能我真的也非常需要:&lt;br /&gt;看到左下方的"Replace" 按钮了吗？&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(255, 0, 0);"&gt;值得注意的是，这个功能在 M9 中被屏蔽了，但在每日构建的版本中可以使用。&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;img src="http://1.bp.blogspot.com/_GUaFO77rw-w/RcDNGbkZUrI/AAAAAAAAAAg/t_qTqZMw834/s1600/nb-find-replace.png" alt="[nb-find-replace.png]" border="0" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;另外，大部分初次使用NetBeans 的开发者，不知道更改“自动完成弹出窗口”的键绑定，因为最常用的"Ctrl + 空格" 是不可工作的，因为在中文操作系统中被绑定到输入法的切换了。所以我一般把它改成 'Ctrl + Enter' , 如下进行：&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Tools | Options -&gt; Keymap -&gt; Other&lt;/li&gt;&lt;li&gt;找到 Show Code Completion Popup, 选中它，点击Add...&lt;/li&gt;&lt;li&gt;按下任何所你希望的键序列，但是如果直接按 Ctrl + Enter 的话，系统提示这个组合键已经被绑定到 Split Line，所以如果我们要使用这个组合键的话，要先把它与 Split Line 解除绑定&lt;/li&gt;&lt;li&gt;在 Show Code completion Popup 下方第六个即是　Split Line, 选中它，点击移除。你可以为这个功能提供另外的组合键，如果经常使用这一功能的话。&lt;/li&gt;&lt;li&gt;然后，按照上述把"Ctrl + Enter " 加到 Show Code Completion Popup 中去。&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;(期待下一篇)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-5203850018959686363?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/5203850018959686363/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=5203850018959686363' title='2 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/5203850018959686363'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/5203850018959686363'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2007/05/netbeans.html' title='体验更多 NetBeans 的新功能'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_bpUunzIgcNA/RlQLuwKV87I/AAAAAAAAAB4/5kqPXrZ45xc/s72-c/last+edit.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-5359638578221088052</id><published>2007-05-18T09:12:00.000+08:00</published><updated>2008-12-11T01:08:12.925+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='NetBeans'/><title type='text'>GlassFish/Sun App Server 配置 MySqlXADataSource 的问题</title><content type='html'>如果你打算使用 GlassFish/Sun App Server，并且打算使用 MySql 的 XA 数据源的话。在目前的配置过程中，会遇到如下问题：&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;重现步骤：&lt;/span&gt;&lt;br /&gt;1. (如果之前没做这一步的话)将 Mysql 的 Connector/J 包 (如我的：mysql-connector-java-3.1.12-bin.jar）放入 GlassFish/Sun App Server 安装目录下子目录 \AppServer\lib\ 中&lt;br /&gt;&lt;br /&gt;2. 启动 GlassFish/Sun App Server. 可通过　右击 Runtime | Servers | Sun App Server 选择 start&lt;br /&gt;&lt;br /&gt;3. 启动后，右击 Sun App Server 选择 View Admin console&lt;br /&gt;&lt;br /&gt;4. 登录WEB 管理后台&lt;br /&gt;&lt;br /&gt;5. 在左侧导航器中 点击 Resources | JDBC | Connection Pool s，在表格的头部点击 New... 按钮&lt;br /&gt;&lt;br /&gt;6. 在右侧中填入：&lt;br /&gt;Name:                         MySql&lt;br /&gt;Resource Type:         javax.sql.XADataSource&lt;br /&gt;Database Vendor:      mysql  &lt;br /&gt;&lt;br /&gt;然后点击 next&lt;br /&gt;&lt;br /&gt;7. 注意在 Datasource class name 中自动填入了: com.mysql.jdbc.jdbc2.optional.MysqlXaConnectionPoolDataSource，这个值是不对的。&lt;br /&gt;&lt;br /&gt;你如果想试试的话，在最下面的　Properties　窗格中填入 :&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_bpUunzIgcNA/Rk0F_AKV82I/AAAAAAAAABQ/8-xOwAPMy18/s1600-h/mydqljdbc.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_bpUunzIgcNA/Rk0F_AKV82I/AAAAAAAAABQ/8-xOwAPMy18/s400/mydqljdbc.png" alt="" id="BLOGGER_PHOTO_ID_5065711735794955106" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;点击 Finish&lt;br /&gt;&lt;br /&gt;8. 在结果窗口中点击 Mysql&lt;br /&gt;&lt;br /&gt;9. 在打开的页面中可以看到一个ping 按钮，点击是用来测试配置成功与否，点击一下，将出现如下错误：&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_bpUunzIgcNA/Rk0HEAKV83I/AAAAAAAAABY/oYX5Mdt52ec/s1600-h/mydqljdbc_error.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_bpUunzIgcNA/Rk0HEAKV83I/AAAAAAAAABY/oYX5Mdt52ec/s400/mydqljdbc_error.png" alt="" id="BLOGGER_PHOTO_ID_5065712921205928818" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;解决的办法：&lt;/span&gt;&lt;br /&gt;如果解开mysql-connector-java-3.1.12-bin.jar 文件，在包com.mysql.jdbc.jdbc2.optional 中可　看到:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;com/mysql/jdbc/jdbc2/optional/&lt;br /&gt;com/mysql/jdbc/jdbc2/optional/CallableStatementWrapper.class&lt;br /&gt;com/mysql/jdbc/jdbc2/optional/ConnectionWrapper.class&lt;br /&gt;com/mysql/jdbc/jdbc2/optional/MysqlConnectionPoolDataSource.class&lt;br /&gt;com/mysql/jdbc/jdbc2/optional/MysqlDataSource.class&lt;br /&gt;com/mysql/jdbc/jdbc2/optional/MysqlDataSourceFactory.class&lt;br /&gt;com/mysql/jdbc/jdbc2/optional/MysqlPooledConnection.class&lt;br /&gt;com/mysql/jdbc/jdbc2/optional/MysqlXAConnection.class&lt;br /&gt;com/mysql/jdbc/jdbc2/optional/MysqlXADataSource.class&lt;br /&gt;com/mysql/jdbc/jdbc2/optional/MysqlXAException.class&lt;br /&gt;com/mysql/jdbc/jdbc2/optional/MysqlXid.class&lt;br /&gt;com/mysql/jdbc/jdbc2/optional/PreparedStatementWrapper.class&lt;br /&gt;com/mysql/jdbc/jdbc2/optional/StatementWrapper.class&lt;br /&gt;com/mysql/jdbc/jdbc2/optional/SuspendableXAConnection.class&lt;br /&gt;&lt;br /&gt;...&lt;/pre&gt;其中并没有默认填入的 com.mysql.jdbc.jdbc2.optional.MysqlXaConnectionPoolDataSource, 但是有　com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource&lt;br /&gt;&lt;br /&gt;在页面Application Server  &gt;  Resources  &gt;  JDBC  &gt;  Connection Pools  &gt;  MySql 中：&lt;br /&gt;1.将 Datasource class name 的值改为： com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource&lt;br /&gt;&lt;br /&gt;2.点击 Save 按钮&lt;br /&gt;&lt;br /&gt;3. 点击 Ping 按钮，成功显示：&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_bpUunzIgcNA/Rk0IVwKV84I/AAAAAAAAABg/-SZNDikl42Y/s1600-h/mydqljdbc_success.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://4.bp.blogspot.com/_bpUunzIgcNA/Rk0IVwKV84I/AAAAAAAAABg/-SZNDikl42Y/s400/mydqljdbc_success.png" alt="" id="BLOGGER_PHOTO_ID_5065714325660234626" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-5359638578221088052?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/5359638578221088052/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=5359638578221088052' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/5359638578221088052'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/5359638578221088052'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2007/05/glassfishsun-app-server.html' title='GlassFish/Sun App Server 配置 MySqlXADataSource 的问题'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_bpUunzIgcNA/Rk0F_AKV82I/AAAAAAAAABQ/8-xOwAPMy18/s72-c/mydqljdbc.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-8872930461868475353</id><published>2007-05-16T19:11:00.000+08:00</published><updated>2008-12-11T01:08:13.122+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='NetBeans'/><title type='text'>NetBeans多语言版本，更换默认 Locale 设置时的问题</title><content type='html'>&lt;span style="color: rgb(255, 0, 0);"&gt;update: (这个BUG只会在中文操作系统下出现，在英文版的操作系统上一切正常。看来是一些模块在编写时没有正确地加载对应locale 的 properties 文件)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;在我看来，在日常的工作平台，JDK/NetBeans 的i18n 字体问题已经成为历史了。但是我前些天又登记了一个 &lt;a href="http://www.netbeans.org/issues/show_bug.cgi?id=103908"&gt;BUG &lt;/a&gt;到 NetBeans 的 IssueZilla 中:&lt;br /&gt;&lt;br /&gt;1. 下载多语言版本的安装包，安装&lt;br /&gt;2. 因为我不喜欢那些翻译的不准确的词，所以我打算回退到英文的 locale:&lt;br /&gt;增加一个启动参数到 $NetBeans/etc/netbeans.conf 文件：&lt;br /&gt;netbeans_default_options="&lt;span style="font-weight: bold;"&gt;$默认的配置&lt;/span&gt; --locale en"&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-weight: bold;font-family:georgia;" &gt;语法为:&lt;/span&gt; --locale language[:country[:variant]]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;3. 重启后，你将看到“著名的字体问题”重新又出现了，显示为小方框：&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_bpUunzIgcNA/RkvO_QKV81I/AAAAAAAAABI/iB6nXRhgZM0/s1600-h/i18n.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://4.bp.blogspot.com/_bpUunzIgcNA/RkvO_QKV81I/AAAAAAAAABI/iB6nXRhgZM0/s400/i18n.png" alt="" id="BLOGGER_PHOTO_ID_5065369791973684050" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;当前，只有两种办法可以解决这一问题：&lt;br /&gt;&lt;br /&gt;1. 去掉加上的  locale 参数，但必须忍受翻译得不佳的词了。&lt;br /&gt;&lt;br /&gt;2. 下载英文版，继续用吧。但这样的话，在 Welcome 中你将看不到中文的 Blog.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-8872930461868475353?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/8872930461868475353/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=8872930461868475353' title='8 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/8872930461868475353'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/8872930461868475353'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2007/05/netbeans-locale.html' title='NetBeans多语言版本，更换默认 Locale 设置时的问题'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_bpUunzIgcNA/RkvO_QKV81I/AAAAAAAAABI/iB6nXRhgZM0/s72-c/i18n.png' height='72' width='72'/><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-3739164309819377361</id><published>2007-05-02T22:26:00.000+08:00</published><updated>2008-12-11T01:08:14.161+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='NetBeans'/><title type='text'>NetBeans 6.0 抢先试用</title><content type='html'>NetBeans 6.0 M9 (Preview) 已经出来好些天了，还剩下最后一个里程碑就要进入测试阶段。&lt;br /&gt;&lt;br /&gt;对我来说，自从从 Oracle JDeveloper 转向 NetBeans 以来，在工作中我一直坚持用它。也许是的我工作表现迫使远在美国那边的同事放弃了说服我使用 Eclipse 吧。你也许想知道，作为一名NetBeans 的老用户，我期待 6.0 的什么，虽然它已经很好了。&lt;br /&gt;&lt;br /&gt;1.不要因为整个 Editor 的体系重组，而使强“稳定性”的口碑打折扣 (基本上大部分模块都重新Retouche了），因为我拒绝使用 Eclipse 的原因之一就是: JVM OutOfMemoryError.&lt;br /&gt;&lt;br /&gt;2.Occurrences Highlight 我在之前的文章中写过关于这一功能&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3.Javadoc and Declaration View 我已经等了好几年，我甚至曾经自己利用 NetBeans 的API 实现过一个类似的模块，但是因为NetBeans本身的问题（java meta data record)，功能不完整。有了这两个窗口，就永远不用 Go to Source, Show JavaDoc 了，所有的信息都在手边，只需将鼠标放在想看的类元素上。&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_bpUunzIgcNA/RkXXRKKBVwI/AAAAAAAAAAs/IMDowTFQ0lo/s1600-h/1.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://1.bp.blogspot.com/_bpUunzIgcNA/RkXXRKKBVwI/AAAAAAAAAAs/IMDowTFQ0lo/s400/1.jpg" alt="" id="BLOGGER_PHOTO_ID_5063690045832124162" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;4.Code Generation dialog 我的确很厌倦写类的构造器的实现，特别是类的成员很多的情况下。还有标准的、功能完善的、性能良好的　Common Methods: equals, hashcode　的实现等。&lt;br /&gt;有了它，在右图中的例子中我只需要输入&lt;br /&gt;private long id;&lt;br /&gt;private String name;&lt;br /&gt;private int age;&lt;br /&gt;&lt;br /&gt;其它的代码都是由它产生的。&lt;br /&gt;&lt;br /&gt;5. Local History &lt;br /&gt;&lt;br /&gt;或许有些功能被我忽视了，如是这样的话，请见&lt;a href="http://wiki.netbeans.org/wiki/view/WhatsCoolInNetBeans60"&gt;此处&lt;/a&gt;的详细列表。还有整个重写的 Editor 的功能都陆续地出现在&lt;a href="http://wiki.netbeans.org/wiki/view/Java_EditorUsersGuide"&gt;这&lt;/a&gt;。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;是的，我也保留些目前还未完善的功能，我本人也没有加紧试用。如果我认为有用的话，我会进一步写出来的。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-3739164309819377361?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/3739164309819377361/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=3739164309819377361' title='4 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/3739164309819377361'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/3739164309819377361'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2007/05/netbeans-60.html' title='NetBeans 6.0 抢先试用'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_bpUunzIgcNA/RkXXRKKBVwI/AAAAAAAAAAs/IMDowTFQ0lo/s72-c/1.jpg' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-5767573093968662859</id><published>2007-03-15T11:24:00.000+08:00</published><updated>2008-12-11T01:08:14.429+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='NetBeans'/><title type='text'>Mark Occurrences in NetBeans</title><content type='html'>Mark Occurrences (元素高亮)指的是当鼠标放在某个类元素上时，在当前文件高亮出该元素的 声明和引用。&lt;br /&gt;如果你使用过 Find Usages 的话，你应该能知道这个功能的好处。但是 Mark Occurrences 比起 Find Usages 来属于轻量级的。因为：&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Mark Occurrences 只搜索当前文件&lt;/li&gt;&lt;li&gt;Mark Occurrences 为动态的，不需要菜单来激活只需要将鼠标放在要查看的元素上即可。&lt;/li&gt;&lt;li&gt;Mark Occurrences 懂得语义，比如将鼠标指向当前类的超类，它将显示所有被实现/覆盖的方法；放在方法的返回类型上，将显示方法的所有返回的语句上；...&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;如果你使用的是 NetBeans 6.0 的开发版的话，这个功能已经内置了，不过它被叫做 Highlights：&lt;br /&gt;         &lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;ul&gt;&lt;li&gt;成员作用域&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://wiki.netbeans.org/wiki/attach/Java_EditorUsersGuide/HL_Identifier.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px;" src="http://wiki.netbeans.org/wiki/attach/Java_EditorUsersGuide/HL_Identifier.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;方法返回点&lt;/li&gt;&lt;/ul&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://wiki.netbeans.org/wiki/attach/Java_EditorUsersGuide/HL_ExitPoints.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px;" src="http://wiki.netbeans.org/wiki/attach/Java_EditorUsersGuide/HL_ExitPoints.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;特定异常抛出点&lt;/li&gt;&lt;/ul&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://wiki.netbeans.org/wiki/attach/Java_EditorUsersGuide/HL_ExceptionPoints.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px;" src="http://wiki.netbeans.org/wiki/attach/Java_EditorUsersGuide/HL_ExceptionPoints.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;如果你使用的是 NetBeans 5.x 系列的话，你需要注册一个更新中心，然后下载插件，具体步骤如下：&lt;br /&gt;&lt;ol&gt;&lt;li&gt;选择 &lt;span style="font-weight: bold;"&gt;Tools | Options&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;单击 &lt;span style="font-weight: bold;"&gt;Advanced Options &lt;/span&gt;按钮&lt;/li&gt;&lt;li&gt;选择&lt;span style="font-weight: bold;"&gt; Options | IDE Configuration | System | Autoupdate Types&lt;/span&gt;&lt;/li&gt;&lt;li&gt;右击并选择 &lt;span style="font-weight: bold;"&gt;New | General Update Center&lt;/span&gt;&lt;/li&gt;&lt;li&gt;在 &lt;span style="font-weight: bold;"&gt;Name &lt;/span&gt;输入域中输入&lt;span style="font-weight: bold;"&gt;Sandip Chitale's Modules  &lt;/span&gt;然后单击 &lt;span style="font-weight: bold;"&gt;Finish&lt;/span&gt;&lt;/li&gt;&lt;li&gt;(此步骤不必，如果你在完成上述步骤后立即进行下面的步骤时) 展开&lt;span style="font-weight: bold;"&gt;Autoupdate Types node&lt;/span&gt;, 选择 &lt;span style="font-weight: bold;"&gt;Sandip Chitale's Modules&lt;/span&gt;&lt;/li&gt;&lt;li&gt;在右边的窗口中的第一个属性值Server URL，输入: http://blogs.sun.com/roller/resources/scblog/update-center.xml&lt;/li&gt;&lt;li&gt;确保&lt;span style="font-weight: bold;"&gt;Enabled&lt;/span&gt; 属性勾上。然后关闭当前窗口&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;现在这个更新中心就可以用了，我们目标是得到 Mark Occurrences 插件，它就在这个更新中心中：&lt;br /&gt;选择&lt;span style="font-weight: bold;"&gt;Tools | Update Center &lt;/span&gt;菜单. 勾上 &lt;span style="font-weight: bold;"&gt;Sandip Chitale's Modules&lt;/span&gt; 项，如果它还没被勾上的话。依照更新向导在 Select Modules to Install 窗口中选择&lt;br /&gt;Sandip Chitale's Modules 选择Make Occurrences&lt;br /&gt;&lt;br /&gt;&lt;b&gt;虽然作者声明：&lt;/b&gt;这个模块是个实验性的模块，但是到目前为止在我的工作中我一直在用它，而且没有出现任何问题(比起一些 Eclipse 的插件可强多了!)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;注意: &lt;/span&gt;安装完后(不记得要不要重启 NetBeans), 你应该能看到工具条上出现一个黄色的按钮(如下图)，或者你可以从 &lt;span style="font-weight: bold;"&gt;View | Mark Occurrences&lt;/span&gt; 激活它：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_bpUunzIgcNA/RkU4QqKBVvI/AAAAAAAAAAk/Hcjh5jdB9BA/s1600-h/Mark+Occurrences.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px" src="http://3.bp.blogspot.com/_bpUunzIgcNA/RkU4QqKBVvI/AAAAAAAAAAk/Hcjh5jdB9BA/s400/Mark+Occurrences.png" alt="" id="BLOGGER_PHOTO_ID_5063515214893373170" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-5767573093968662859?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/5767573093968662859/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=5767573093968662859' title='3 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/5767573093968662859'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/5767573093968662859'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2007/03/mark-occurrences-in-netbeans.html' title='Mark Occurrences in NetBeans'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_bpUunzIgcNA/RkU4QqKBVvI/AAAAAAAAAAk/Hcjh5jdB9BA/s72-c/Mark+Occurrences.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-4840119221115522578</id><published>2006-11-11T20:40:00.000+08:00</published><updated>2008-12-11T01:08:14.603+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='NetBeans'/><title type='text'>Hibernate Jpetstore 之四 表示层技术</title><content type='html'>&lt;h2&gt;文档内容&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;概览&lt;/li&gt;&lt;li&gt;Struts 表示层组件 FormBean&lt;/li&gt;&lt;ul&gt;&lt;li&gt;FormBean 配置&lt;/li&gt;&lt;li&gt;FormBean 类层次&lt;/li&gt;&lt;li&gt;BaseActionForm 子类实例 AccountActionForm&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;避免重复提交&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Struts 的事务 Token&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;我们还缺什么?&lt;/li&gt;&lt;ul&gt;&lt;li&gt;客户端校验&lt;/li&gt;&lt;li&gt;漂亮的页面&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;总结&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_bpUunzIgcNA/RnKM9o3zgfI/AAAAAAAAAEU/jsleco4RgaY/s1600-h/index.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://2.bp.blogspot.com/_bpUunzIgcNA/RnKM9o3zgfI/AAAAAAAAAEU/jsleco4RgaY/s400/index.png" alt="" id="BLOGGER_PHOTO_ID_5076274720571359730" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;在阅读本篇文章之前，请先仔细阅读前面系列的相关内容。&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;概览&lt;/h2&gt;&lt;br /&gt;在各种框架欣欣向荣的今天，你能想象最初 Java WEB 开发者的日子吗？要知道，就算是JSP，当时都被寄予厚望，因为当时，开发者不得不在Servlet 中书写之如：out.println("&amp;lt;html&amp;gt;&amp;lt;head&amp;gt;&amp;lt;title&amp;gt;My God&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;");&lt;br /&gt;&lt;br /&gt;你能想象，以这种方式做一个象样的页面是怎样的一种情形。这种情况下，是将“表示层”的内容(HTML标记)渗透进Java代码中了，你哪怕是修改页面上的一个文字，你都不得不在上述的 println 中修改 -&amp;gt; 编译 -&amp;gt; 测试-&amp;gt; ...&lt;br /&gt;&lt;br /&gt;于是，JSP应运而生，可是很快，开发者发现，情况反过来了：在JSP页面代码中到处散布有之如：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&amp;lt;%&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;String amount =&lt;br /&gt;request.getParameter("amount");&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;      if&lt;br /&gt;( amount != null &amp;&amp;amp;&lt;br /&gt;amount.length() &amp;gt; 0 ) {&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;%&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;也就是说，此时表示逻辑的代码渗透进页面代码中了。&lt;br /&gt;&lt;br /&gt;于是才有后来的 JavaBeans, &amp;lt;jsp:useBean&amp;gt;, Taglibs 等，以及术语 WEB MVC, MVC2 等。&lt;br /&gt;&lt;br /&gt;毫无疑问，对于在JAVA Web 领域工作多年的老手，看到我这篇关于 Struts 的文章肯定会觉得好土，或者甚至老掉牙了! 的确，这也是我这段时间一直在考虑是否需要写这样一个系列的原因。&lt;br /&gt;&lt;br /&gt;不管现在 JSF. WebWorks/Struts2, SpringMVC , JBoss Seam 被如何鼓吹，Struts 作为 Web&lt;br /&gt;框架的先行者，还是有它的位置。尽管此例子中所采用的方法比起最新的 Struts (Struts 1.3.x 系列)也同样显得有些陈旧，但是正如 JAVA 领域中的一惯作法，“在引入新功能前先考虑向后兼容”，因此，新的功能尽管加入吧，你可以欣喜若狂，但我也同样可以一直运行已经稳定运行好几年的产品。&lt;br /&gt;&lt;br /&gt;随便提一下，本人并不认为上述新的WEB框架使开发工作简化了多少，相反，倒是增加了不少复杂性。作为新手，很难保证在研究这些框架一周后能开发出一个稳&lt;br /&gt;定可靠的方案。相反象几个简单的框架反而在引入面向 Page 的设计方法的同时，简化了开发的难度：&lt;a href="http://wicket.sourceforge.net/"&gt;Wicket&lt;/a&gt;    &lt;a href="http://click.sourceforge.net/"&gt;Click&lt;/a&gt; ，而且更加符合当今的 Web2 的需求。&lt;br /&gt;&lt;br /&gt;再有，由于 JSTL 的流行，几乎所有的 Web 框架都依靠它来排除JSP脚本。但是我们不会在这里介绍每个 JSTL 标记的用法，具体的用法见工程的JSP 源代码。&lt;br /&gt;&lt;br /&gt;好了，一来就说了这么多，无非是为了引入主角 Struts，但是请原谅，关于整个Struts&lt;br /&gt;的介绍是需要一整书才能介绍完的。所以我们还是以代码为依托，一步步来吧。&lt;br /&gt;我们的主题是表示层的相关技术。&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Struts 表示层组件 FormBean&lt;/h2&gt;&lt;h3&gt;FormBean 配置&lt;/h3&gt;&lt;br /&gt;FormBean 即是我们熟悉的 JSP + JavaBean 设置方式中的 JavaBean，只不过它作为 Struts 框架的组件担任起页面表单与 Struts Action的信息传递的使者。&lt;br /&gt;&lt;br /&gt;为了弄清 FormBean 的工作原理，我们现在给出我们整个的 struts-config.xml 文件的内容&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&amp;lt;?xml version="1.0"&lt;br /&gt;encoding="GBK"?&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&amp;lt;!DOCTYPE struts-config PUBLIC&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;"-//Apache Software&lt;br /&gt;Foundation//DTD Struts Configuration 1.1//EN"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;"http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&amp;lt;struts-config&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;  &amp;lt;!-- 配置此应用中的所有 FormBean&lt;br /&gt;--&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;  &amp;lt;form-beans&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(51, 204, 0);"&gt;&amp;lt;!-- 这种复用&lt;br /&gt;FormBean 的方式值得讨论，见紧随其后的说明 1 --&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;&amp;lt;!--&lt;br /&gt;与注册帐户和帐户信息相关的页面使用的 FormBean --&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;form-bean name="accountForm"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.AccountActionForm"/&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;&amp;lt;!--&lt;br /&gt;与购物车相关的页面使用的 FormBean --&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;form-bean name="cartForm"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.CartActionForm"/&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:monospace;"&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;    &amp;lt;!-- 没有对应的页面元素的&lt;br /&gt;FormBean, 例如点击一个链接或按下搜索按钮等等功能，被设计成不需要 FormBean 来收集用户输入 --&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;form-bean&lt;br /&gt;name="emptyForm"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.BaseActionForm"/&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:monospace;"&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;&amp;lt;!-- 与帐户修改相关的页面使用的&lt;br /&gt;FormBean，因为此时也许在当前的 session 已经存在了一个 accountForm --&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;form-bean&lt;br /&gt;name="workingAccountForm"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.AccountActionForm"/&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:monospace;"&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;&amp;lt;!-- 与所有定单操作相关的页面使用的 FormBean --&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;form-bean&lt;br /&gt;name="workingOrderForm"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.OrderActionForm"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;  &amp;lt;/form-beans&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;&amp;lt;!-- 全局跳转声明，这此跳转可以被所有的&lt;br /&gt;Action 中共享 --&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;global-forwards&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;forward&lt;br /&gt;name="failure" path="/WEB-INF/jsp/struts/Error.jsp"&lt;br /&gt;redirect="false"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;forward&lt;br /&gt;name="unknown-error" path="/WEB-INF/jsp/struts/Error.jsp"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;forward&lt;br /&gt;name="global-signon" path="/WEB-INF/jsp/struts/SignonForm.jsp"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;  &amp;lt;/global-forwards&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;&amp;lt;!-- 以下为所有的 Action 映射&lt;br /&gt;--&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;action-mappings&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;&amp;lt;!--&lt;br /&gt;点击链接将一只宠物加入购物车 --&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;action path="/shop/addItemToCart"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.AddItemToCartAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;name="cartForm" scope="session" validate="false"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success" path="/WEB-INF/jsp/struts/Cart.jsp"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;/action&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;&amp;lt;!-- 结算购物车&lt;br /&gt;--&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;action path="/shop/checkout"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.ViewCartAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;name="cartForm" scope="session" validate="false"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success" path="/WEB-INF/jsp/struts/Checkout.jsp"/&amp;gt;&lt;/span&gt;&amp;lt;/action&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;&amp;lt;!--&lt;br /&gt;修改帐号信息 --&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;action path="/shop/editAccount"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.EditAccountAction"&lt;br /&gt;&lt;br /&gt;name="workingAccountForm" scope="session" validate="true"&lt;br /&gt;input="/WEB-INF/jsp/struts/EditAccountForm.jsp"&amp;gt;&lt;br /&gt;&amp;lt;forward name="success" path="/shop/index.do"/&amp;gt;&lt;br /&gt;&amp;lt;/action&amp;gt;&lt;br /&gt;&amp;lt;action&lt;br /&gt;path="/shop/editAccountForm"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.EditAccountFormAction"&lt;br /&gt;name="workingAccountForm" scope="session"&lt;br /&gt;validate="false"&amp;gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success"&lt;br /&gt;path="/WEB-INF/jsp/struts/EditAccountForm.jsp"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;/action&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;action&lt;br /&gt;path="/shop/index"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.DoNothingAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;validate="false"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success" path="/WEB-INF/jsp/struts/index.jsp"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;/action&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;action&lt;br /&gt;path="/shop/help"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.DoNothingAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;validate="false"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success" path="/WEB-INF/jsp/struts/help.jsp"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;/action&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;action&lt;br /&gt;path="/shop/listOrders"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.ListOrdersAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;name="accountForm" scope="session" validate="false"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success"&lt;br /&gt;path="/WEB-INF/jsp/struts/ListOrders.jsp"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;/action&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;action&lt;br /&gt;path="/shop/newAccount"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.NewAccountAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;name="workingAccountForm" scope="session" validate="true"&lt;br /&gt;input="/WEB-INF/jsp/struts/NewAccountForm.jsp"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success" path="/shop/index.do"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;/action&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;action&lt;br /&gt;path="/shop/newAccountForm"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.NewAccountFormAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;name="workingAccountForm" scope="session" validate="false"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success"&lt;br /&gt;path="/WEB-INF/jsp/struts/NewAccountForm.jsp"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;/action&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;&amp;lt;!--&lt;br /&gt;进入结算中心页面后，点击继续进入此 --&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;action path="/shop/newOrderForm"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.NewOrderFormAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;name="workingOrderForm" scope="session" validate="false"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success"&lt;br /&gt;path="/WEB-INF/jsp/struts/NewOrderForm.jsp"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;/action&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:monospace;"&gt;    &lt;span style="font-weight: bold; color: rgb(51, 204, 0);"&gt;&amp;lt;!-- &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;fixed by pprun: 将原先混在一起的逻辑打破成几个小部分，否则在多步向导式提交&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;页面中的任何一步出错都无理地返回到 NewOrderForm.jsp 页面，而不是真正的出错的页面&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;--&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;!--&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;action&lt;br /&gt;path="/shop/newOrder"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.NewOrderAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;name="workingOrderForm" scope="session" validate="true"&lt;br /&gt;input="/WEB-INF/jsp/struts/NewOrderForm.jsp"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="confirm"&lt;br /&gt;path="/WEB-INF/jsp/struts/ConfirmOrder.jsp"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="shipping"&lt;br /&gt;path="/WEB-INF/jsp/struts/ShippingForm.jsp"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success" path="/WEB-INF/jsp/struts/ViewOrder.jsp"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;/action&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    --&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-weight: bold;"&gt;&amp;lt;!--&lt;br /&gt;填写定单信息的多页向导式页面 --&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;&amp;lt;!--&lt;br /&gt;当第一页校验失败时，需要跳回填写购物单的第一页 --&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;action path="/shop/newOrderStep1"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.NewOrderAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;name="workingOrderForm" scope="session" validate="true"&lt;br /&gt;input="/shop/newOrderForm.do"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="confirm"&lt;br /&gt;path="/WEB-INF/jsp/struts/ConfirmOrder.jsp"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="shipping"&lt;br /&gt;path="/WEB-INF/jsp/struts/ShippingForm.jsp"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;/action&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&amp;lt;!--&lt;br /&gt;&lt;span&gt;(只有页面上填写了将宠物送到不同的地址时，默认为送到当前用户的地址)，&lt;/span&gt;&lt;br /&gt;&lt;span&gt;才会出现此面。此页校验失败，毫无疑问应该回到这个新地址填写页，&lt;/span&gt;&lt;br /&gt;&lt;span&gt;而不是整个流程的第一页。这就是原版中的BUG所在处，因为它将这个向导性的流程&lt;/span&gt;&lt;br /&gt;&lt;span&gt;处理放到了一个映射中，所以没法处理这种情况 --&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;action&lt;br /&gt;path="/shop/newOrderStep2"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.NewOrderAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;name="workingOrderForm" scope="session" validate="true"&lt;br /&gt;input="/WEB-INF/jsp/struts/ShippingForm.jsp"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="confirm"&lt;br /&gt;path="/WEB-INF/jsp/struts/ConfirmOrder.jsp"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;/action&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&amp;lt;!--&lt;br /&gt;当在最后一步确认时出错，需要跳回填写购物单的第一页 --&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;action&lt;br /&gt;path="/shop/newOrderStep3"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.NewOrderAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;name="workingOrderForm" scope="session" validate="true"&lt;br /&gt;input="/WEB-INF/jsp/struts/NewOrderForm.jsp"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success" path="/WEB-INF/jsp/struts/ViewOrder.jsp"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;/action&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;!-- fixed&lt;br /&gt;end --&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:monospace;"&gt;&lt;/span&gt;&lt;span style="font-family:monospace;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;action&lt;br /&gt;path="/shop/removeItemFromCart"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.RemoveItemFromCartAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;name="cartForm" scope="session" validate="false"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success" path="/WEB-INF/jsp/struts/Cart.jsp"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;/action&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;action&lt;br /&gt;path="/shop/searchProducts"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.SearchProductsAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;name="emptyForm" scope="session" validate="false"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success"&lt;br /&gt;path="/WEB-INF/jsp/struts/SearchProducts.jsp"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;/action&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;action&lt;br /&gt;path="/shop/signon"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.SignonAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;name="accountForm" scope="session" validate="false"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success" path="/shop/index.do"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;/action&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;action&lt;br /&gt;path="/shop/signonForm"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.DoNothingAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;validate="false"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success"&lt;br /&gt;path="/WEB-INF/jsp/struts/SignonForm.jsp"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;/action&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;action&lt;br /&gt;path="/shop/updateCartQuantities"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.UpdateCartQuantitiesAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;name="cartForm" scope="session" validate="false"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success" path="/WEB-INF/jsp/struts/Cart.jsp"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;/action&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;action&lt;br /&gt;path="/shop/viewCart"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.ViewCartAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;name="cartForm" scope="session" validate="false"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success" path="/WEB-INF/jsp/struts/Cart.jsp"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;/action&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;action&lt;br /&gt;path="/shop/viewCategory"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.ViewCategoryAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;name="emptyForm" scope="session" validate="true"&lt;br /&gt;input="/WEB-INF/jsp/struts/index.jsp"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success" path="/WEB-INF/jsp/struts/Category.jsp"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;/action&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;action&lt;br /&gt;path="/shop/viewItem"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.ViewItemAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;name="emptyForm" scope="session" validate="true"&lt;br /&gt;input="/WEB-INF/jsp/struts/Product.jsp"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success" path="/WEB-INF/jsp/struts/Item.jsp"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;/action&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;action&lt;br /&gt;path="/shop/viewOrder"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.ViewOrderAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;name="accountForm" scope="session" validate="false"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success" path="/WEB-INF/jsp/struts/ViewOrder.jsp"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;/action&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;action&lt;br /&gt;path="/shop/viewProduct"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.ViewProductAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;name="emptyForm" scope="session" validate="true"&lt;br /&gt;input="/WEB-INF/jsp/struts/index.jsp"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success" path="/WEB-INF/jsp/struts/Product.jsp"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;/action&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;  &amp;lt;/action-mappings&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;  &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&amp;lt;/struts-config&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;说明：&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;1. 从FormBean 的数量和每个使用了FormBean的 Action 映射可知，这里存在 FormBean&lt;br /&gt;复用问题，即用一个来服务多个 Action, 这种方式可以大大减少 FormBean 的数量，&lt;br /&gt;但是，在 Action中的逻辑变得复杂了。因为在 FormBean 中包括了所有 Action 的需求，&lt;br /&gt;而在Action中不得不排除它所不需要的元素的干扰。这样使代码看起来很混乱。&lt;br /&gt;&lt;br /&gt;2. 有了全局声明，在 Action 的代码中就可以随时发出 mapping.findForward("failure");&lt;br /&gt;之类的代码，而不需要在对应的 Action 映射中配置该 &amp;lt;forward&amp;gt; 子元素.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3. 注释掉的 Action 映射是为了修复一个BUG：&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:monospace;"&gt;&lt;/span&gt;&lt;br /&gt;因为在涉及到定单提交时，采用的是多页提交(也就向导页面)方式，即收集的信息是从连续多个&lt;br /&gt;页面中获得的，而不是普通的从一个页面中得到的。这样就涉及到，当其中的一个页面出现校验&lt;br /&gt;失败时，将要将流控跳转到出错的页面，通过将原先混在一起的逻辑打破成几个小部分，&lt;br /&gt;否则在多步向导式提交页面中的任何一步出错都无理地返回到 NewOrderForm.jsp 页面，&lt;br /&gt;而不是真正的出错的页面,请看相应的映射元素的注释说明。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;4. 为了保持连贯性，关于每个映射元素的每个属性，我们重复 &lt;a href="http://pprun.blogspot.com/2007/05/hibernate-jpetstore_31.html"&gt;Hibernate&lt;br /&gt;JPetstore 系列之三: 控制层技术&lt;/a&gt; 中的 ActionForm &amp;lt;-- struts-config.xml --&amp;gt;Action 部分的内容：&lt;br /&gt;&lt;br /&gt;1. path=&lt;span style="font-weight: bold;"&gt;/shop/editAccount&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;所有要去住 /shop/editAccount （严格地讲，如果按照Struts 的方言是 /shop/editAccount.do)&lt;br /&gt;的请求，都要遵循这里的配置&lt;br /&gt;&lt;br /&gt;2. &lt;span style="font-weight: bold;"&gt;name="workingAccountForm"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;都将绑定 workingAccountForm ，注意 form-bean 在 Action 中引用是通过 name&lt;br /&gt;属性来引用的，它是在一开始定义的: &amp;lt;form-bean name="workingAccountForm"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.AccountActionForm"/&amp;gt;&lt;br /&gt;&lt;br /&gt;3. &lt;span style="font-weight: bold;"&gt;scope="session"&lt;/span&gt; 该 bean&lt;br /&gt;&lt;br /&gt;将在整个会话其间始终有效 ，但注意这个配置是多余的，默认就是 session 上下文的，反而如果 bean 只在&lt;br /&gt;request上下文时，才需要明确地声明。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;4. validate="true" 将对表单的输入调用 form-bean 的 validate 方法。但我们发现在&lt;br /&gt;AccountActionForm.java 中，只有 doValidate(...) 方法，并没有 validate()方法，&lt;br /&gt;但细心的话，应该发现了，和所有的Action 都是从BaseAction 中派生而来一样，&lt;br /&gt;所有的ActionForm 中都是从一个基类 BaseActionForm.java 中派生下来。&lt;br /&gt;&lt;br /&gt;其中定义了所有 formbean都需要的东西，对于校验错误的处理。&lt;br /&gt;&lt;br /&gt;其中就是 validate(...) 方法，并在其中调用了 doValidate() 方法，&lt;br /&gt;&lt;br /&gt;而每个BaseActionForm 的子类只要override 这个doValidate() 方法，&lt;br /&gt;&lt;br /&gt;如果 validate="true"声明了的话，那么子类中的 doValidate() 方法将会被调用。这是多态性的表现。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;5. input="..." 一般来讲，一个表单在校验失败后都需要回去重纠正错误的输出项，&lt;br /&gt;所以我们通过这个值来告诉 Struts该回到哪去纠错.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;FormBean 类层次&lt;/h3&gt;&lt;br /&gt;与 Action 类一样，FormBean 也基于类的继承关系设计的，这样子类 FormBean&lt;br /&gt;只需实现父类 FormBean指定的约束，所有的子类都复用父类中的功能并按照这种设计约束工作。&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;基类 BaseActionForm&lt;/h4&gt;该类本身又是从 抽象类 org.apache.struts.action.ActionForm 派生而来，&lt;br /&gt;所以应用中的所有 FormBean只要从 BaseActionForm 派生即可：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;public class BaseActionForm&lt;br /&gt;extends ActionForm {&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;   /**&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;     *此乃最原始的错误处理方法，将所有错误信息加入到一个列表后，然后存入到&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;     *Servlet 请求属性中供页面使用.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;     *更现代的方法是使用 Struts1.1 之后的 commons-validator,关于这个功能在&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;     * 各种关于Struts 的参考或书籍中都有介绍。&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;     *&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;     *是否为调用此方法是通过属性 &lt;span style="color: rgb(102, 0, 204);"&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;validate&lt;/span&gt; &lt;/span&gt;来控制的，如：&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;     *&amp;lt;action path="/shop/signon"type="org.springframework.samples.jpetstore.web.struts.SignonAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;     *name="accountForm" scope="session" &lt;span style="color: rgb(255, 0, 0);"&gt;validate="false"&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;     *是不会调用的，因为 validate="false".&lt;br /&gt;　　　&lt;br /&gt; * 这是“模板方法”（Template method) 设计模式中的“方法”&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;     */&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;public ActionErrors validate(ActionMapping mapping,&lt;br /&gt;HttpServletRequest request) {&lt;br /&gt;ActionErrors errorMessages =&lt;br /&gt;null;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;// 整个系统的错误信息列表，通过调用doValidate(mapping, request, errorList);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;&lt;br /&gt;// addErrorIfStringEmpty 会将错误信息加入到列表当中，并且它被存入了请求属性当中.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;ArrayList errorList = new&lt;br /&gt;ArrayList();&lt;br /&gt;&lt;br /&gt;doValidate(mapping, request,&lt;br /&gt;errorList);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;request.setAttribute("errors", errorList);&lt;br /&gt;&lt;br /&gt;if (!errorList.isEmpty()) {&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;errorMessages = new org.apache.struts.action.ActionErrors();&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;errorMessages.add(ActionErrors.GLOBAL_MESSAGE, new&lt;br /&gt;ActionMessage("global.error"));&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;return errorMessages;&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;/**&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;     *此方法被设计为供子类覆盖的(overriding).&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;     *任何子类实现了这个方法，将自动被上面的 validate 方法调用。&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;     *&lt;br /&gt; * 这是“模板方法"模式中的默认钓子方法，由子类的实现方法来替换。&lt;br /&gt; *&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;     * @param mapping&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;     * @param request&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;     * @param&lt;br /&gt;errors&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;     */&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;public void doValidate(ActionMapping mapping,&lt;br /&gt;HttpServletRequest request, List errors) {&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;/**&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;     *此辅助方法被用来给定的页面输入内容是否为空，如果是空的话，将显示给定的出错信息。&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;     *&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;     * @param errors 错误信息列表&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;     * @param message 当 value 为空时，将显示这个错误信息&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;     * @param value 页面元素对应的值&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;     */&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;protected void addErrorIfStringEmpty(List errors,&lt;br /&gt;String message, String value) {&lt;br /&gt;&lt;br /&gt;if (value == null ||&lt;br /&gt;value.trim().length() &amp;lt; 1) {&lt;br /&gt;&lt;br /&gt;errors.add(message);&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;}&lt;/span&gt;&lt;span style="font-family:monospace;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;BaseActionForm 子类实例 AccountActionForm&lt;/h4&gt;&lt;br /&gt;我仅介绍一个子类 &lt;span style="font-family:monospace;"&gt;AccountActionForm :&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;public class AccountActionForm&lt;br /&gt;extends BaseActionForm {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt; &lt;span style="color: rgb(51, 204, 0);"&gt;/** 用于检验的常量定义，因为在新建帐户与修改帐户时检验逻辑是不一样的。&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* 至少在修改帐户时，帐户名是已经存在了 */&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    public static final String VALIDATE_EDIT_ACCOUNT = "editAccount";&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    public static final String VALIDATE_NEW_ACCOUNT = "newAccount";&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;span style="color: rgb(51, 204, 0);"&gt;/** 用于存贮用户的首先语言的列表 */&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    private static final ArrayList LANGUAGE_LIST = new ArrayList();&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;span style="color: rgb(51, 204, 0);"&gt;/* Private Fields */&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;// 看起来好象与 Account 中的成员重复了，这是因为此 Form 被多个页面重复使用的&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;// 结果，因为在登录页面时，那时根本不存在 Account, 所以不可能通过&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;// account.getUsername() 和 account.getPassword() 来得到用户的输入值的，&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;// 下面两项即是在登录当时收集输入 信息，&lt;/span&gt; &lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;// 其它情况（比如修改，新建帐户时）都是间接使用了 Account 中的成员，因当时都&lt;/span&gt; &lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;// 已经在 session 中存放了一个 Account 的实例&lt;/span&gt; &lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;// 所以重用是有代价的（使代码不那么直观了，如果是一个页面表单 Form 对应一个&lt;/span&gt; &lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;// FormBean 的话，以下成员与页面中的输入元素是一一对应的）&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;   &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;// 供登录页面使用的 元素&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    private String username;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    private String password;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;span style="color: rgb(51, 204, 0);"&gt;// 登录后，与帐户相关的元素&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    private String repeatedPassword;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    private List languages;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    private List categories;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;/span&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;/**&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* 这个成员的值是通过页面隐藏元素传入的：&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;* &lt;span style="color: rgb(51, 51, 255);"&gt;NewAccountForm.jsp 中: &amp;lt;html:hidden name="workingAccountForm" property="validate"&lt;br /&gt;value="newAccount"/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);font-family:monospace;" &gt;* EditAccountForm.jsp 中:&amp;lt;html:hidden name="workingAccountForm" property="validate" value="editAccount" /&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;*/&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    private String validate;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;/**&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* 用来记住用户是从哪里跳转过来的，因为准备对购物车进行结算时，如果没有登录&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* 的话，首先将结算中心页面的地址存入此成员中，登录成功后再跳转过去。&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* 如果没有这样一步操作的话，那么就会出现讨厌的将你送回首页面(也就是程序&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* 的逻辑流程打扰了用户的进程，&lt;span style="color: rgb(255, 0, 0);"&gt;这是最应当避免的&lt;/span&gt;。)&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;*/&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    private String forwardAction;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;/span&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;/**&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* 所有的帐号信息放在这个 POJO 中&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;*/&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    private Account account;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;/span&gt;&lt;span style="font-family:monospace;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;/**&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* 用于显示标语，当你在用户信息页面选择显示标语时&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;*/&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    private String bannerName;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;/**&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* 用于显示根据用户的喜好被推荐的宠物列表,当你选择了显示该列表时。&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;*/&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    private PagedListHolder myList;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;/**&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* 用户最喜欢的宠物类别&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;*/&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    private String favCategoryName;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    /* Static Initializer */&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    static {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;LANGUAGE_LIST.add("english");&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;LANGUAGE_LIST.add("japanese");&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    public AccountActionForm() {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;languages = LANGUAGE_LIST;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    public PagedListHolder getMyList() {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;return myList;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    public void setMyList(PagedListHolder myList) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;this.myList = myList;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    public String getForwardAction() {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;return forwardAction;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    public void setForwardAction(String forwardAction) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;this.forwardAction = forwardAction;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    public String getUsername() {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;return username;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    public void setUsername(String username) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;this.username = username;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    public String getPassword() {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;return password;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:monospace;"&gt;    public void setPassword(String password) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;this.password = password;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    public String getRepeatedPassword() {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;return repeatedPassword;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:monospace;"&gt;    public void setRepeatedPassword(String repeatedPassword) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;this.repeatedPassword = repeatedPassword;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    public Account getAccount() {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;return account;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    public void setAccount(Account account) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;this.account = account;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    public List getLanguages() {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;return languages;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    public void setLanguages(List languages) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;this.languages = languages;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    public List getCategories() {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;return categories;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    public void setCategories(List categories) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;this.categories = categories;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    public String getBannerName() {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;return bannerName;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    public void setBannerName(String bannerName) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;this.bannerName = bannerName;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    public String getFavCategoryName() {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;return favCategoryName;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    public void setFavCategoryName(String favCategoryName) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;this.favCategoryName = favCategoryName;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    public String getValidate() {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;return validate;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:monospace;"&gt;    public void setValidate(String validate) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;this.validate = validate;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;span style="color: rgb(51, 204, 0);"&gt;/**&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt; * 覆盖父类中的方法”默认钓子“方法，用于特定于此子类的输入校验&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt; */&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    public void doValidate(ActionMapping mapping,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;HttpServletRequest request, List errors) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;if (validate != null) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;if (VALIDATE_EDIT_ACCOUNT.equals(validate) ||&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;br /&gt;VALIDATE_NEW_ACCOUNT.equals(validate)) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;if (VALIDATE_NEW_ACCOUNT.equals(validate)) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt; // 是新建帐户时，需要额外的校验&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;account.setStatus("OK");&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;br /&gt;addErrorIfStringEmpty(errors, "User ID is required.",&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;            &lt;br /&gt;account.getUsername());&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;br /&gt;if (account.getPassword() == null ||&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;            &lt;br /&gt;account.getPassword().length() &amp;lt; 1 ||&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;            &lt;br /&gt;!account.getPassword().equals(repeatedPassword)) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;        &lt;br /&gt;errors.add("Passwords did not match or were not provided.  " +&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;                &lt;br /&gt;"Matching passwords are required.");&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;if (account.getPassword() != null &amp;&amp;amp;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;        &lt;br /&gt;account.getPassword().length() &amp;gt; 0) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;br /&gt;if (!account.getPassword().equals(repeatedPassword)) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;        &lt;br /&gt;errors.add("Passwords did not match.");&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;addErrorIfStringEmpty(errors, "First name is required.",&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;        &lt;br /&gt;this.account.getFirstname());&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;addErrorIfStringEmpty(errors, "Last name is required.",&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;        &lt;br /&gt;this.account.getLastname());&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;addErrorIfStringEmpty(errors, "Email address is required.",&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;        &lt;br /&gt;this.account.getEmail());&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;addErrorIfStringEmpty(errors, "Phone number is required.",&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;        &lt;br /&gt;this.account.getPhone());&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;addErrorIfStringEmpty(errors, "Address (1) is required.",&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;        &lt;br /&gt;this.account.getUserAddr().getAddr1());&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;addErrorIfStringEmpty(errors, "City is required.",&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;        &lt;br /&gt;this.account.getUserAddr().getCity());&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;addErrorIfStringEmpty(errors, "State is required.",&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;        &lt;br /&gt;this.account.getUserAddr().getState());&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;addErrorIfStringEmpty(errors, "ZIP is required.",&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;        &lt;br /&gt;this.account.getUserAddr().getZipcode());&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;addErrorIfStringEmpty(errors, "Country is required.",&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;        &lt;br /&gt;this.account.getUserAddr().getCountry());&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &lt;span style="color: rgb(51, 204, 0);"&gt;/**&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* 此方法是一个很重要的方法，我们看看基类中对该方法的描述:&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;*&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* Reset bean properties to their default state, as needed.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* This method is called before the properties are repopulated by the&lt;br /&gt;controller.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* 在需要时，复位 Bean 的属性值，此方法是在控制器重新组装Bean的属性值之前调用的。&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;*&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* The default implementation does nothing. In practice, the only&lt;br /&gt;properties&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* that need to be reset are those which represent checkboxes on a&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* session-scoped form. Otherwise, properties can be given initial values&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* where the field is declared.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* 默认的实现，并没有做任何事。实际上，唯一需要重置的属性是那些基于&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* session 作用域的复选框页面元素。否则这些元素将使用页面上声明的默认值。&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* 是勾选还是未勾选。&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;*&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* If the form is stored in session-scope so that values can be collected&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* over multiple requests (a "wizard"), you must be very careful of&lt;br /&gt;which properties,&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* if any, are reset. As mentioned, session-scope checkboxes must be&lt;br /&gt;reset to&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* false for any page where this property is set. This is because the&lt;br /&gt;client&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* does not submit a checkbox value when it is clear (false).&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* If a session-scoped checkbox is not proactively reset, it can never&lt;br /&gt;be set to false.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* 假如表单是存贮在 Session 作用域中(如：&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* &lt;span style="color: rgb(102, 51, 255);"&gt;&amp;lt;action&lt;br /&gt;path="/shop/signon"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.SignonAction"&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(102, 51, 255);font-family:monospace;" &gt;&lt;br /&gt;* name="accountForm" &lt;span style="color: rgb(255, 0, 0);"&gt;scope="session"&lt;/span&gt;&lt;br /&gt;validate="false"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* 即声明为 session 范围的 formBean)的话，表单元素的值可以在多个请求(即多页向导性页面)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* 中被收集，此时必须小心对等哪些输入域必须重置。象我们前面所述，session&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* 作用域范围内的 checkbox(复选按钮)，在为它们设置值之前必须重置为 false，&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* 因为客户端(即浏览器)在复选按钮未被勾选时并不会发送任何值到服务器端。(否则，&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* 就出现这样的问题：如果之前该复选按钮是勾选状态，并且用户请求这一页面&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* 该按钮显示为勾选状态，在后续的操作中，用户取消选中状态。但是因为 checkbox&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* 在取消选中状态后，浏览器并不发送任何关于这个控件的信息，但 ActionForm 中&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* 要改变控制的状态，必须比较浏览器传上来的状态和当前状态，但因为浏览器并未&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* 告知它，所以 ActionForm 认为这个控件的状态并未改变。因为从这时开始，无论&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;* 用户怎么做，&lt;span style="color: rgb(255, 0, 0);"&gt;这个控件将永远保持为选中状态&lt;/span&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&lt;br /&gt;*/&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    public void&lt;br /&gt;reset(ActionMapping mapping, HttpServletRequest request) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;super.reset(mapping, request);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;setUsername(null);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;setPassword(null);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;setRepeatedPassword(null);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);"&gt;// BUG here: by pprun&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);font-family:monospace;" &gt;&lt;br /&gt;// 按照此方法的 api 文档说明，说 checkbox 的值必须在此复位，&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);font-family:monospace;" &gt;&lt;br /&gt;//可是 NewAccountForm.jsp 中 Enable MyList 和 Enable MyBanner 却没有&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);font-family:monospace;" &gt;&lt;br /&gt;// 所以当用户第一次选中后，以后想改为未选中是没门了，(除了象程序控制那样：&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);font-family:monospace;" &gt;&lt;br /&gt;// 比如：&lt;br /&gt;acctForm.getAccount().setDisplayMylist(&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);font-family:monospace;" &gt;&lt;br /&gt;//&lt;br /&gt;request.getParameter("account.displayMylist") != null);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);font-family:monospace;" &gt;&lt;br /&gt;//   acctForm.getAccount().setDisplayBanner(&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);font-family:monospace;" &gt;&lt;br /&gt;//&lt;br /&gt;request.getParameter("account.displayBanner") != null);)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);font-family:monospace;" &gt;&lt;br /&gt;//&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);font-family:monospace;" &gt;&lt;br /&gt;// 但是当输入错误时重新显示当前页面时，上次选为未选中状态被丢失了！&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);font-family:monospace;" &gt;&lt;br /&gt;//&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);font-family:monospace;" &gt;&lt;br /&gt;// 因为按照 api 的说明&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);font-family:monospace;" &gt;&lt;br /&gt;// 当 checkbox 为未选中状态时，浏览器是不会发信息到服务器端的，所以&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);font-family:monospace;" &gt;&lt;br /&gt;// struts 无法设置其值&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);font-family:monospace;" &gt;&lt;br /&gt;// 解决办法：&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;if (getAccount() != null) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;getAccount().setDisplayMylist(false);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;getAccount().setDisplayBanner(false);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;基于 JSTL 和 Struts HTML Tag 的 JSP&lt;/h2&gt;&lt;br /&gt;我们主要介绍一下JSP文件的总体结构。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;由于此应用在表示层来讲，大体上还是属于 Demo 级别的，所以并未采用 Struts Tile&lt;br /&gt;技术来对页面布局进行管理。而是使用传统的JSP表态包含指令，来包含进公共部分，如页眉，页脚及导航区域等。&lt;br /&gt;&lt;br /&gt;所有以 Include 前缀命名的JSP都用来被其它JSP页面包含的页面块。例如：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&amp;lt;%@ include&lt;br /&gt;file="IncludeTop.jsp" %&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;   页面的具体内容&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&amp;lt;%@ include&lt;br /&gt;file="IncludeBottom.jsp" %&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;在 IncludeTop.jsp 中声明：&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt" %&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;%@ taglib prefix="html" uri="http://jakarta.apache.org/struts/tags-html" %&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;这样我们就不需要在所有用到JSTL的页面中重复声明。&lt;br /&gt;同时，我们并没有使用 Struts 的 Bean 和 Logic 等标记库，因为在 Struts 网站上声明有：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Note:&lt;/strong&gt; - Many of the features in this taglib are also&lt;br /&gt;available in the &lt;a href="http://java.sun.com/products/jsp/jstl/"&gt;&lt;br /&gt;JavaServer Pages Standard Tag Library (JSTL).&lt;/a&gt; The Apache Struts&lt;br /&gt;group encourages the use of the standard tags over the Struts specific&lt;br /&gt;tags when possible.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;避免重复提交&lt;/h2&gt;&lt;br /&gt;避免重复提交是一项挑战性的工作，如果你曾经真正参与过一个基于 B/S 结构的项目的话，&lt;br /&gt;甚至基于 C/S结构的界面也同样有这样的工作，正不过在那个领域叫做控制状态管理，&lt;br /&gt;比如，当你按下一个登录按钮后，而按钮并没有变为disable/不可用状态，&lt;br /&gt;你可能在不经意间又点了一次该按钮，那么在一瞬间你肯定登录了两次，这种情况还好，&lt;br /&gt;因为登录并不伤害系统的其它情况，只不过统计系统或许会感觉到纳闷，&lt;br /&gt;为什么在不到两秒钟内，你登录了两次？&lt;br /&gt;&lt;br /&gt;但是如果这个操作是插入一条数据或者是删除一条数据呢？&lt;br /&gt;&lt;br /&gt;对于插入一条数据，如果系统没设唯一性检查，则两条相同的数据生成了；&lt;br /&gt;&lt;br /&gt;对于删除数据，则第二次删除必然会失败。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;知道问题的重要性了，可是对B/S 开发人员来说，问题还不止这些：&lt;br /&gt;&lt;br /&gt;1.典型的，网络状况不是很好时，为完成一个插入操作可有会等上好几十秒的时间，&lt;br /&gt;用户此时会“再点”一次，还是会“回退”，甚至是忍无可忍关掉浏览器呢？&lt;br /&gt;&lt;br /&gt;2. 对于回退，如果前一操作是删除操作，是否需要再次进行一次删除操作？&lt;br /&gt;&lt;br /&gt;3. 如果用户收藏起了这一个进行删除或插入操作的URL，在他/她重新激活这一链接后，&lt;br /&gt;该做何处理，如果这一操作需要授权呢？&lt;br /&gt;&lt;br /&gt;我们要介绍的机制并不是完美的机制，事实上这些现实的问题并没有列入大多数的WEB&lt;br /&gt;框架的设计议程中，所以做WEB应用开发是乏味的，甚至有时会让人冒火!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Struts 的事务 Token&lt;/h3&gt;&lt;br /&gt;通过使用Struts 的事务Token 来防止重复提交是可行的，&lt;br /&gt;仔细阅读org.apache.struts.action.Action中的如下方法的 javadoc&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;generateToken&lt;/li&gt;&lt;br /&gt;&lt;li&gt;saveToken&lt;/li&gt;&lt;br /&gt;&lt;li&gt;isTokenValid&lt;/li&gt;&lt;br /&gt;&lt;li&gt;resetToken&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://struts.apache.org/1.3.8/struts-taglib/tagreference.html#link"&gt;&amp;lt;html:link&lt;br /&gt;transaction="true"&amp;gt;&lt;/a&gt; If set to true, any current transaction&lt;br /&gt;control token will be included in the generated hyperlink, so that it&lt;br /&gt;will pass an isTokenValid() test in the receiving Action.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;我们通过提交定单的例子来看这个事务 Token 的工作流:&lt;br /&gt;&lt;br /&gt;我们的例子中，是要在显示确认页面中，如果点 'Continue' 按钮，会将一个定单插入到数据库中，&lt;br /&gt;显然，我们需避免重复点击该按钮。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;解决方案&lt;/span&gt;：&lt;br /&gt;&lt;br /&gt;我们得看看这个过程的映射配置：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;&amp;lt;!-- 进入结算中心页面后，点击继续进入此 --&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;action path="/shop/newOrderForm"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.NewOrderFormAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;name="workingOrderForm" scope="session" validate="false"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success"&lt;br /&gt;path="/WEB-INF/jsp/struts/NewOrderForm.jsp"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;/action&amp;gt;&lt;/span&gt;&lt;span style="font-family:monospace;"&gt;&lt;/span&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0); font-weight: bold;"&gt;&amp;lt;!--&lt;br /&gt;填写定单信息的多页向导式页面 --&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;&amp;lt;!--&lt;br /&gt;当第一页校验失败时，需要跳回填写购物单的第一页 --&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;action path="/shop/newOrderStep1"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.NewOrderAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;name="workingOrderForm" scope="session" validate="true"&lt;br /&gt;input="/shop/newOrderForm.do"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="confirm"&lt;br /&gt;path="/WEB-INF/jsp/struts/ConfirmOrder.jsp"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="shipping"&lt;br /&gt;path="/WEB-INF/jsp/struts/ShippingForm.jsp"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;/action&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&amp;lt;!--&lt;br /&gt;(只有页面上填写了将宠物送到不同的地址时，默认为送到当前用户的地址)，才会出现此面。&lt;br /&gt;此页校验失败，毫无疑问应该回到这个新地址填写页，而不是整个流程的第一页。&lt;br /&gt;这就是原版中的BUG所在处，因为它将这个向导性的流程处理放到了一个映射中，&lt;br /&gt;所以没法处理这种情况 --&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;action&lt;br /&gt;path="/shop/newOrderStep2"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.NewOrderAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;name="workingOrderForm" scope="session" validate="true"&lt;br /&gt;input="/WEB-INF/jsp/struts/ShippingForm.jsp"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="confirm"&lt;br /&gt;path="/WEB-INF/jsp/struts/ConfirmOrder.jsp"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;/action&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 204, 0);font-family:monospace;" &gt;&amp;lt;!--&lt;br /&gt;当在最后一步确认时出错，需要跳回填写购物单的第一页 --&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;action&lt;br /&gt;path="/shop/newOrderStep3"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.NewOrderAction"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;name="workingOrderForm" scope="session" validate="true"&lt;br /&gt;input="/WEB-INF/jsp/struts/NewOrderForm.jsp"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;forward name="success" path="/WEB-INF/jsp/struts/ViewOrder.jsp"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;/action&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1. 因为最后三个映射使用的是同一个 NewOrderAction，再有作重复提交检查就是在这个 Action 中，因此，不可能在这个Action 的 exeute 方法中调用 &lt;span style="font-weight: bold; color: rgb(255, 0, 0);"&gt;saveToken(request);,&lt;br /&gt;一般来说，总是在进行重复提交检查的前一个Action 中放一个 Token, 即调用 saveToken(request);方法，因此根据这个流程，我们只能在 &lt;/span&gt;&lt;span style="font-family:monospace;"&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;NewOrderFormAction&lt;br /&gt;&lt;/span&gt;中生成：正如你可以在源码中看到一样：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;//避免重复提交&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;saveToken(request);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;&lt;br /&gt;return mapping.findForward("success");&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;2. 因为我们是要避免重复按 &lt;span style="font-family:monospace;"&gt;ConfirmOrder.jsp&lt;br /&gt;中的 'Continue' 按钮，因此我们需要这样写:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;&amp;lt;%-- prevent duplication submit --%&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;center&amp;gt;&amp;lt;html:link&lt;br /&gt;page="/shop/newOrderStep3.do?step=3&amp;newOrder=true" &lt;span style="color: rgb(255, 0, 0);"&gt;transaction="true"&lt;/span&gt;&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;img border="0"&lt;br /&gt;src="../images/button_continue.gif" /&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/html:link&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/center&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3. 最后，在处理的 Action 中(即 &lt;span style="font-family:monospace;"&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;NewOrderAction&lt;/span&gt;) 进行有效性检查：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;protected ActionForward &lt;span style="font-weight: bold;"&gt;doExecute&lt;/span&gt;(ActionMapping mapping, ActionForm form,&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;HttpServletRequest request, HttpServletResponse response) throws Exception {&lt;br /&gt;&lt;br /&gt;if (!isTokenValid(request, false)&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;// 如果结果不是同一个令牌，为多重提交&lt;br /&gt;&lt;br /&gt;//resetToken(request); &lt;span style="color: rgb(255, 0, 0);"&gt;// 判断完不自动销毁，留待下面的逻辑处理&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;request.setAttribute("message", "多重提交！");&lt;br /&gt;request.getSession().removeAttribute("workingOrderForm");&lt;br /&gt;request.getSession().removeAttribute("cartForm");&lt;br /&gt;&lt;br /&gt;// Fixed by pprun for duplicate-submitand bug in the next time submit:&lt;br /&gt;// 竟然不再需要确认了！&lt;br /&gt;&lt;br /&gt;request.getSession().removeAttribute("orderForm");&lt;br /&gt;return mapping.findForward("failure");&lt;br /&gt;&lt;br /&gt;} else {&lt;br /&gt;&lt;br /&gt;// 多页表单&lt;br /&gt;&lt;br /&gt;OrderActionForm orderForm = (OrderActionForm) form;&lt;br /&gt;&lt;br /&gt;// 是否要进入可选的 shipingAddress 页面&lt;br /&gt;&lt;br /&gt;if&lt;br /&gt;(orderForm.isShippingAddressRequired() &amp;&amp;amp; orderForm.getStep().equals("1")) {&lt;br /&gt;&lt;br /&gt;// 需要将物品寄给别人，而不是自己&lt;br /&gt;&lt;br /&gt;return mapping.findForward("shipping");&lt;br /&gt;&lt;br /&gt;// 两种情况：&lt;br /&gt;// 1.&lt;br /&gt;从页面1直接进入确认页面（不需要寄到不同的地址时）&lt;br /&gt;&lt;br /&gt;// 2. 从 shipingAddress&lt;br /&gt;进入到确认页面&lt;br /&gt;&lt;br /&gt;} else if&lt;br /&gt;((orderForm.getStep().equals("1") &amp;&amp;amp; orderForm.isShippingAddressRequired() == false)&lt;br /&gt;|| orderForm.getStep().equals("2")) {&lt;br /&gt;&lt;br /&gt;// 进入确认页面&lt;br /&gt;&lt;br /&gt;return mapping.findForward("confirm");&lt;br /&gt;&lt;br /&gt;} else if (orderForm.getOrder() != null) {&lt;br /&gt;&lt;br /&gt;// 最终处理&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;// 销毁事务标记(放在此处，最开始处很重要，&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;&lt;br /&gt;// 以保证不管再快的多重提交都会得到无效的判断的)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;resetToken(request);&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Order order = orderForm.getOrder();&lt;br /&gt;// todo 这段逻辑应该放在 DAO 层？&lt;br /&gt;&lt;br /&gt;getPetStore().insertOrder(order);&lt;br /&gt;&lt;br /&gt;// 成功进行后，移除会话状态，&lt;br /&gt;// 以便 NewOrderFormAction 中检查出是否用户后退操作&lt;br /&gt;&lt;br /&gt;request.getSession().removeAttribute("workingOrderForm");&lt;br /&gt;request.getSession().removeAttribute("cartForm");&lt;br /&gt;&lt;br /&gt;// Fixed by pprun for duplicate-submit and bug in the next time submit:&lt;br /&gt;&lt;br /&gt;// 竟然不再需要确认了！所以必须移除它&lt;br /&gt;request.getSession().removeAttribute("orderForm");&lt;br /&gt;request.setAttribute("order", order);&lt;br /&gt;request.setAttribute("message", "Thank you, your order has been&lt;br /&gt;submitted.");&lt;br /&gt;&lt;br /&gt;// 选择 ViewOrder.jsp 中的显示方式&lt;br /&gt;&lt;br /&gt;request.setAttribute("newOrder", true);&lt;br /&gt;return mapping.findForward("success");&lt;br /&gt;&lt;br /&gt;} else {&lt;br /&gt;&lt;br /&gt;request.setAttribute("message",&lt;br /&gt;"An error occurred processing your order (order was null).");&lt;br /&gt;&lt;br /&gt;return mapping.findForward("failure");&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;调用 &lt;/span&gt;&lt;span style="font-family:monospace;"&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;isTokenValid(request,false) 判断我们上述的 1, 2, 3 三处步骤是否是按顺序成功处理完，如果中途哪个步骤重新执行，比如在执行到第三步的 &lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:monospace;"&gt;&lt;span style="font-weight: bold;"&gt;doExecute&lt;/span&gt;()的代码&lt;/span&gt;&lt;span style="font-family:monospace;"&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;&lt;span style="font-weight: bold;"&gt;resetToken(request)之前，&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:monospace;"&gt;又来了一个请求，由于此时 Token 还在，未被 resetToken, 此时比较已经存在的 Token 和 link 带进的&lt;br /&gt;Token，发现它们俩不同，因此&lt;/span&gt;&lt;span style="font-family:monospace;"&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;&lt;span style="font-weight: bold;"&gt;isTokenValid(request,false&lt;/span&gt;)将返回 false,告之多重提交，并跳到错误页面。&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:monospace;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&lt;br /&gt;我们之所以调用&lt;/span&gt;&lt;span style="font-family:monospace;"&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;&lt;span style="font-weight: bold;"&gt; isTokenValid(request, false&lt;/span&gt;&lt;/span&gt;) 这个方法并传一个 false是因为我们使用的向导页面，在这个判断之后到最终的确认页面还有一个或两个页面要处理，因此我们不能在判断完后，立即销毁 Token,而是要等到真正处理完时才这样做。但是对简单逻辑的页面，可以直接调用isTokenValid(request) 或isTokenValid(request,true) 在判断完后，直接销毁 Token.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;我们还缺什么?&lt;/h2&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;客户端校验&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;基于 JavaScript 的检验方式。Struts支持这种处理方式，只不过我们没有把这一功能加入进来而已。因为客户端检验可以在第一时间发现输入数据的问题，而不至于浪费一个数据传输来回(提交错误数&lt;br /&gt;据 -&amp;gt; 在 FormBean 中判断为无效 -&amp;gt; 以错误信息的形式显示给用户)。&lt;br /&gt;&lt;br /&gt;但是，请记住!&lt;br /&gt;服务端校验是一定要做的，因为有人总喜欢在中途拦截、篡改客户发来的数据而骗过客户端的校验器。而服务端是发生在服务器上，只要服务器没被攻破，黑客是不&lt;br /&gt;可能篡改这段 FormBean 代码的。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;漂亮的页面&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;现在的页面只是个原型，离最终的漂亮还有段距离。但是这是需要美工设计人员介入的，因为一个人总不可能样样在行的。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;总结&lt;/h2&gt;&lt;br /&gt;对于新手而言，看基于 Struts 的实现代码，有时的确会失去方向。此时，最好将 Strut-config.xml&lt;br /&gt;文件打印一份在手边，然后对应页面上的每一个动作(提交，链接点击等)得到其要去往的URL，然后在Strut-config.xml 中找到对应的Action 映射。例如：&lt;br /&gt;&lt;br /&gt;在 SignonForm.jsp 页面中有：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;  &amp;lt;a href="&amp;lt;c:url&lt;br /&gt;value="&lt;span style="color: rgb(255, 0, 0);"&gt;/shop/newAccountForm&lt;/span&gt;.do"/&amp;gt;"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    &amp;lt;img&lt;br /&gt;border="0" src="../images/button_register_now.gif" /&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;  &amp;lt;/a&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;于是我们在struts-config.xml 文件中搜索“&lt;span style="color: rgb(255, 0, 0);"&gt;/shop/newAccountForm”&lt;/span&gt; 找到：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;&amp;lt;!-- 修改帐号信息 --&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&amp;lt;action path="&lt;span style="color: rgb(255, 0, 0);"&gt;/shop/newAccountForm&lt;/span&gt;"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.&lt;span style="color: rgb(255, 0, 0);"&gt;NewAccountFormAction&lt;/span&gt;"&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;name="&lt;span style="color: rgb(255, 0, 0);"&gt;workingAccountForm&lt;/span&gt;"&lt;br /&gt;scope="session" validate="false"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;forward name="success"&lt;br /&gt;path="/WEB-INF/jsp/struts/&lt;span style="color: rgb(255, 0, 0);"&gt;NewAccountForm.jsp&lt;/span&gt;"/&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/action&amp;gt;&lt;/span&gt;&lt;span style="font-family:monospace;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;这样我们得知：&lt;br /&gt;&lt;br /&gt;1. 在页面 SignonForm.jsp 中，如果点击了 注册 按钮的话，Struts 将使用 workingAccountForm&lt;br /&gt;(即，类AccountActionForm) 来收集页面的即将的输入值，&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2. validate="false" 所以这时不需要做任何校验，因为此时，用户还没输入数据，只是在&lt;br /&gt;注册页面上点了“注册”按钮被带到了注册信息填写页面。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3. 执行&lt;span style="font-family:monospace;"&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;NewAccountFormAction&lt;/span&gt;&lt;/span&gt;#execute()方法，在成功处理后，将前进到页面 &lt;span style="font-family:monospace;"&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;NewAccountForm.jsp&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;4. 用户输入用户信息数据&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;我们看到在 NewAccountForm.jsp 页面中有：&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;html:form action="&lt;span style="color: rgb(255, 0, 0);"&gt;/shop/newAccount&lt;/span&gt;.do"&lt;br /&gt;styleId="workingAccountForm" method="post" &amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;5. 我们再次在 struts-config.xml 文件中找 "&lt;span style="font-family:monospace;"&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;/shop/newAccount"&lt;/span&gt;, 得到&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;action path="&lt;span style="color: rgb(255, 0, 0);"&gt;/shop/newAccount&lt;/span&gt;"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.NewAccountAction"&lt;br /&gt;&lt;br /&gt;name="workingAccountForm" scope="session" validate="true"&lt;br /&gt;input="/WEB-INF/jsp/struts/NewAccountForm.jsp"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;forward name="success" path="&lt;span style="color: rgb(255, 0, 0);"&gt;/shop/index.do&lt;/span&gt;"/&amp;gt;&lt;br /&gt;&amp;lt;/action&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;6. 这一次还是利用同一个 FormBean(已经在前面收集了用户的输入数据),&lt;br /&gt;因为这一次 在&lt;span style="color: rgb(255, 0, 0);"&gt;NewAccountAction#execute()&lt;/span&gt;方法中要用到 前面的输入值.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;7. 判断输入数据的合法性&lt;br /&gt;&lt;br /&gt;如果不合法，将跳转到同一页面，但此时将显示错误信息&lt;br /&gt;&lt;br /&gt;如果合法，则继续向前，这一次是回到首页，即这一流程宣告结束。&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-4840119221115522578?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/4840119221115522578/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=4840119221115522578' title='1 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/4840119221115522578'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/4840119221115522578'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2007/06/hibernate-jpetstore.html' title='Hibernate Jpetstore 之四 表示层技术'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_bpUunzIgcNA/RnKM9o3zgfI/AAAAAAAAAEU/jsleco4RgaY/s72-c/index.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-4330826481913649418</id><published>2006-10-01T22:04:00.000+08:00</published><updated>2008-01-07T16:24:25.981+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='NetBeans'/><title type='text'>Hibernate JPetstore 系列之三: 控制层技术</title><content type='html'>&lt;a name="1"&gt;&lt;/a&gt;&lt;h2&gt;&lt;a name="2"&gt;&lt;/a&gt;文档内容&lt;br /&gt;&lt;/h2&gt;&lt;div style="margin-left: 40px;"&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;概览&lt;/li&gt;&lt;li&gt;Spring 应用上下文&lt;/li&gt;&lt;li&gt;依赖注入&lt;/li&gt;&lt;li&gt;拦截机&lt;br /&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Spring 内置支持的事务处理拦截机&lt;/li&gt;&lt;li&gt;Spring 自定拦截机&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;li&gt;声明性事务控制&lt;br /&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;事务隔离级别&lt;/li&gt;&lt;li&gt;事务传播行为&lt;/li&gt;&lt;li&gt;只读提示&lt;/li&gt;&lt;li&gt;事务超时周期&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Actions 及 struts-config.xml&lt;/li&gt;&lt;ul&gt;&lt;li&gt;BaseAction&lt;/li&gt;&lt;li&gt;DoNothingAction&lt;/li&gt;&lt;li&gt;ActionForm &amp;lt;-- struts-config.xml --&amp;gt; Action&lt;/li&gt;&lt;li&gt;SecureBaseAction&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;li&gt;DAO接口设计及Hibernate DAO 实现&lt;/li&gt;&lt;li&gt;总结&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;/div&gt;&lt;br /&gt;在阅读本篇文章之前，请先仔细阅读前面系列的相关内容。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;其实在发出上篇文章之后，我发现我遗漏了一个很大的主题没讲，就是在包&lt;br /&gt;org.springframework.samples.jpetstore.dao.hibernate&lt;br /&gt;的实现内容。但是因为这些类的实现严格依赖 Spring 的 HibernateDaoSupport&lt;br /&gt;类，再者由于上篇文章实在太长了，所以决定放在这里来讲。但是请别误会，这个包是属于数据层的内容，并不是控制层。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;&lt;a name="3"&gt;&lt;/a&gt;概览&lt;/h2&gt;&lt;br /&gt;在传统的基于 Struts 应用中，所谓的控制层组件，自己需要写的都无非是一些 Action，对于&lt;br /&gt;ActionForm,严格地讲，它更接近于表示层，主要用来将表示层的表单数据传递到控制层的 Action。&lt;br /&gt;&lt;br /&gt;但是由于我们引入了Spring，所以引入了依赖注入、拦截机(AOP的范畴）及声明性事务控制。&lt;br /&gt;&lt;br /&gt;所以本系列的内容除了将上一系列遗漏的 Dao 的 Hibernate 实现补上之外，就是：&lt;br /&gt;&lt;br /&gt;依赖注入、拦截机、声明性事务控制及Struts 的 Action.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;&lt;a name="4"&gt;&lt;/a&gt;Spring 应用上下文&lt;/h2&gt;&lt;br /&gt;Spring 之所以又叫 Bean 包容器(container), 就是因为它存在一个特殊的配置文件&lt;br /&gt;applicationContext.xml 用来注册所有 bean, 这些 bean&lt;br /&gt;会在应用加载或应用部署完成后一刹那完成初始化，除非你将某个 bean&lt;br /&gt;配置成“懒初始化”(Lazily-instantiating)，默认的是提前初始化 (eagerly pre-instantiate).详情见&lt;br /&gt;Spring reference: 3.3.5. Lazily-instantiating beans&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;我们将 applicationContext.xml 全部内容列出:&lt;br /&gt;&lt;span class="921372908-18012007"&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!--&lt;br /&gt;- Application context definition for JPetStore's business layer.&lt;br /&gt;- Contains bean references to the transaction manager and to the DAOs in&lt;br /&gt;- dataAccessContext-local/jta.xml (see web.xml's "contextConfigLocation").&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;Jpetstore 的应用上下文定义，包含事务管理和引用了&lt;br /&gt;在 dataAccessContext-local/jta.xml&lt;br /&gt;(具体使用了哪个要看 web.xml 中的 'contextConfigLocation' 的配置）&lt;br /&gt;中注册的DAO&lt;/span&gt;&lt;br /&gt;--&amp;gt;&lt;br /&gt;&amp;lt;beans xmlns="http://www.springframework.org/schema/beans"&lt;br /&gt;xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;xmlns:aop="http://www.springframework.org/schema/aop"&lt;br /&gt;xmlns:tx="http://www.springframework.org/schema/tx"&lt;br /&gt;xsi:schemaLocation="http://www.springframework.org/schema/beans&lt;br /&gt;http://www.springframework.org/schema/beans/spring-beans-2.0.xsd&lt;br /&gt;http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd&lt;br /&gt;http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd"&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- ========================= GENERAL DEFINITIONS ========================= --&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- Configurer that replaces ${...} placeholders with values from properties files&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;占位符的值将从列出的属性文件中抽取出来&lt;/span&gt;&lt;br /&gt;--&amp;gt;&lt;br /&gt;&amp;lt;!-- (in this case, mail and JDBC related properties) --&amp;gt;&lt;br /&gt;&amp;lt;bean id="propertyConfigurer"&lt;br /&gt;class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"&amp;gt;&lt;br /&gt;&amp;lt;property name="locations"&amp;gt;&lt;br /&gt;&amp;lt;list&amp;gt;&lt;br /&gt;&amp;lt;value&amp;gt;WEB-INF/mail.properties&amp;lt;/value&amp;gt;&lt;br /&gt;&amp;lt;value&amp;gt;WEB-INF/jdbc.properties&amp;lt;/value&amp;gt;&lt;br /&gt;&amp;lt;/list&amp;gt;&lt;br /&gt;&amp;lt;/property&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- MailSender used by EmailAdvice&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;指定用于发送邮件的 javamail 实现者，这里使用了 spring 自带的实现。&lt;br /&gt;此 bean 将被 emailAdvice 使用&lt;/span&gt;&lt;br /&gt;--&amp;gt;&lt;br /&gt;&amp;lt;bean id="mailSender"&lt;br /&gt;class="org.springframework.mail.javamail.JavaMailSenderImpl"&amp;gt;&lt;br /&gt;&amp;lt;property name="host" value="${mail.host}"/&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- ========================= BUSINESS OBJECT DEFINITIONS ======================== --&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!--&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;主要的商业逻辑对象，即我们所说的门面对象&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;&lt;br /&gt;注入了所有的DAO，这些DAO是引用了 dataAccessContext-xxx.xml 中&lt;br /&gt;定义的DAO&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt; 门面对象中的所有方法的事务控制将通过下面的 aop:config 来加以控制&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;- JPetStore primary business object (default implementation).&lt;br /&gt;- Transaction advice gets applied through the AOP configuration below.&lt;br /&gt;--&amp;gt;&lt;br /&gt;&amp;lt;bean id="petStore" class="org.springframework.samples.jpetstore.domain.logic.PetStoreImpl"&amp;gt;&lt;br /&gt;&amp;lt;property name="accountDao" ref="accountDao"/&amp;gt;&lt;br /&gt;&amp;lt;property name="categoryDao" ref="categoryDao"/&amp;gt;&lt;br /&gt;&amp;lt;property name="productDao" ref="productDao"/&amp;gt;&lt;br /&gt;&amp;lt;property name="itemDao" ref="itemDao"/&amp;gt;&lt;br /&gt;&amp;lt;property name="orderDao" ref="orderDao"/&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- ========================= ASPECT CONFIGURATION ======================== --&amp;gt;&lt;br /&gt;&amp;lt;!-- &lt;span style="color: rgb(255, 0, 0);"&gt;AOP配置，用来控制&lt;big&gt;&lt;big&gt;&lt;span style="font-weight: bold;"&gt;哪些&lt;/span&gt;&lt;/big&gt;&lt;/big&gt;方法将需要进行事务处理，采用了AspectJ 的语法&lt;/span&gt; --&amp;gt;&lt;br /&gt;&amp;lt;aop:config&amp;gt;&lt;br /&gt;&amp;lt;!--&lt;br /&gt;This definition creates auto-proxy infrastructure based on the given pointcut,&lt;br /&gt;expressed in AspectJ pointcut language. Here: applying the advice named&lt;br /&gt;"txAdvice" to all methods on classes named PetStoreImpl.&lt;br /&gt;--&amp;gt;&lt;br /&gt;&amp;lt;!-- &lt;span style="color: rgb(255, 0, 0);"&gt;指出在 PetStoreFacade 的所有方法都将采用 txAdvice(在紧接着的元素中定义了）事务方针，&lt;br /&gt;注意，我们这里虽然指定的是接口 PetStoreFacace, 但其暗示着其所有的实现类也将&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;　　　　　　　　&lt;br /&gt;同样具有这种性质，因为本身就是实现类的方法在执行的，接口是没有方法体的。&lt;/span&gt; --&amp;gt;&lt;br /&gt;&amp;lt;aop:advisor pointcut="execution(* *..PetStoreFacade.*(..))" advice-ref="txAdvice"/&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!--&lt;br /&gt;This definition creates auto-proxy infrastructure based on the given pointcut,&lt;br /&gt;expressed in AspectJ pointcut language. Here: applying the advice named&lt;br /&gt;"emailAdvice" to insertOrder(Order) method of PetStoreImpl&lt;br /&gt;--&amp;gt;&lt;br /&gt;&amp;lt;!-- &lt;span style="color: rgb(255, 0, 0);"&gt;当执行 PetStoreFacade.insertOrder方法，该方法最后一个参数为Order类型时&lt;br /&gt;（其实我们的例子中只有一个 insertOrder 方法，但这告诉了我们，当我们的接口或类中有重载了的方法，&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;　　　　　　　　&lt;br /&gt;并且各个重载的方法可能使用不同的拦截机机制时，我们可以通过方法的参数加以指定），&lt;br /&gt;将执行emailAdvice(在最后定义的那个元素）&lt;/span&gt;--&amp;gt;&lt;br /&gt;&amp;lt;aop:advisor pointcut="execution(* *..PetStoreFacade.insertOrder(*..Order))"&lt;br /&gt;advice-ref="emailAdvice"/&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/aop:config&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!--&lt;br /&gt;　　　　　&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;事务方针声明，用于控制采用&lt;big style="font-weight: bold;"&gt;&lt;big&gt;什么样&lt;/big&gt;&lt;/big&gt;的事务策略&lt;/span&gt;&lt;&gt; Transaction advice definition,&lt;br /&gt;based on method name patterns.&lt;br /&gt;Defaults to PROPAGATION_REQUIRED for all methods whose name starts with&lt;br /&gt;"insert" or "update", and to PROPAGATION_REQUIRED with read-only hint&lt;br /&gt;for all other methods.&lt;br /&gt;--&amp;gt;&lt;br /&gt;&amp;lt;tx:advice id="txAdvice"&amp;gt;&lt;br /&gt;&amp;lt;tx:attributes&amp;gt;&lt;br /&gt;&amp;lt;tx:method name="insert*"/&amp;gt;&lt;br /&gt;&amp;lt;tx:method name="update*"/&amp;gt;&lt;br /&gt;&amp;lt;tx:method name="*" read-only="true"/&amp;gt;&lt;br /&gt;&amp;lt;/tx:attributes&amp;gt;&lt;br /&gt;&amp;lt;/tx:advice&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- &lt;span style="color: rgb(255, 0, 0);"&gt;拦截机，用于在适当的时机(通过AOP配置，如上面)在方法执行成功后发送邮件&lt;/span&gt;&lt;br /&gt;AOP advice used to send confirmation email after order has been submitted --&amp;gt;&lt;br /&gt;&amp;lt;!-- --&amp;gt;&lt;br /&gt;&amp;lt;bean id="emailAdvice"&lt;br /&gt;class="org.springframework.samples.jpetstore.domain.logic.SendOrderConfirmationEmailAdvice"&amp;gt;&lt;br /&gt;&amp;lt;property name="mailSender" ref="mailSender"/&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- ========================= &lt;span style="color: rgb(255, 0, 0);"&gt;忽略&lt;/span&gt; REMOTE EXPORTER DEFINITIONS ======================== --&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/beans&gt;&lt;span style="font-family:Georgia,serif;"&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;/span&gt;&lt;br /&gt;先粗略地看看&lt;span style="color: rgb(255, 0, 0);"&gt;红色&lt;/span&gt;的注释和相关的配置，下面将一一介绍。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;&lt;a name="5"&gt;&lt;/a&gt;依赖注入&lt;/h2&gt;&lt;br /&gt;依赖注入 DI (&lt;span style="font-weight: bold;"&gt;D&lt;/span&gt;ependency &lt;span style="font-weight: bold;"&gt;I&lt;/span&gt;njection )，又做反转控制 IoC (&lt;span style="font-weight: bold;"&gt;I&lt;/span&gt;nversion &lt;span style="font-weight: bold;"&gt;o&lt;/span&gt;f &lt;span style="font-weight: bold;"&gt;C&lt;/span&gt;ontrol)。&lt;br /&gt;不管这些概念如何，我们用最简单的文字和例子加以描述，省得费心去理解一大堆陌生的概念。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;由于我们的门面实现类中要汇集所有的DAO，要调用DAO的方法，当然首先需要获得DAO的实例对象。既然我们知道一定会用到DAO的实例对象，那么，传&lt;br /&gt;统的方式肯定不外乎&lt;br /&gt;&lt;br /&gt;在 &lt;span style="font-family:monospace;"&gt;PetStoreImpl &lt;/span&gt;中&lt;br /&gt;&lt;span class="921372908-18012007"&gt;&lt;br /&gt;&lt;pre&gt;AccountDao accountDao = new HibernateAccountDao(...);&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;这是传统的依赖方式，即 PetStoreImpl 依赖于 AccountDao，这种传统的依赖方式有什么不好？&lt;br /&gt;&lt;br /&gt;因为为了初始化一个类，虽然 对类型的声明可以是接口或抽象类，如我们的 AccountDao 正好是个接口，但 new 后面永远只能是&lt;br /&gt;具体的实现类 (concrete class),&lt;br /&gt;不可能是抽象类或接口。这说明了什么？这说明了当从一种实现切换到另一种实现时，你仍然不得不修改这段代码。如现在想提高性能，重新用JDBC实现了一套&lt;br /&gt;DAO，JdbcAccountDao, 那么从 HibernateAccountDao　换到 JdbcAccountDao, 我们需要这样做：&lt;br /&gt;&lt;br /&gt;&lt;span class="921372908-18012007"&gt;&lt;br /&gt;&lt;pre&gt;AccountDao accountDao = new &lt;span style="color: rgb(255, 0, 0);"&gt;JdbcAccountDao&lt;/span&gt;(...);&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;虽然工厂方法可以减轻这种影响，将改变集中到工厂方法之中，但是一个类要想被构造出来，在普通的 Java 代码中离不开 new&lt;br /&gt;关键字。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;所以依赖注入的倡导者认为，既然我们知道 PetStoreImpl 一定会用到 AccountDao，我们不如让 AccountDao 注入到&lt;br /&gt;PetStoreImpl&lt;br /&gt;中，何必要等到要用时，才将其初始出来呢？这就原行的顺序依赖倒过来了：被依赖的对象自己初始化好了并且注入到依赖于它的对象中来。这就是依赖注入或反转&lt;br /&gt;控制的由来。&lt;br /&gt;&lt;br /&gt;但是，我知道任何东西都有利必有弊：依赖注入有时会显得浪费，如果整个应用的生命周期内根本没有用到这个类，那个它的初始化及浪费在加载时的时间就显示多&lt;br /&gt;余了。但是，这些损失对于服务器端的程序来讲还是可以忍受，只是对于客户端的程序有些不适合。比如我们的IDE，启动要那么长时间，就是因为每次都加载了&lt;br /&gt;所有的东西，但其实我们只想用它打开一个源文件，看完就关了罢了。&lt;br /&gt;&lt;br /&gt;但是我们前面提到了，“懒加载”就是为了解决这一问题的。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;下面我们看看项目的依赖注入的例子：&lt;br /&gt;&lt;br /&gt;PetStoreImpl.java:&lt;br /&gt;&lt;br /&gt;&lt;span class="921372908-18012007"&gt;&lt;br /&gt;&lt;pre&gt;public class PetStoreImpl implements PetStoreFacade, OrderService {&lt;br /&gt;&lt;br /&gt;// &lt;span style="color: rgb(255, 0, 0);"&gt;以下是所依赖的DAO &lt;/span&gt;&lt;br /&gt;private AccountDao accountDao;&lt;br /&gt;&lt;br /&gt;private CategoryDao categoryDao;&lt;br /&gt;&lt;br /&gt;private ProductDao productDao;&lt;br /&gt;&lt;br /&gt;private ItemDao itemDao;&lt;br /&gt;&lt;br /&gt;private OrderDao orderDao;&lt;br /&gt;&lt;br /&gt;//-------------------------------------------------------------------------&lt;br /&gt;// Setter methods for dependency injection&lt;br /&gt;// &lt;span style="color: rgb(255, 0, 0);"&gt;我们采用的是基于 Setter 方法的注入方式&lt;/span&gt;&lt;br /&gt;//-------------------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;public void setAccountDao(AccountDao accountDao) {&lt;br /&gt;this.accountDao = accountDao;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setCategoryDao(CategoryDao categoryDao) {&lt;br /&gt;this.categoryDao = categoryDao;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setProductDao(ProductDao productDao) {&lt;br /&gt;this.productDao = productDao;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setItemDao(ItemDao itemDao) {&lt;br /&gt;this.itemDao = itemDao;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setOrderDao(OrderDao orderDao) {&lt;br /&gt;this.orderDao = orderDao;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;代码应该好简单，声明一个 private 的依赖的对象，提供一个对应的 setter 方法，剩下的事情就是配置了：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;applicationContext.xml 文件中：对每个私有的成员对应有一个 &amp;lt;property name="成员的名称"&amp;gt;，&lt;br /&gt;ref= 告诉 Spring 这个成员的实例是引用其它地方配置的 bean, 如果不是在其它地方配置的，这里可以直接提供一个&lt;br /&gt;value="org.springframework.samples.jpetstore.dao.hibernate.HibernateAccountDao",&lt;br /&gt;对于其它类型的属性，如集合类型的属性的值的设置，请参见 Spring reference: 3.3.3. Bean properties&lt;br /&gt;and constructor arguments detailed&lt;br /&gt;&lt;br /&gt;&lt;span class="921372908-18012007"&gt;&lt;br /&gt;&lt;pre&gt; &amp;lt;bean id="petStore" class="org.springframework.samples.jpetstore.domain.logic.PetStoreImpl"&amp;gt;&lt;br /&gt;&amp;lt;property name="accountDao" ref="accountDao"/&amp;gt;&lt;br /&gt;&amp;lt;property name="categoryDao" ref="categoryDao"/&amp;gt;&lt;br /&gt;&amp;lt;property name="productDao" ref="productDao"/&amp;gt;&lt;br /&gt;&amp;lt;property name="itemDao" ref="itemDao"/&amp;gt;&lt;br /&gt;&amp;lt;property name="orderDao" ref="orderDao"/&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;dataAccessContext-hibernate.xml 文件中：该文件中配置了所有的 DAO的实现类.&lt;br /&gt;&lt;br /&gt;值得注意的是，每个DAO的实现类又需要一个 sessionFactory Bean, 这个重量级的bean 同样是在此文件中定义了。&lt;br /&gt;&lt;br /&gt;&lt;span class="921372908-18012007"&gt;&lt;br /&gt;&lt;pre&gt; &amp;lt;bean id="accountDao" class="org.springframework.samples.jpetstore.dao.hibernate.HibernateAccountDao"&amp;gt;&lt;br /&gt;&amp;lt;property name="sessionFactory" ref="sessionFactory"/&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;bean id="categoryDao" class="org.springframework.samples.jpetstore.dao.hibernate.HibernateCategoryDao"&amp;gt;&lt;br /&gt;&amp;lt;property name="sessionFactory" ref="sessionFactory"/&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;bean id="productDao" class="org.springframework.samples.jpetstore.dao.hibernate.HibernateProductDao"&amp;gt;&lt;br /&gt;&amp;lt;property name="sessionFactory" ref="sessionFactory"/&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;bean id="itemDao" class="org.springframework.samples.jpetstore.dao.hibernate.HibernateItemDao"&amp;gt;&lt;br /&gt;&amp;lt;property name="sessionFactory" ref="sessionFactory"/&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;bean id="orderDao" class="org.springframework.samples.jpetstore.dao.hibernate.HibernateOrderDao"&amp;gt;&lt;br /&gt;&amp;lt;property name="sessionFactory" ref="sessionFactory"/&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;如果你细心的话，你会发现，在所有的Hibernate 实现的DAO中，根本不存在:&lt;br /&gt;&lt;br /&gt;&lt;span class="921372908-18012007"&gt;&lt;br /&gt;&lt;pre&gt;private SessionFactory sessionFactory;&lt;br /&gt;&lt;br /&gt;public final void setSessionFactory(SessionFactory sessionFactory) {&lt;br /&gt;this.sessionFactory = sessionFactory;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;但是，我们看看，所有的这些类都是从 &lt;span style="font-family:monospace;"&gt;org.springframework.orm.hibernate3.support.HibernateDaoSupport&lt;br /&gt;派生过来的，跳到它的源码，我们可以看到：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="921372908-18012007"&gt;&lt;br /&gt;&lt;pre&gt; private HibernateTemplate hibernateTemplate;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Set the Hibernate SessionFactory to be used by this DAO.&lt;br /&gt;* Will automatically create a HibernateTemplate for the given SessionFactory.&lt;br /&gt;* @see #createHibernateTemplate&lt;br /&gt;* @see #setHibernateTemplate&lt;br /&gt;*/&lt;br /&gt;public final void setSessionFactory(SessionFactory sessionFactory) {&lt;br /&gt;this.hibernateTemplate = createHibernateTemplate(sessionFactory);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;在 Spring 中 &lt;span style="font-family:monospace;"&gt;HibernateTemplate&lt;br /&gt;扮演着与 Hibernate 的 SessionFactory.getCurrentSession()同样的角色，即获得一次数据库会话，与&lt;br /&gt;JDBC 的 DriverManager.getConnection(...) 有异曲同工之效。&lt;br /&gt;&lt;br /&gt;所以上面的代码是真正把 sessionFactory 注入到了 HibernateDaoSupport 类中了，也即是所有 Hibernate&lt;br /&gt;DAO 的超类中了。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;因此，我们在所有的Hibernate DAO 总是看到如下代码：&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="921372908-18012007"&gt;&lt;br /&gt;&lt;pre&gt;getHibernateTemplate().xxx&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;如这样，获得了数据库连接后，你想干什么就干什么，但剩下的内容正是上系列遗漏的，在HibernateDAO 实现一节中介绍&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;&lt;a name="6"&gt;&lt;/a&gt;拦截机&lt;/h2&gt;&lt;a href="http://www.blogger.com/Hibernate%20Jpetstore%20%D6%AE%C8%FD%20%BF%D8%D6%C6%B2%E3%C9%E8%BC%C6.html#1"&gt;&lt;small&gt;&lt;/small&gt;&lt;/a&gt;&lt;br /&gt;拦截机 (Interceptor), 是 AOP (&lt;span style="font-weight: bold;"&gt;A&lt;/span&gt;spect-&lt;span style="font-weight: bold;"&gt;O&lt;/span&gt;riented &lt;span style="font-weight: bold;"&gt;P&lt;/span&gt;rogramming)&lt;br /&gt;的另一种叫法，我们的应用在两个地方使用了这种机制。AOP本身是一门语言，只不过我们使用的是基于JAVA的集成到Spring 中的&lt;br /&gt;SpringAOP。同样，我们将通过我们的例子来理解陌生的概念。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;先看一下最常用的事务控制器拦截机。如果不采用拦截机的机制时，在使用JDBC进行数据库访问时，存在两种情况：&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;自动提交&lt;/span&gt;    &amp;amp; nbsp;&lt;br /&gt;这是JDBC驱动默认的模式，每次数据库操作(CRUD)成功完成后，都作为一个单独的事务自动提交，如果未成功完成，即抛出了&lt;br /&gt;SQLException 的话，仅最近的一个操作将回滚。&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;非自动提交&lt;/span&gt;&lt;br /&gt;这是想更好的控制事务时需要程序地方式进行控制：&lt;/li&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;在进行该事务单元的任何操作之前 &lt;span style="font-family:monospace;"&gt;setAutoCommit(false)&lt;/span&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;在成功完成事务单元后 &lt;span style="font-family:monospace;"&gt;commit()&lt;/span&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;在异常发生后&lt;span style="font-family:monospace;"&gt; rollback()&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;br /&gt;自动提交模式是不被推荐的，因为每个操作都将产生一个事务点，这对于大的应用来说性能将受到影响；再有，对于常见的业务逻辑，这种模式显得无能为力。比&lt;br /&gt;如：&lt;br /&gt;&lt;br /&gt;转帐，从A帐户取出100元，将其存入B帐户；如果在这两个操作之间发生了错误，那么用户A将损失了100元，而本来应该给帐户B的，却因为失败给了银&lt;br /&gt;行。&lt;br /&gt;&lt;br /&gt;所以，建议在所有的应用中，如果使用 JDBC 都将不得不采用非自动提交模式(你们要能发现了在我们的 JDBC&lt;br /&gt;那个例子中，我们采用的就是自动提交模式，我们是为了把精力放在JDBC上，而不是事务处理上)，即我们不得不在每个方法中：&lt;br /&gt;&lt;br /&gt;&lt;span class="921372908-18012007"&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;try&lt;/span&gt; {&lt;br /&gt;// &lt;span style="color: rgb(255, 0, 0);"&gt;在获得连接后，立即通过调用　setAutoCommit(false) 将事务处理置为非自动提交模式&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;// Prepare Query to fetch the user Information&lt;br /&gt;pst = conn.prepareStatement(findByName);&lt;br /&gt;&lt;br /&gt;// ...&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;conn.commit();&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;} &lt;span style="color: rgb(51, 51, 255);"&gt;catch&lt;/span&gt;(Exception ex) {&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;conn.rollback();&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;throw ex;&lt;br /&gt;} &lt;span style="color: rgb(51, 51, 255);"&gt;finally&lt;/span&gt; {&lt;br /&gt;try {&lt;br /&gt;// Close Result Set and Statement&lt;br /&gt;if (rset != null) rset.close();&lt;br /&gt;if (pst != null) pst.close();&lt;br /&gt;&lt;br /&gt;} catch (Exception ex) {&lt;br /&gt;ex.printStackTrace();&lt;br /&gt;throw new Exception("SQL Error while closing objects = " +&lt;br /&gt;ex.toString());&lt;br /&gt;}&lt;br /&gt;&lt;span class="921372908-18012007"&gt;&lt;pre&gt; }&lt;/pre&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;这样代码在AOP的倡导者看来是“肮脏”的代码。他们认为，所有的与事务有关的方法都应当可以集中配置（见声明性事务控制），&lt;br /&gt;并自动拦截，程序应当关心他们的主要任务，即商业逻辑，而不应和事务处理的代码搅和在一起。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;我先看看 Spring 是怎么做到拦截的：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;a name="6.1"&gt;&lt;/a&gt;Spring 内置支持的事务处理拦截机&lt;a href="http://www.blogger.com/Hibernate%20Jpetstore%20%D6%AE%C8%FD%20%BF%D8%D6%C6%B2%E3%C9%E8%BC%C6.html#1"&gt;&lt;small&gt;&lt;/small&gt;&lt;/a&gt;&lt;br /&gt;&lt;/h3&gt;&lt;div style="text-align: right;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;这个配置比想象的要简单的多：&lt;br /&gt;&lt;br /&gt;&lt;span class="921372908-18012007"&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;aop:config&amp;gt;&lt;br /&gt;&amp;lt;!--&lt;br /&gt;This definition creates auto-proxy infrastructure based on the given pointcut,&lt;br /&gt;expressed in AspectJ pointcut language. Here: applying the advice named&lt;br /&gt;"txAdvice" to all methods on classes named PetStoreImpl.&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;指出在 PetStoreFacade 的所有方法都将采用 txAdvice(在紧接着的元素中定义了）事务方针，&lt;br /&gt;注意，我们这里虽然指定的是接口 PetStoreFacace, &lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;&lt;br /&gt;但其暗示着其所有的实现类也将同样具有这种性质，因为本身就是实现类的方法在执行的，接口是没有方法体的。&lt;/span&gt;&lt;&gt; --&amp;gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;&amp;lt;aop:advisor pointcut="execution(* *..PetStoreFacade.*(..))" advice-ref="txAdvice"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- 其它拦截机--&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/aop:config&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;1. 所有的拦截机配置都放在 &amp;lt;aop:config&amp;gt; 配置元素中.&lt;br /&gt;&lt;br /&gt;2. 下面还是需要理解一下几个有关AOP的专用名词，不过，是挺抽象的，最好能会意出其的用意&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;pointcut  切入点，比如：updateAccount&lt;br /&gt;方法需要进行事务管理，则这个切入点就是“执行方法体”(execution)。Spring 所有支持的切入点类型在都在 Spring&lt;br /&gt;reference: 6.2.3.1. Supported Pointcut Designators 中列出了。&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;advice    要对这个切入点进行什么操作，比如事务控制&lt;/li&gt;&lt;br /&gt;&lt;li&gt;advisor   Spring 特有的概念，将上两个概念合到一个概念中来，即一个 advisor&lt;br /&gt;包含了一个切入点及对这个切入点所实施的操作。&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;因为 方法执行切入点 execution 为最常见的切入点类型，我们着重介绍一下，execution 的完全形式为：&lt;br /&gt;&lt;br /&gt;&lt;pre class="programlisting"&gt;&lt;span style="font-weight: bold;"&gt;execution&lt;/span&gt;(modifiers-pattern? ret-type-pattern declaring-type-pattern?&lt;br /&gt;name-pattern(param-pattern) throws-pattern?)&lt;/pre&gt;&lt;br /&gt;这是一个正则表达式，其中由 '?' 结尾的部分是可选的。翻译过来就是：&lt;br /&gt;&lt;br /&gt;&lt;pre class="programlisting"&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-family:monospace;"&gt;执行&lt;/span&gt;&lt;/span&gt;(方法访问修饰符? 方法返回类型 声明类型? 方法名(方法参数类型) 抛出异常?)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;所有的这些都是用来定义执行切入点，即那些方法应该被侯选为切入点：&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;方法访问修饰符   即 public, private 等等&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;方法返回类型       即方法返回的类型，如 void,&lt;br /&gt;String 等等&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;声明类型&lt;br /&gt;1.5的语法，现在可以先忽略它&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;方法名&lt;br /&gt;方法的名字&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;方法参数类型       方法的参数类型&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;抛出异常&lt;br /&gt;方法声明的抛出的异常&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;例如，所有dao代码被定义在包 com.xyz.dao　及子包 com.xyz.dao.hibernate, 或者其它，如果还有的话，子包中,&lt;br /&gt;里面定义的是提供DAO功能的接口或类，那么表达式：&lt;br /&gt;&lt;br /&gt;&lt;pre class="programlisting"&gt;&lt;span style="font-weight: bold;"&gt;execution(* com.xyz.dao..*.*(..))&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;表示切入点为：执行定义在包 com.xyz.dao 及其子包（因为 &lt;span style="font-family:monospace;"&gt;..&lt;br /&gt;&lt;/span&gt;所致) 中的任何方法&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;详细情况可以参见 Spring refernce: &lt;span style="font-weight: bold;"&gt;6.2.3.4.&lt;br /&gt;Examples&lt;/span&gt;&lt;br /&gt;&lt;span class="921372908-18012007"&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;&amp;lt;aop:advisor pointcut="execution(* *..PetStoreFacade.*(..))" advice-ref="txAdvice"/&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;因此这个表达式为执行定义在类 PetStoreFacade　及其实现类中的所有方法，采取的动作定义在 txAdvice 中.&lt;br /&gt;关于该 advice 的定义，（见声&lt;br /&gt;明性事务控制）一节&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;a name="6.2"&gt;&lt;/a&gt;Spring 自定拦截机&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;看来为了进行事务控制，我们只需简单地配置几下，所有的工作都由 Spring&lt;br /&gt;来做。这样固然很好，但有时我们需要有我们特有的控制逻辑。因为Spring&lt;br /&gt;不可能包含所有人需要的所有拦截机。所以它提供了通过程序的方式加以定制的方式。我们的项目中就有这么一个拦截机，在用户确认付款后，将定单信息通过&lt;br /&gt;email 的方式发送给注册用户的邮箱中。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="programlisting"&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-family:monospace;"&gt;&amp;lt;aop:config&amp;gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- &lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:monospace;"&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;当执行 PetStoreFacade.insertOrder方法，&lt;br /&gt;该方法最后一个参数为Order类型时（其实我们的例子中只有一个&lt;br /&gt;insertOrder 方法，但这告诉了我们，当我们的接口或类中有重载了的方法，&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;　　　　　　　&lt;br /&gt;　并且各个重载的方法可能使用不同的拦截机机制时，我们可以通过方法的参数加以指定），&lt;br /&gt;将执行emailAdvice(在最后定义的那个元素）&lt;/span&gt;&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-family:monospace;"&gt;--&amp;gt;&lt;br /&gt;&amp;lt;aop:advisor pointcut="execution(* *..PetStoreFacade.insertOrder(*..Order))"&lt;br /&gt;advice-ref="emailAdvice"/&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/aop:config&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;红色的注释已经说的很清楚这个 Advisor 了，它的切入点(pointcut) 为 PetStoreFacade 的 void&lt;br /&gt;insertOrder(Order order) 方法，采取的动作为引用的 emailAdvice, 下面我们就来看看 emailAdvice:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="programlisting"&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-family:monospace;"&gt; &amp;lt;bean id="emailAdvice"&lt;br /&gt;class="org.springframework.samples.jpetstore.domain.logic.SendOrderConfirmationEmailAdvice"&amp;gt;&lt;br /&gt;&amp;lt;property name="mailSender" ref="mailSender"/&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;它给了这个 advice 的实现类为 logic 包中 SendOrderConfirmationEmailAdvice, 该Bean&lt;br /&gt;引用了我们前面定义的邮件发送器（一个 Spring 内置的邮件发送器）.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;下面看看这个实现类：&lt;br /&gt;&lt;br /&gt;&lt;pre class="programlisting"&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-family:monospace;"&gt;public class SendOrderConfirmationEmailAdvice implements &lt;span style="color: rgb(51, 204, 0);"&gt;AfterReturningAdvice&lt;/span&gt;, &lt;span style="color: rgb(255, 0, 0);"&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;InitializingBean&lt;/span&gt; &lt;/span&gt;{&lt;br /&gt;// user jes on localhost&lt;br /&gt;private static final String DEFAULT_MAIL_FROM = "test@pprun.org";&lt;br /&gt;&lt;br /&gt;private static final String DEFAULT_SUBJECT = "Thank you for your order!";&lt;br /&gt;&lt;br /&gt;private final Log logger = LogFactory.getLog(getClass());&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;private MailSender mailSender;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;private String mailFrom = DEFAULT_MAIL_FROM;&lt;br /&gt;&lt;br /&gt;private String subject = DEFAULT_SUBJECT;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt; public void setMailSender(MailSender mailSender) {&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt; this.mailSender = mailSender;&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt; }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;public void setMailFrom(String mailFrom) {&lt;br /&gt;this.mailFrom = mailFrom;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setSubject(String subject) {&lt;br /&gt;this.subject = subject;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void throws Exception {&lt;br /&gt;if (this.mailSender == null) {&lt;br /&gt;throw new IllegalStateException("mailSender is required");&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span&gt;/**&lt;/span&gt; &lt;span&gt;&lt;br /&gt;* &lt;/span&gt; &lt;span&gt;&lt;br /&gt;* @param returnValue 被拦截的方法的返回值&lt;/span&gt;&lt;br /&gt;* @param m 被拦截的方法的所有信息（Method类封装了这些信息）&lt;/span&gt; &lt;span&gt;&lt;br /&gt;* @param args 被拦截的方法的所有参数组成的数组&lt;/span&gt; &lt;span&gt;&lt;br /&gt;* @param target 目标对象，对于方法执行来说，即是方法所在的类的实例（与 this 同，批当前对象）&lt;/span&gt; &lt;span&gt;&lt;br /&gt;* @throws java.lang.Throwable &lt;/span&gt; &lt;span&gt;&lt;br /&gt;*/&lt;/span&gt;&lt;br /&gt;public void &lt;span&gt;&lt;span&gt;afterReturning&lt;/span&gt;(&lt;/span&gt;Object returnValue, Method m, Object[] args, Object target) throws Throwable {&lt;br /&gt;&lt;span&gt;// 我们被拦截的方法为 void insertOrder(Order order)，方法只有一个参数，所以可知数据的第1个元素即是被传进的　order 对象&lt;br /&gt;// 得到了order 对象，就可以将 order 对应的帐户名及帐单号发送到邮件中，以便确认无误。&lt;br /&gt;&lt;/span&gt; Order order = (Order) args[0];&lt;br /&gt;Account account = ((PetStoreFacade) target).getAccount(&lt;span&gt;order&lt;/span&gt;.getUser().getUsername());&lt;br /&gt;&lt;br /&gt;// don't do anything if email address is not set&lt;br /&gt;if (account.getEmail() == null || account.getEmail().length() == 0) {&lt;br /&gt;return;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;StringBuffer text = new StringBuffer();&lt;br /&gt;text.append("Dear ").append(account.getFirstname()).&lt;br /&gt;append(' ').append(account.getLastname());&lt;br /&gt;text.append(", thank your for your order from JPetStore. " +&lt;br /&gt;"Please note that your order number is ");&lt;br /&gt;text.append(&lt;span style="color: rgb(204, 153, 51);"&gt;order&lt;/span&gt;.getId());&lt;br /&gt;&lt;br /&gt;SimpleMailMessage mailMessage = new SimpleMailMessage();&lt;br /&gt;mailMessage.setTo(account.getEmail());&lt;br /&gt;mailMessage.setFrom(this.mailFrom);&lt;br /&gt;mailMessage.setSubject(this.subject);&lt;br /&gt;mailMessage.setText(text.toString());&lt;br /&gt;try {&lt;br /&gt;this.&lt;span style="color: rgb(255, 0, 0);"&gt;mailSender&lt;/span&gt;.send(mailMessage);&lt;br /&gt;} catch (MailException ex) {&lt;br /&gt;// just log it and go on&lt;br /&gt;logger.warn("An exception occured when trying to send email", ex);&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1. &lt;span style="color: rgb(255, 0, 0);"&gt;红&lt;/span&gt;色的内容即为反向注入的 &lt;span style="color: rgb(255, 0, 0);"&gt;mailSender &lt;/span&gt;属性&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2. &lt;span style="color: rgb(51, 51, 255);"&gt;蓝&lt;/span&gt;色的内容为 Spring Bean&lt;br /&gt;的一个通用的接口 &lt;span style="color: rgb(51, 102, 255);"&gt;InitializingBean &lt;/span&gt;，&lt;br /&gt;实现类需要实现该接口定义的方法 &lt;span style="color: rgb(51, 102, 255);"&gt;afterPropertiesSet()&lt;/span&gt;&lt;br /&gt;，该方法中一般是在Bean 被初始化后并设置了所有的 setter&lt;br /&gt;注入后调用的。所以这里是保证邮件发送器配置正确。因为如果没有配置正确，下面的工作是无法进行的，所以与其等那时抛出异常，还不如早早地在部署时就告知&lt;br /&gt;（通过抛出 IllegalStateException 来提示）&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3. &lt;span style="color: rgb(51, 204, 0);"&gt;绿&lt;/span&gt;色的内容为这个 Advise&lt;br /&gt;的核心，即在切入点被切入后将采用的动作。因为 Advise 也同样有多种类型，比如我们这里的“&lt;span style="font-weight: bold;"&gt;方法正常返回&lt;/span&gt;”，“&lt;span style="font-weight: bold;"&gt;方法执行前&lt;/span&gt;”，“&lt;span style="font-weight: bold;"&gt;方法执行后&lt;/span&gt;”，“&lt;span style="font-weight: bold;"&gt;环绕在方法执行前后&lt;/span&gt;”，“&lt;span style="font-weight: bold;"&gt;方法抛出异常时&lt;/span&gt;”等等(详情参见 Spring Reference:&lt;span style="font-weight: bold;"&gt; 6.2.4. Declaring advice&lt;/span&gt;)。但是我们的逻辑为在用户&lt;br /&gt;确认定单并且执行成功（所谓的成功是指将这一定单插入到了表 Order 中了）后，将发送一确认信。所以”方法正常返回“完全符合我们的要求。&lt;br /&gt;&lt;br /&gt;接口AfterReturningAdvice&lt;br /&gt;即是Spring中表示”方法正常返回“&lt;br /&gt;这一语义的 Advice, 所以我们实现这个接口及其必须的方法 &lt;span&gt;afterReturning.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;方法代码的工作其实并不重要，只要我们理解这些“魔法”一样的技术后，实现代码是很简单的。值得提及的是这个方法的参数，这&lt;br /&gt;些参数是封装了切入点的所有信息，请见上面的&lt;span&gt;注释&lt;/span&gt;。在&lt;br /&gt;我们的实现中只使用了被拦截方法的参数，在复杂的 Advice 实现中可能会用到切入点所有信息。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;&lt;a name="7"&gt;&lt;/a&gt;声明性事务控制&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;由于你们都不熟悉EJB，其实EJB有一个专用名词叫做 CMT (&lt;span style="font-weight: bold;"&gt;C&lt;/span&gt;ontainer&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;M&lt;/span&gt;anagement &lt;span style="font-weight: bold;"&gt;T&lt;/span&gt;ransaction)，它也是在EJB的部署文件中对每个方法声明执行这个&lt;br /&gt;方法是否需要进行事务控制，以及如何控制。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;理解事务处理的概念是掌握任何事务处理框架的的关键，所以我们必须强迫自己尽量理解。Spring 的事务处理框架也不例外，详细情况可以参见&lt;br /&gt;(Spring In Action: 5.3.1&lt;br /&gt;Understanding transaction attributes)：&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Propagation behavior  传播行为&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Isolation level 隔离级别&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Read-only hints 只读提示&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;The transaction timeout period 事务超时周期&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;&lt;a name="7.1"&gt;&lt;/a&gt;事务隔离级别&lt;/h3&gt;&lt;br /&gt;由于事务隔离级别的概念相对简单些，所以我们首先看看事务隔离级别&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;打开 java.sql.Connection类的 doc&lt;br /&gt;(jdk-1_5_0-doc/docs/api/java/sql/Connection.html)，我们可以看到其声明了五个事务隔离极别常量成&lt;br /&gt;员：&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;TRANSACTION_NONE &lt;/span&gt;&lt;br /&gt;A constant indicating that transactions are not&lt;br /&gt;supported.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;TRANSACTION_READ_UNCOMMITTED&lt;/span&gt;&lt;br /&gt;A constant indicating that dirty reads, non-repeatable reads and&lt;br /&gt;phantom reads can occur. This level allows a row changed by one&lt;br /&gt;transaction to be read by another transaction before any changes in&lt;br /&gt;that row have been committed (a "dirty read"). If any of the changes&lt;br /&gt;are rolled back, the second transaction will have retrieved an invalid&lt;br /&gt;row.()&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;TRANSACTION_READ_COMMITTED&lt;/span&gt;&lt;br /&gt;A constant indicating that dirty reads are prevented; non-repeatable&lt;br /&gt;reads and phantom reads can occur. This level only prohibits a&lt;br /&gt;transaction from reading a row with uncommitted changes in it.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;TRANSACTION_REPEATABLE_READ&lt;/span&gt;&lt;br /&gt;A constant indicating that dirty reads and non-repeatable reads are&lt;br /&gt;prevented; phantom reads can occur. This level prohibits a transaction&lt;br /&gt;from reading a row with uncommitted changes in it, and it also&lt;br /&gt;prohibits the situation where one transaction reads a row, a second&lt;br /&gt;transaction alters the row, and the first transaction rereads the row,&lt;br /&gt;getting different values the second time (a "non-repeatable read").&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;TRANSACTION_SERIALIZABLE&lt;/span&gt;&lt;br /&gt;A constant indicating that dirty reads, non-repeatable reads and&lt;br /&gt;phantom reads are prevented. This level includes the prohibitions in&lt;br /&gt;TRANSACTION_REPEATABLE_READ and further prohibits the situation where&lt;br /&gt;one transaction reads all rows that satisfy a WHERE condition, a second&lt;br /&gt;transaction inserts a row that satisfies that WHERE condition, and the&lt;br /&gt;first transaction rereads for the same condition, retrieving the&lt;br /&gt;additional "phantom" row in the second read.&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;以下是我对这几个隔离极别的翻译：(我想如果是四年制本科的软件专业，在数据库课程中应该会接触到这些内容)&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;TRANSACTION_NONE &lt;/span&gt;&lt;br /&gt;没有事务支持，不可能用在真正的应用中&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;TRANSACTION_READ_UNCOMMITTED&lt;/span&gt;&lt;br /&gt;允许“脏”读，不可再现重读和影子读：具体表现为，允许数据库的一行由一个事务单元A进行改变的同时，允许由另一个事务单元B读取这个被事务A改变后的同&lt;br /&gt;一行，而此时事务A还没提交它的改变，因为数据正处在改变状态还未将改变提交到数据库中（术语“脏”的来历），如果事务后来又回滚了它的改变，那么事务B&lt;br /&gt;读取的信息将是无效的，而这无效只有等到事务B提交时才能察觉到（以失败告终）。此极别提高了事务的并发性，但同时导致了无效的读增多。此方案在只读事务&lt;br /&gt;单元时有用&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;TRANSACTION_READ_COMMITTED&lt;/span&gt;&lt;br /&gt;此级别不允许“脏读”，但未可再现重读和影子读还是允许的，此级别阻止了读取未提交的改变。&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;TRANSACTION_REPEATABLE_READ&lt;/span&gt;&lt;br /&gt;此级别不允许“脏读”，也不允许不可再现的重读，但影子读还是允许的。所谓的“不可再现的重读”为：一个事务单元A读取一行，紧接着第二个事务单元B改变&lt;br /&gt;了这行，但未提交更改，事务单元A再接接着读取这行，如果允许事务单元A两次读取的内容不同，则叫做不可再现的重读，如果数据库保证了了两次读取的内容必&lt;br /&gt;须相同，则为可再现重读。&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;TRANSACTION_SERIALIZABLE&lt;/span&gt;&lt;br /&gt;此级别指示“脏读”，不可再现重读及影子读都被禁止。本级别除了 TRANSACTION_REPEATABLE_READ&lt;br /&gt;中的限制之外，还得满足未影子读。所谓影子读为：如果一个事务单元A通过 Where&lt;br /&gt;条件限制了取回的结果集，而第二事务单元B插入了一行且这行满足Where&lt;br /&gt;条件，但未提交更改，当事务单元A再次通过同样的条件进行查询时，如果可以获得刚刚由事务单元B插入的记录，则表示影子读，如果不可能获得则叫禁止影子读&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;h3&gt;&lt;a name="7.2"&gt;&lt;/a&gt;事务传播行为&lt;/h3&gt;&lt;a href="http://www.blogger.com/Hibernate%20Jpetstore%20%D6%AE%C8%FD%20%BF%D8%D6%C6%B2%E3%C9%E8%BC%C6.html#1"&gt;&lt;small&gt;&lt;/small&gt;&lt;/a&gt;&lt;br /&gt;除了上面我们已经介绍了的隔离级别，另一个重要的概念则是事务传播行为(Propagation behavior)：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Spring In Action:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt; Table 5.2 Spring’s&lt;br /&gt;transactional propagation rules&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;PROPAGATION_MANDATORY&lt;/span&gt;&lt;br /&gt;Indicates that the method must run within a transaction. If no existing&lt;br /&gt;transaction is in progress, an exception will be thrown.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;PROPAGATION_NESTED&lt;/span&gt;&lt;br /&gt;Indicates that the method should be run within a nested&lt;br /&gt;transaction if an existing transaction is in progress. The nested&lt;br /&gt;transaction can be committed and rolled back individually from the&lt;br /&gt;enclosing transaction. If no enclosing transaction exists, behaves like&lt;br /&gt;PROPAGATION_REQUIRED. Beware that vendor support for this propagation&lt;br /&gt;behavior is spotty at best. Consult the documentation for your resource&lt;br /&gt;manager to determine if nested transactions are supported.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;PROPAGATION_NEVER&lt;/span&gt;&lt;br /&gt;Indicates that the current method should not run within a transactional&lt;br /&gt;context. If there is an existing transaction in progress, an exception&lt;br /&gt;will be thrown. &lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;PROPAGATION_NOT_SUPPORTED&lt;/span&gt;&lt;br /&gt;Indicates that the method should not run within a transaction. If an&lt;br /&gt;existing transaction is in progress, it will be suspended for the&lt;br /&gt;duration of the method. If using JTATransactionManager, access to&lt;br /&gt;TransactionManager is required.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;PROPAGATION_REQUIRED&lt;br /&gt;&lt;/span&gt;Indicates that the current method must run within a&lt;br /&gt;transaction. If an existing transaction is in progress, the method will&lt;br /&gt;run within that transaction. Otherwise, a new transaction will be&lt;br /&gt;started.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;PROPAGATION_REQUIRES_NEW&lt;/span&gt;&lt;br /&gt;Indicates that the current method must run within its own transaction.&lt;br /&gt;A new transaction is started and if an existing transaction is in&lt;br /&gt;progress, it will be suspended for the duration of the method. If using&lt;br /&gt;JTATransactionManager, access to Transaction-Manager is required.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;PROPAGATION_SUPPORTS&lt;/span&gt;&lt;br /&gt;Indicates that the current method does not require a transactional&lt;br /&gt;context, but may run within a transaction if one is already in progress.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;PROPAGATION_MANDATORY&lt;/span&gt;&lt;br /&gt;指示方法执行必须具有事务支持，否则异常将会抛出。&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;PROPAGATION_NESTED&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;指示如果当前已经存在一个事务，该方法将在自己的事务单元中执行，但该事务单元将嵌套在已存在的事务单元之中，而且这个事务单元可单独于外包的事务单元进&lt;br /&gt;行提交、回滚。如果没有事务单元存在，它的行为与PROPAGATION_REQUIRED一样，一个新的事务单元将被初始化出来。但是每个数据库厂间对&lt;br /&gt;这个传播行为的支持不大一样。请留意。&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;PROPAGATION_NEVER&lt;/span&gt;&lt;br /&gt;指示方法不应运行在一个事务单元中，如果已经有一个事务单元存在了，将抛出异常。 &lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;PROPAGATION_NOT_SUPPORTED&lt;/span&gt;&lt;br /&gt;指示方法不应运行在一个事务单元中，但如果已经存了一个事务单元，在方法的执行过程中将会将事务功能挂起。&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;PROPAGATION_REQUIRED&lt;br /&gt;&lt;/span&gt;指示方法必须运行在事务单元中，如果已经存了一个事务单元，则方法将合并到该事务单元中去，如果没有存在的事务单元，则将创建出一&lt;br /&gt;个新的事务单元。&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;PROPAGATION_REQUIRES_NEW&lt;/span&gt;&lt;br /&gt;指示此方法必须运行在自己的事务单元中，如果一个事务单元已经存在的话，一个新的事务单元将创建且原先存在的事务单元在这个方法的执行其间将被挂起。&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;PROPAGATION_SUPPORTS&lt;/span&gt;&lt;br /&gt;指示方法不必一定要运行在事务单元中，但是如果有已经存在的事务单元的话，它也乐意在事务单元中运行。&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;h3&gt;&lt;a name="7.3"&gt;&lt;/a&gt;只读提示&lt;/h3&gt;&lt;div style="text-align: right;"&gt;&lt;a href="http://www.blogger.com/Hibernate%20Jpetstore%20%D6%AE%C8%FD%20%BF%D8%D6%C6%B2%E3%C9%E8%BC%C6.html#1"&gt;&lt;small&gt;&lt;/small&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;此属性只对 PROPAGATION_REQUIRED, PROPAGATION_REQUIRES_NEW, and&lt;br /&gt;PROPAGATION_NESTED　传播行为有意义，因为对于其它没有事务单元的传播行为是没有必要的。&lt;br /&gt;&lt;br /&gt;只读提示给予数据库有机会作出更大胆的优化。&lt;br /&gt;&lt;br /&gt;如果是使用 Hinbernate 作为 O/R maping 的话，Hibernate 可以使用 FLUSH_NEVER&lt;br /&gt;模式避免不必要的数据同步消耗，因为是吹读，数据同步是根本没有必要的。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;a name="7.4"&gt;&lt;/a&gt;事务超时周期&lt;/h3&gt;&lt;a href="http://www.blogger.com/Hibernate%20Jpetstore%20%D6%AE%C8%FD%20%BF%D8%D6%C6%B2%E3%C9%E8%BC%C6.html#1"&gt;&lt;small&gt;&lt;/small&gt;&lt;/a&gt;&lt;div style="text-align: right;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;对于长时间运行的事务操作，我们必需估计操作的最坏情形（也就可能的最大运行时间），由于事务会大量使用数据库锁，将相关的数据库列，或数据库行或整个表&lt;br /&gt;锁住。长时间的锁将会使数据库长时间不可用。因此我们必须估计最坏的情形。通过设置超时时间，超过了这个时间，整个事务会回滚。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;ORACLE Tip:&lt;br /&gt;&lt;/span&gt;&lt;span style="font-style: italic;"&gt;Read-only connections are supported by the Oracle server, but not by the Oracle JDBC drivers. For transactions, the Oracle server supports only the TRANSACTION_READ_COMMITTED and TRANSACTION_SERIALIZABLE transaction isolation levels.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;The default is TRANSACTION_READ_COMMITTED.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;只读模式只针对服务器端，JDBC 驱动不支持。&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;ORACLE只支持两种事务隔离级别：TRANSACTION_READ_COMMITTED 和 TRANSACTION_SERIALIZABLE, 默认的是 TRANSACTION_READ_COMMITTED&lt;/span&gt;&lt;code style="font-style: italic;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;弄懂了上面这些重要的概念后，看 Spring 对事务的配置是相当的简单了：&lt;br /&gt;&lt;br /&gt;&lt;span class="921372908-18012007"&gt;&lt;br /&gt;&lt;pre&gt; &amp;lt;!--&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;事务方针声明，用于控制采用&lt;big style="font-weight: bold;"&gt;&lt;big&gt;什么样&lt;/big&gt;&lt;/big&gt;的事务策略&lt;/span&gt;&lt;&gt; Transaction advice definition, based on method name patterns.&lt;br /&gt;Defaults to PROPAGATION_REQUIRED for all methods whose name starts with&lt;br /&gt;"insert" or "update", and to PROPAGATION_REQUIRED with read-only hint&lt;br /&gt;for all other methods.&lt;br /&gt;--&amp;gt;&lt;br /&gt;&amp;lt;tx:advice id="txAdvice"&amp;gt;&lt;br /&gt;&amp;lt;tx:attributes&amp;gt;&lt;br /&gt;&amp;lt;tx:method name="insert*"/&amp;gt;&lt;br /&gt;&amp;lt;tx:method name="update*"/&amp;gt;&lt;br /&gt;&amp;lt;tx:method name="*" read-only="true"/&amp;gt;&lt;br /&gt;&amp;lt;/tx:attributes&amp;gt;&lt;br /&gt;&amp;lt;/tx:advice&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;1. 首先定义了 Advice ，该 advice 被 AOP事务 拦截机引用了&lt;br /&gt;&lt;br /&gt;2. 事务的属性，依次列出了每个方法的前缀，如 insert* 则会匹配PetStoreFacade中的 void&lt;br /&gt;insertAccount(Account account);  void insertOrder(Order order);，而&lt;br /&gt;update* 则会匹配 void updateAccount(Account account); ，其它的（"*") 都只是&lt;br /&gt;get/search/select, 即是只读查询了，所以了指定了 read-only="true" 属性.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;你可能会问，上面谈了半天的 isolation level 及 propagation behavior, 怎么这里根本没有出现。其实是&lt;br /&gt;Spring 使用了默认的值：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;如果没有指定隔离级别，ISOLATION_DEFAULT 将被默认指定&lt;br /&gt;&lt;br /&gt;如果没有指定事务传播行为，PROPAGATION_REQUIRED　将被指定&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;所以上面的声明与下面的的一样的：&lt;br /&gt;&lt;br /&gt;&lt;span class="921372908-18012007"&gt;&lt;br /&gt;&lt;pre&gt; &amp;lt;tx:advice id="txAdvice"&amp;gt;&lt;br /&gt;&amp;lt;tx:attributes&amp;gt;&lt;br /&gt;&amp;lt;tx:method name="insert*" PROPAGATION_REQUIRED ISOLATION_DEFAULT /&amp;gt;&lt;br /&gt;&amp;lt;tx:method name="update*" PROPAGATION_REQUIRED ISOLATION_DEFAULT /&amp;gt;&lt;br /&gt;&amp;lt;tx:method name="*" PROPAGATION_REQUIRED ISOLATION_DEFAULT read-only="true" /&amp;gt;&lt;br /&gt;&amp;lt;/tx:attributes&amp;gt;&lt;br /&gt;&amp;lt;/tx:advice&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;即：&lt;br /&gt;&lt;br /&gt;1. 所有以 insert 开头的方法都需要事务处理 (PROPAGATION_REQUIRED）而隔离级别采用底层数据为默认的级别&lt;br /&gt;&lt;br /&gt;2. 所有以 update 开头的方法与 insert 相同&lt;br /&gt;&lt;br /&gt;3. 其它方法除与上面的事务属性相同外，且为 read-only&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;&lt;a name="8"&gt;&lt;/a&gt;Actions 及 struts-config.xml&lt;br /&gt;&lt;br /&gt;&lt;/h2&gt;Action 是Struts 的核心，是控制层组件的关键，是通往业务层/ DAO的层的途径。在页面上，每一个按钮，超链接都有相应的&lt;br /&gt;Action　来表示，因为每个这种页面元素都是用来做一点事情的。比如：提交一张用户信息表单；执行一段服务器的代码，比如，按下搜索按钮，将从数据库&lt;br /&gt;中查出满足条件的产品记录。&lt;br /&gt;&lt;br /&gt;每个Action 都应当从 Struts 的 org.apache.struts.action.Action 类派生下来，并&lt;br /&gt;overriding 其中的一个 execute() 方法，所有的动作（按下按钮或点击链接后的动作）都应当在这个方法中完成。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;我们这里不可能把所有的 Action 都列出来，所以只挑几个有代表的来作介绍，最主要是理解 Struts&lt;br /&gt;框架的机理，怎么使各个部分有机的组织在一起，达到简化开发步骤的目的。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;a name="8.1"&gt;&lt;/a&gt;BaseAction&lt;/h3&gt;&lt;div style="text-align: right;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;我们已经在前面的系列中详细讲过这个类，如果不记得它做了什么，回头看看源码，如果还不十分清楚，可以再回头看看前面的系列。这个 Action&lt;br /&gt;是我们所有真正工作的（带有 execute()方法的) Action的超类，所以这里不打算重复了。不过，值得借鉴的是，如果所有的 Action&lt;br /&gt;中都有的东西，都可以提到这个超类当中来。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;a name="8.2"&gt;&lt;/a&gt;DoNothingAction&lt;/h3&gt;&lt;a href="http://www.blogger.com/Hibernate%20Jpetstore%20%D6%AE%C8%FD%20%BF%D8%D6%C6%B2%E3%C9%E8%BC%C6.html#1"&gt;&lt;small&gt;&lt;/small&gt;&lt;/a&gt;&lt;br /&gt;对于有些 Action,&lt;br /&gt;它其实并没涉及到商业逻辑，只是从一个页面跳到另一个页面，因为甚至连校验用户这个功能都不需要（这是可能的，当你进入china-pub&lt;br /&gt;时，在没有注册的情况下是完全可以浏览图书的）。所以存在一个与商业逻辑无关的 Action, 即 DoNothingAction,&lt;br /&gt;我们看看它的代码：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="921372908-18012007"&gt;&lt;br /&gt;&lt;pre&gt;public class DoNothingAction extends BaseAction {&lt;br /&gt;&lt;br /&gt;/* Public Methods */&lt;br /&gt;&lt;br /&gt;public ActionForward execute(ActionMapping mapping, ActionForm form,&lt;br /&gt;HttpServletRequest request, HttpServletResponse response) throws Exception {&lt;br /&gt;// 是否是从 Spring web 跳过来的&lt;br /&gt;if (request.getParameter("invalidate") != null&lt;br /&gt;&amp;amp;&amp;amp; request.getParameter("invalidate").toString().equals("true")) {&lt;br /&gt;// 如果是，无效 session&lt;br /&gt;request.getSession().invalidate();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;return mapping.findForward("success");&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;其中，真正的代码就这一行：return mapping.findForward("success");&lt;br /&gt;&lt;br /&gt;其它的是因为我们工程是有两套WEB框架来演示的（一个是 Struts , 一个是 SpringMVC),&lt;br /&gt;所以这里判断是否是从另一种实现中跳过来的，如果是的话，先将目前 session&lt;br /&gt;中的对象无效，比如：已经登录的用户，已经放入到购物车的东西。因为从一种框架跳到另一种框架（在页面的最下面），后台的实现是一样的，只是WEB层东西&lt;br /&gt;不一样，但为了演示的框架的整个生命周期，所以从一个实现跳到一种实现都会“从头再来”。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;所以这个Action 所要进行的动作就是，找到你该去的地方（success)，如果不出意外的话，跳过去吧。在&lt;br /&gt;struts-config.xml 文件中搜索（Ctrl-f) "DoNothingAction"，我们发现三个地方引用了该类&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="921372908-18012007"&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;!-- 无论何时，要去首面时 --&amp;gt;&lt;br /&gt;&amp;lt;action path="/shop/index" type="org.springframework.samples.jpetstore.web.struts.DoNothingAction"&lt;br /&gt;validate="false"&amp;gt;&lt;br /&gt;&amp;lt;forward name="success" path="/WEB-INF/jsp/struts/index.jsp"/&amp;gt;&lt;br /&gt;&amp;lt;/action&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;&amp;lt;!-- 点击帮助链接时 --&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;lt;action path="/shop/help" type="org.springframework.samples.jpetstore.web.struts.DoNothingAction"&lt;br /&gt;validate="false"&amp;gt;&lt;br /&gt;&amp;lt;forward name="success" path="/WEB-INF/jsp/struts/help.jsp"/&amp;gt;&lt;br /&gt;&amp;lt;/action&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;&amp;lt;!-- 点击注册按钮，进入注册页面 --&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;lt;action path="/shop/signonForm" type="org.springframework.samples.jpetstore.web.struts.DoNothingAction"&lt;br /&gt;validate="false"&amp;gt;&lt;br /&gt;&amp;lt;forward name="success" path="/WEB-INF/jsp/struts/SignonForm.jsp"/&amp;gt;&lt;br /&gt;&amp;lt;/action&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;a name="8.3"&gt;&lt;/a&gt;ActionForm &amp;lt;-- struts-config.xml --&amp;gt; Action&lt;/h3&gt;&lt;br /&gt;struts-config.xml 文件是Struts 框架将各部分有机地组织在一起的关键，可以打开 struts-config.xml&lt;br /&gt;文件看看：&lt;br /&gt;&lt;br /&gt;1. 它声明了所有的 form-bean (即每个输入表单对就的 Java 对象，用来收集用户提交的输入信息），这些 bean 将被&lt;br /&gt;&amp;lt;action-mappings&amp;gt; 中的 &amp;lt;action&amp;gt; 的 name 属性引用&lt;br /&gt;&lt;br /&gt;2. 它指定了全局跳转 (global forward),  可以在Action 的 execute()&lt;br /&gt;方法中引用，如：mapping.findForward("failure");&lt;br /&gt;&lt;br /&gt;3. 它指定了所有的 action-mapping, 从这个 mapping 集合就可知整个应用的来龙去脉，如：&lt;br /&gt;&lt;br /&gt;&lt;span class="921372908-18012007"&gt;&lt;br /&gt;&lt;pre&gt; &amp;lt;action path="/shop/editAccount"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.EditAccountAction"&lt;br /&gt;name="workingAccountForm" scope="session" validate="true"&lt;br /&gt;input="/WEB-INF/jsp/struts/EditAccountForm.jsp"&amp;gt;&lt;br /&gt;&amp;lt;forward name="success" path="/shop/index.do"/&amp;gt;&lt;br /&gt;&amp;lt;/action&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;1. path=&lt;span style="font-weight: bold;"&gt;/shop/editAccount&lt;/span&gt;&lt;br /&gt;所有要去住 /shop/editAccount （严格地讲，如果按照Struts 的方言是 /shop/editAccount.do)&lt;br /&gt;的请求，都要遵循这里的配置&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2. &lt;span style="font-weight: bold;"&gt;name="workingAccountForm"&lt;/span&gt;&lt;br /&gt;都将绑定 workingAccountForm ，注意 form-bean 在 Action 中引用是通过 name&lt;br /&gt;属性来引用的，它是在一开始定义的: &amp;lt;form-bean name="workingAccountForm"&lt;br /&gt;type="org.springframework.samples.jpetstore.web.struts.AccountActionForm"/&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3. &lt;span style="font-weight: bold;"&gt;scope="session"&lt;/span&gt; 该 bean&lt;br /&gt;将在整个会话其间始终有效 ，但注意这个配置是多余的，默认就是 session 上下文的，反而如果 bean 只在 request&lt;br /&gt;文时，才需要明确地声明。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;4. validate="true" 将对表单的输入调用 form-bean 的 validate 方法。但我们发现在&lt;br /&gt;AccountActionForm.java 中，只有 doValidate(...) 方法，并没有&lt;br /&gt;validate()方法，但细心的话，应该发现了，和所有的Action 都是从BaseAction 中派生而来一样，所有的&lt;br /&gt;ActionForm 中都是从一个基类 BaseActionForm.java 中派生下来。其中定义了所有 formbean&lt;br /&gt;都需要的东西，对于校验错误的处理。其中就是 validate(...) 方法，并在其中调用了 doValidate() 方法，而每个&lt;br /&gt;BaseActionForm 的子类只要override 这个 doValidate() 方法，如果 validate="true"&lt;br /&gt;声明了的话，那么子类中的 doValidate() 方法将会被调用。这是多态性的表现。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;5. input="..."  一般来讲，一个表单在校验失败后都需要回去重纠正错误的输出项，所以我们通过这个值来告诉 Struts&lt;br /&gt;该回到哪去纠错&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;a name="8.4"&gt;&lt;/a&gt;SecureBaseAction&lt;/h3&gt;SecureBaseAction 是一个抽象类，但它也是从BaseAction 派生过来的，它的目的在执行 execute 方法之前首先要经过&lt;span style="font-weight: bold;"&gt;是否登录&lt;/span&gt;检查，如果没有则跳到登录页面，并将当前要去往的页面记下来，等登录完&lt;br /&gt;后，再跳转过去。（而不象有些菜鸟做的，我本来选择了去下载页面，但它首先要我登录，而登录后却把我带到了首页，而不是我要去的下载页面。注意在&lt;br /&gt;execute() 方法中调用用的是抽象方法 doExecute(...) ，这个抽象方法是等待此类的子类来实现的。这也是多态性的表现。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;&lt;a name="9"&gt;&lt;/a&gt;DAO接口设计及Hibernate DAO 实现&lt;/h2&gt;&lt;br /&gt;设计方式有好多种，有些是从自底向上设计，有些叫做自顶向下设计。对于 J2EE 的项目自底向上设计会好些。&lt;br /&gt;&lt;br /&gt;对于DAO的设计，一般来说，每个DAO都会包含所有的 CRUD(Create, Retrieve, Update,&lt;br /&gt;Delete)，而不管顶层，即表示层目前是否会全用到这些功能。因为这些基本功能是组成更复杂数据操作的基础，况且目前虽然没有用到，但说不定随着产品&lt;br /&gt;的演化，下一版本就会用到。况且实现这些 CRUD并不那么困难。但是我们的项目好象偷了懒，只是定义出上层需要的所有方法。这对于演示项目也无可厚非。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;除了基本的CRUD，一般为了适应上层的需求，都需要提取出相应的方法来满足需求的动词。如：列出满足条件的所有产品，那么在 ProductDao&lt;br /&gt;中则有：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="921372908-18012007"&gt;&lt;br /&gt;&lt;pre&gt;List searchProductList(String keywords) throws DataAccessException;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;我们不把主要精力放在DAO接口的设计上，因为这主要是设计师的责任（或许对于小公司而言，也是程序员的责任，如果是这样的话，一定要抓住机会！）。我们&lt;br /&gt;主要看看基于 Spring 的 HibernateSupport 的 Dao 的实现。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;如果了解SQL语言，其实是很简单的，但如果不了解的话，别无选择，至少得读一本SQL方面的书，如果想成为一名开发者的话，当然在第一份工作时可以不必&lt;br /&gt;担心，如果你敢于冒险的话！是不是，良子？&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;摘自HibernateCategoryDao.java&lt;br /&gt;&lt;br /&gt;&lt;span class="921372908-18012007"&gt;&lt;br /&gt;&lt;pre&gt;public class HibernateCategoryDao extends &lt;span style="color: rgb(51, 102, 255);"&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;HibernateDaoSupport&lt;/span&gt; &lt;/span&gt;implements CategoryDao {&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;public List getCategoryList() throws DataAccessException {&lt;br /&gt;// todo: now not retrive id&lt;br /&gt;return &lt;span style="color: rgb(51, 51, 255);"&gt;getHibernateTemplate().find&lt;/span&gt;(&lt;br /&gt;"&lt;span style="color: rgb(255, 0, 0);"&gt;from Category&lt;/span&gt;");&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* todo: pp, renamed categoryId to categoryName&lt;br /&gt;*/&lt;br /&gt;public Category getCategory(String categoryName) throws DataAccessException {&lt;br /&gt;Category category = null;&lt;br /&gt;&lt;br /&gt;List ls = &lt;span style="color: rgb(51, 51, 255);"&gt;getHibernateTemplate().find&lt;/span&gt;(&lt;br /&gt;"&lt;span style="color: rgb(255, 0, 0);"&gt;from Category cat where cat.categoryName = ?", categoryName&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;if (ls != null &amp;amp;&amp;amp; ls.size() &amp;gt; 0) {&lt;br /&gt;category = (Category) ls.get(0);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;return category;&lt;br /&gt;}&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;蓝&lt;/span&gt;色的是调用的 Spring 的&lt;br /&gt;HibernateDaoSupport 的api&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;红&lt;/span&gt;色的则是 HQL (&lt;span style="font-weight: bold;"&gt;H&lt;/span&gt;ibernate &lt;span style="font-weight: bold;"&gt;Q&lt;/span&gt;uery &lt;span style="font-weight: bold;"&gt;L&lt;/span&gt;anguage) , SQL 的变体&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1. 要从表 Category 选出所有记录，&lt;span style="font-family:monospace;"&gt;form&lt;br /&gt;Category&lt;/span&gt; 就这么简单，其相当于 &lt;span style="font-family:monospace;"&gt;select&lt;br /&gt;* from category&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2. 如果要设置查询条件，就象第二个方法中那样做。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3. 如果 api 返回的是一个结果集，那么它即是 List, 有了这个结果集，我们就可以用我们已熟悉的方式处理它了。JSTL&lt;br /&gt;的for-each，普通的iterator 随你怎么用。值得一提的是，Spring 内置支持简单的分页功能。在我们的好几个 Action&lt;br /&gt;都用到了。如：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;分页显示产品项列表，每页显示4项：&lt;br /&gt;&lt;br /&gt;&lt;span class="921372908-18012007"&gt;&lt;br /&gt;&lt;pre&gt; PagedListHolder itemList = new PagedListHolder(getPetStore().&lt;br /&gt;getItemListByProduct(productNumber));&lt;br /&gt;itemList.setPageSize(4);&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;4. 如果我不想返回表的所有列，那么就明确地写 select 子句（前我们都省去了它）&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;摘自 HibernateProductDao.java&lt;br /&gt;&lt;br /&gt;&lt;span class="921372908-18012007"&gt;&lt;br /&gt;&lt;pre&gt;getHibernateTemplate().find(&lt;br /&gt;"&lt;span style="color: rgb(255, 0, 0);"&gt;select p , c.categoryName&lt;/span&gt; " +&lt;br /&gt;"from Product p, Category c " +&lt;br /&gt;"where c.id = &lt;span style="color: rgb(0, 102, 0);"&gt;p.category.id&lt;/span&gt; and p.productNumber = ?", productNumber);&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;值得提及的是，我们看到（绿色的字）我们可以级联导航（多层访问，通过点"."),  p.category.id&lt;br /&gt;其实是从Product表导航到了Category 表，再访问 id 列的。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;上面我们看到的都是查询，我们看看其它操作：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;5. 插入&lt;br /&gt;&lt;br /&gt;摘自HibernateOrderDao.java&lt;br /&gt;&lt;br /&gt;&lt;span class="921372908-18012007"&gt;&lt;br /&gt;&lt;pre&gt;getHibernateTemplate().persist(order);&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;如果映射一切正常，在这个购物单上的所有项（LineItem）都将被持久化。还记得 cascade="save-update"&lt;br /&gt;吗？我们花那么大力气，为得就是此时的这么简单。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;6. 更新&lt;br /&gt;&lt;br /&gt;摘自　HibernateAccountDao.java&lt;br /&gt;&lt;br /&gt;&lt;span class="921372908-18012007"&gt;&lt;br /&gt;&lt;pre&gt;getHibernateTemplate().update(account, LockMode.UPGRADE);&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;7. 删除&lt;br /&gt;&lt;br /&gt;虽然我们的代码中没有删除功能，但正如你猜到的，如下：&lt;br /&gt;&lt;br /&gt;&lt;span class="921372908-18012007"&gt;&lt;br /&gt;&lt;pre&gt;getHibernateTemplate().delete(abcObject);&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;8. 在IDE中，将鼠标指针放在 &lt;span style="font-family:monospace;"&gt;getHibernateTemplate().&lt;br /&gt;&lt;/span&gt;激活自动完成，看到的方法应该可以完成大部分普通的数据操作，如果你能用SQL轻松实现的话，应该就会在这里找到对应的方法。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;最后，你可能会问，我们映射了那么多 domain 对象，为什么这时只有五个DAO呢？&lt;br /&gt;&lt;br /&gt;我们没有必要对每个 domain&lt;br /&gt;对象都提供一个DAO的，特别是在关系建立的比较好的数据库时。因关系的存在，再加映射正确地建立起来了，从一个表导航到另一个表，此时只在 java&lt;br /&gt;代码或 HQL 中表现出来：&lt;br /&gt;&lt;br /&gt;&lt;span class="921372908-18012007"&gt;&lt;br /&gt;&lt;pre&gt;getHibernateTemplate().find(&lt;br /&gt;"select inv.quantity from &lt;span style="color: rgb(204, 0, 0);"&gt;Inventory inv&lt;/span&gt; where " +&lt;br /&gt;"inv.item.itemName = ?", itemName);&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;虽然此语句在 HibernateItemDAO 中，但是它用到了 Item 与 Inventory 之间的关系。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;一般按照这个法则，domain 是细粒度的对象 &amp;lt;  Dao 是中等粒度的对象  &amp;lt; Facade&lt;br /&gt;门面是粗粒度的对象&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;&lt;a name="10"&gt;&lt;/a&gt;总结&lt;/h2&gt;&lt;a href="http://www.blogger.com/Hibernate%20Jpetstore%20%D6%AE%C8%FD%20%BF%D8%D6%C6%B2%E3%C9%E8%BC%C6.html#1"&gt;&lt;small&gt;&lt;/small&gt;&lt;/a&gt;&lt;br /&gt;控制层技术或框架本身就是为了简化开发而开发的，所以它不可能太复杂的。&lt;br /&gt;&lt;br /&gt;只要弄懂了框架的来龙去脉，写应用就不会偏离主心。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-4330826481913649418?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/4330826481913649418/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=4330826481913649418' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/4330826481913649418'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/4330826481913649418'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2007/05/hibernate-jpetstore_31.html' title='Hibernate JPetstore 系列之三: 控制层技术'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-3728988415692991792</id><published>2006-08-01T12:48:00.000+08:00</published><updated>2007-05-12T21:47:42.490+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate'/><title type='text'>Hibernate Jpetstore 之二 数据层技术</title><content type='html'>&lt;h2&gt;文档内容&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;概览&lt;/li&gt;  &lt;ul&gt;&lt;li&gt;面象对象与结构化的错配&lt;/li&gt;       &lt;li&gt;Java 代码：面向对象的表示&lt;/li&gt;       &lt;li&gt;数据库表：结构化的数据表示&lt;/li&gt; &lt;/ul&gt;&lt;br /&gt;&lt;li&gt;DAO调用序列图&lt;/li&gt; &lt;li&gt;Strtus &amp;lt;-- Spring --&amp;gt; DAO (Spring 作为 DAO 与Struts 的桥梁)&lt;/li&gt; &lt;li&gt;实体关系图&lt;/li&gt; &lt;li&gt;实体关系映射(O/R Mapping)&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Java代码中的关系表示&lt;/li&gt;    &lt;ul&gt;&lt;li&gt;单向关系&lt;/li&gt;      &lt;li&gt;双向关系&lt;br /&gt;&lt;/li&gt;   &lt;/ul&gt;  &lt;/ul&gt;  &lt;ul&gt;&lt;li&gt;Hibernate 的关系表示&lt;/li&gt;&lt;ul&gt;&lt;li&gt;account - category&lt;/li&gt;      &lt;li&gt;account - order&lt;/li&gt;   &lt;/ul&gt;   &lt;li&gt;主键映射&lt;/li&gt;   &lt;li&gt;其他映射&lt;/li&gt;   &lt;li&gt;二级缓存映射&lt;br /&gt;&lt;/li&gt;  &lt;/ul&gt;  &lt;ul&gt;&lt;li&gt;Hibernate 配置文件&lt;/li&gt;   &lt;li&gt;Ehcache&lt;/li&gt;  &lt;/ul&gt;&lt;br /&gt;&lt;li&gt;总结&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;在阅读本篇文章之前，请先仔细阅读 Hibernate Jpetstore之一：数据层　的相关内容。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;此篇文章中或多或少会重复一些系列之一的相关内容，放在这里以达到理解的连续性。&lt;br /&gt;再有，在讨论时，我不时地会“跑题”，这也是为了将大量的信息转达出来，因为象这种书面形式的机会实在难得。&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;h2&gt;概览&lt;/h2&gt;&lt;br /&gt;一般来说，数据层设计的好坏直接关系到整个系统的成败。在关系数据库占工业主导地位的今天，不论采用何种数据层技术，必然牵涉到数据库表，以及表与表之间&lt;br /&gt;的关系。值得注意的是，我们面对的项目需求文档，我们的工作（至少是设计者的工作）是从文档中找到“有意义”的名词，对于面向对象的设计方法来说，就是把&lt;br /&gt;这些名词表示为对象；（文档中与该名词有关的约束，则作为对象的属性，而与之相关的动词就是该对象的行为，即函数或方法）&lt;br /&gt;&lt;br /&gt;你可能会问，我们是在谈数据层技术，怎么突然转到了面向对象的概念了？&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;是的，在面向对象编程语言占主导地位，而数据管理与存储技术（即数据库）仍处在“结构化”的今天，我不得不寻求一种折衷的方案，来将&lt;span style="font-weight: bold;"&gt;程序的面向对象化&lt;/span&gt;与&lt;span style="font-weight: bold;"&gt;数&lt;br /&gt;据的结构化&lt;/span&gt;间的“错配”的影响减到最小。Hibernate 即是这一方案中的先行者。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;前面这个回答虽然简单地道出了问题的所在，并以 Hibernate&lt;br /&gt;作出了回答，但是是否真正明白了呢？我想只有在项目中真正体验过数据层设计后才会悟出这句话的真谛。但我这里还是打算介绍一下这几个词语：面象对&lt;br /&gt;象，结构化及它俩的错配。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;面象对象与结构化的错配&lt;/h3&gt;&lt;br /&gt;需求：&lt;span style="font-weight: bold;"&gt;用户&lt;/span&gt;可以使用多种&lt;span style="font-weight: bold;"&gt;支付方式&lt;/span&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;付款&lt;/span&gt;：&lt;span style="font-weight: bold;"&gt;如信用卡&lt;/span&gt;，&lt;span style="font-weight: bold;"&gt;银行转帐&lt;/span&gt; ...&lt;br /&gt;名词：用户, 信用卡，银行转帐&lt;br /&gt;动词：付款&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;用户&lt;/span&gt;可以用 &lt;span style="font-family:monospace;"&gt;User &lt;/span&gt;来表示，而因为有多种支付方式，而每种支付方式必然存在&lt;br /&gt;着某些共性或相同的动作，因此可以用一个&lt;span style="font-weight: bold;"&gt;支付详情&lt;/span&gt;来作为父类&lt;br /&gt;BillingDetail, 而&lt;span style="font-weight: bold;"&gt;信用卡&lt;/span&gt;可用子类&lt;br /&gt;CreditCard 来表示，&lt;span style="font-weight: bold;"&gt;银行转帐&lt;/span&gt;可以用&lt;br /&gt;BankAccount 来表示。为了使讨论简化，我们现在只考虑父类 BillingDetail。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;付款 bill() 方法由子类实现对应的付款功能。&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;&lt;a name="2.2"&gt;&lt;/a&gt;Java 代码：面向对象的表示&lt;/h4&gt;&lt;br /&gt;&lt;span class="921372908-18012007"&gt;&lt;pre&gt;public class User {&lt;br /&gt;private String name;&lt;br /&gt;private String sex;&lt;br /&gt;private String address;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(204, 0, 0);"&gt; // 因为用户可以多种支付方式，因此采用集合类 Set&lt;/span&gt;&lt;br /&gt;private Set&amp;lt;BillingDetail&amp;gt; billingDetails;&lt;br /&gt;&lt;br /&gt;// Accessor methods (getter/setter), business methods, etc.&lt;br /&gt;...&lt;br /&gt;...&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;public abstract class BillingDetail {&lt;br /&gt;private String accountNumber;&lt;br /&gt;private String accountName;&lt;br /&gt;private String accountType;&lt;br /&gt;&lt;span style="color: rgb(204, 0, 0);"&gt; // 每个支付详情仅属于一个用户，因为支付信息中有帐户名，帐号之类的信息&lt;/span&gt;&lt;br /&gt;private User user;&lt;br /&gt;&lt;br /&gt;// Accessor methods (getter/setter), business methods, etc.&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;public abstract void bill();&lt;br /&gt;...&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/span&gt;&lt;br /&gt;&lt;h4&gt;&lt;a name="2.3"&gt;&lt;/a&gt;数据库表：结构化的数据表示&lt;/h4&gt;&lt;span class="921372908-18012007"&gt;&lt;pre&gt;create table USER (&lt;br /&gt;NAME varchar(15) not null primary key,&lt;br /&gt;SEX  varchar(1) not null, -- 'M' Male, 'F' Female&lt;br /&gt;ADDRESS varchar(100)&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;create table BILLING_DETAILS (&lt;br /&gt;ACCOUNT_NUMBER varchar(10) not null primary key,&lt;br /&gt;ACCOUNT_NAME varchar(50) not null,&lt;br /&gt;ACCOUNT_TYPE varchar(2) not null,&lt;br /&gt;NAME varchar(15) foreign key references user&lt;br /&gt;&lt;span style="font-family:Georgia,serif;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;注意，从 USER 的 create table 语句根本看不出它与 BILLING_DETAILS 有什么关系，但当我们看到&lt;br /&gt;BILLING_DETAILS 中的外键约束行 &lt;span style="font-weight: bold;"&gt;NAME&lt;br /&gt;varchar(15) foreign key references user&lt;/span&gt; 时，才可以得知 USER 与 BILLING_DETAILS 是相关联的，就上述建表语句来讲，用户与付款详情的关系为一对多关系，表示为为 &lt;span style="font-weight: bold; color: rgb(204, 0, 0);"&gt;USER --- (1..*)&lt;br /&gt;---&amp;gt; BILLING_DETAILS&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;但是如果外键约束为：&lt;span class="921372908-18012007"&gt;&lt;br /&gt;&lt;pre&gt;NAME &lt;span style="color: rgb(204, 0, 0);"&gt;unique&lt;/span&gt; varchar(15) foreign key references user&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;则它们之间的关系成了一对一的关系了，&lt;span style="font-weight: bold; color: rgb(204, 0, 0);"&gt;USER --- (1..1)&lt;br /&gt;---&amp;gt; BILLING_DETAILS&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;但是对于面向对象的程序而言，我们一眼就能看出它们之间存在关系，而且我们很快就可以写出下面的代码：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;从 User 来找到对应的 BillingDetail&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Set billingDetails = aUser.getBillingDetails();&lt;br /&gt;&lt;br /&gt;for (Iterator i = billingDetails.iterator(); i.hasNext(); ) {&lt;br /&gt;String accountNumber = (BillingDetail)i.next()).getAccountNumber();&lt;br /&gt;...&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;或，从 BillingDetail 找到对应的 User:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;User aUser = billingDetail.getUser();&lt;br /&gt;String address = aUser.getAddress();&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;对于结构化的数据，我们采用 SQL：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;select u.ADDRESS, bd.ACCOUNT_NUMBER from USER u, BILLING_DETAIL bd&lt;br /&gt;where bd.NAME = u.NAME and u.NAME = '悟空';&lt;/pre&gt;&lt;br /&gt;也许从乍一看，并看不出其中的问题，但是对于象上述这样需要得到两个相关表中的数据（获得用户“悟空”的地址和帐号），因为数据是分布在两个表中，所以必&lt;br /&gt;须将两个表联合 (join, 这个词是出自于标准的SQL: select u.ADDRESS, bd.ACCOUNT_NUMBER from&lt;br /&gt;USER u &lt;span style="font-weight: bold;"&gt;joint &lt;/span&gt;BILLING_DETAIL&lt;br /&gt;bd &lt;span style="font-weight: bold;"&gt;on &lt;/span&gt;bd.NAME = u.NAME where&lt;br /&gt;u.NAME = '悟空'; 这与上面的写法效果是等同的)，联合意味着扫描两张表。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;而对于面向对象的语言，我们可以轻松地从一个对象访问到另一个对象，只要对象中包含了被访问对象的引用即可。我们也可以轻易地看出它们之间的关系，比如&lt;br /&gt;Use 包含一个集合类型 Set 的 BillingDetail引用，则可知其包含多个 BillingDetail, 而&lt;br /&gt;BillingDetail 只包含单个的 User 引用，因此它仅对应一个 User.&lt;br /&gt;而结构化的形式，如SQL则一定要通过引入附加的关键字才能将这一情况加以区分，如 unique, foriegn key&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;所谓的&lt;span style="font-weight: bold;"&gt;面向对象关系型数据库&lt;/span&gt;(如：db4o)正在努力地解决结构化的&lt;br /&gt;问题，但由于大部分工业基础已经建立在传统的&lt;span style="font-weight: bold;"&gt;关系型数据库&lt;/span&gt;的模式之&lt;br /&gt;上，因此变革将肯定是缓慢的，有时甚至不大可能。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;&lt;a name="3"&gt;&lt;/a&gt;DAO调用序列图&lt;/h2&gt;&lt;br /&gt;1. 首先，所有的DAO是在 Spring 的应用上下文加载时初始化的。&lt;br /&gt;&lt;br /&gt;在 dataAccessContext-hibernate.xml 中有：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;  &lt;span style="color: rgb(204, 0, 0);"&gt;&amp;lt;!-- 每个DAO的实现都需要 Hibernate 的 sessionFactory 属性，&lt;br /&gt;该对象相当于普通的JDBC的连接对象，因此其是用来与数据库进行会话的 --&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;lt;bean id="accountDao" class="org.springframework.samples.&lt;br /&gt;jpetstore.dao.hibernate.HibernateAccountDao"&amp;gt;&lt;br /&gt;&amp;lt;property name="sessionFactory" ref="sessionFactory"/&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;bean id="categoryDao" class="org.springframework.samples.&lt;br /&gt;jpetstore.dao.hibernate.HibernateCategoryDao"&amp;gt;&lt;br /&gt;&amp;lt;property name="sessionFactory" ref="sessionFactory"/&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;bean id="productDao" class="org.springframework.samples.&lt;br /&gt;jpetstore.dao.hibernate.HibernateProductDao"&amp;gt;&lt;br /&gt;&amp;lt;property name="sessionFactory" ref="sessionFactory"/&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;bean id="itemDao" class="org.springframework.samples.&lt;br /&gt;jpetstore.dao.hibernate.HibernateItemDao"&amp;gt;&lt;br /&gt;&amp;lt;property name="sessionFactory" ref="sessionFactory"/&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;bean id="orderDao" class="org.springframework.samples.&lt;br /&gt;jpetstore.dao.hibernate.HibernateOrderDao"&amp;gt;&lt;br /&gt;&amp;lt;property name="sessionFactory" ref="sessionFactory"/&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;2. 客户端是通过 Facade 接口来与DAO进行交互的。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;在 applicationContext.xml 中有：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style="color: rgb(204, 0, 0);"&gt;&amp;lt;!-- 结合类 PetStoreImpl 中的 setXXXDao 方法，这种方式在 AOP&lt;br /&gt;的术语中叫做基于 setter 的依赖注入；&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(204, 0, 0);"&gt;还有一种是基于构造器的依赖注入，即将所有的依赖关系在构造器中一并初始化好. --&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;lt;bean id="petStore" class="org.springframework.samples.&lt;br /&gt;jpetstore.domain.logic.PetStoreImpl"&amp;gt;&lt;br /&gt;&amp;lt;property name="accountDao" ref="accountDao"/&amp;gt;&lt;br /&gt;&amp;lt;property name="categoryDao" ref="categoryDao"/&amp;gt;&lt;br /&gt;&amp;lt;property name="productDao" ref="productDao"/&amp;gt;&lt;br /&gt;&amp;lt;property name="itemDao" ref="itemDao"/&amp;gt;&lt;br /&gt;&amp;lt;property name="orderDao" ref="orderDao"/&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;3. 而 PetStoreImpl 中有：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;public class PetStoreImpl implements PetStoreFacade, OrderService {&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(204, 0, 0);"&gt;// 对应于上面配置文件中的列出的所有属性(property) &lt;/span&gt;&lt;br /&gt;private AccountDao accountDao;&lt;br /&gt;&lt;br /&gt;private CategoryDao categoryDao;&lt;br /&gt;&lt;br /&gt;private ProductDao productDao;&lt;br /&gt;&lt;br /&gt;private ItemDao itemDao;&lt;br /&gt;&lt;br /&gt;private OrderDao orderDao;&lt;br /&gt;&lt;br /&gt;//-------------------------------------------------------------------------&lt;br /&gt;// &lt;span style="color: rgb(204, 0, 0);"&gt;基于 setter 的依赖注入方式&lt;/span&gt; (Setter methods for dependency injection)&lt;br /&gt;//-------------------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;public void setAccountDao(AccountDao accountDao) {&lt;br /&gt;this.accountDao = accountDao;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setCategoryDao(CategoryDao categoryDao) {&lt;br /&gt;this.categoryDao = categoryDao;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setProductDao(ProductDao productDao) {&lt;br /&gt;this.productDao = productDao;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setItemDao(ItemDao itemDao) {&lt;br /&gt;this.itemDao = itemDao;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setOrderDao(OrderDao orderDao) {&lt;br /&gt;this.orderDao = orderDao;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;这样，就将初始化出来的所有DAO对象"注入" (通过 setXXXDao(XXXDao) 方法) 到 Facade 的实现类&lt;br /&gt;PetStoreImpl&lt;br /&gt;&lt;br /&gt;4. 好，我们现在来看看在这个应用中有几个地方使用这个门面BEAN来进行DAO操作。&lt;br /&gt;&lt;br /&gt;首先可以肯定的是，有了 PetStoreFacade 这个接口（及其实现类&lt;br /&gt;PetStoreImpl)，永远不出现直接初始化某个DAO的代码，如：&lt;br /&gt;&lt;br /&gt;&lt;pre style="text-decoration: line-through;"&gt;AccountDao accountDao = new HibernateAccountDao();&lt;/pre&gt;&lt;br /&gt;如果不是这样的话，我们前面这几步 1, 2, 3 就白做了，一个个来看：&lt;br /&gt;&lt;br /&gt;1. 在　dataAccessContext-hibernate.xml 配置这些DAO干什么？ 为了在应用 加载/部署&lt;br /&gt;时就把它们初始化出来。我们只需要保证每个配置 bean 有默认构造器。（我们看看包&lt;span style="font-family:monospace;"&gt;org.springframework.samples.jpetstore.dao.hibernate&lt;/span&gt;　&lt;br /&gt;所有的&lt;br /&gt;HibernateXXXDao就可以看到，它们都没有定义任何构造器，那么则意味着编译器会自动产生一个默认构造器 -- 无参数的 public&lt;br /&gt;构造器，这正好符合要求)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2. 在 applicationContext.xml 把这些初始化好的DAO注入到门面接口PetStoreFacade的实现类&lt;br /&gt;PetStoreImpl干什么？因为这个门面，在门里边汇总了所有的DAO，既然已经都初始化出来了，把它们注入进来是很简单的（采用了&lt;br /&gt;Setter 注入方式)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3. 采用 Setter 注入方式　把配置中的DAO注入进来。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;&lt;a name="4"&gt;&lt;/a&gt;Strtus &amp;lt;-- &lt;span style="color: rgb(255, 0, 0);"&gt;Spring&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;--&amp;gt; DAO (Spring 作为 DAO 与 Struts 的桥梁)&lt;/h2&gt;&lt;br /&gt;因为我们知道，在写程序时最好是使用接口进行类型声明，如：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Map map = new HashMap();&lt;/pre&gt;&lt;br /&gt;这样，在以后有更好的实现时，切换到其它实现后，调用端不需要改变，因这个类型是 Map接口, 不是实现类&lt;br /&gt;HashMap。但有一种情况例外，如果你的代码中这样：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;((HashMap)map).XXX;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;这样的话，那么从一种实现平滑切换到接口的另一种实现是不可能的。但是对于 HashMap 是不需要这样的，因为HashMap 所暴露的方法和&lt;br /&gt;Map 是一样的，也就是说 HashMap&lt;br /&gt;没有增加任何方法，所以强制转型是没有意义的，从易扩展（考虑到可能切换到另一种实现）的角度来看，这反而是自己给自己找麻烦。&lt;br /&gt;&lt;br /&gt;所以在我们自己的类设计过程中，这些都可以借鉴的。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;在　NetBeans 中, 选中 PetStoreFacade ，右击 | Find Usages, 在弹出窗口中选择 'Next' :&lt;br /&gt;&lt;br /&gt;在底下列出了所有使用到PetStoreFacade的地方:&lt;br /&gt;&lt;br /&gt;1.排除 以 spring 结尾的包（因为那是 SpringMVC　用到的），&lt;br /&gt;&lt;br /&gt;2.以logic&lt;br /&gt;结尾的包中除一个是在实现类PetStoreImpl的声明之外，还有一个是SendOrderConfirmationEmailAdvice&lt;br /&gt;中有到了，　但这个是采用 Spring 的面象方面 (AOP) 的拦截机，先忽略它。&lt;br /&gt;&lt;br /&gt;3.以 struts 结尾的包正是我们所关心的，我们看到，只有一个类 BaseAction 中用到了这个门面接口。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;乍一想，有点好奇，但当我们深入到以 struts 结尾的这个包中时，我们发现，所有的 Action&lt;br /&gt;（即动作，对应页面的提交按钮，链接等）都是从这个 BaseAction 派生的。&lt;br /&gt;&lt;br /&gt;再有，我们这篇文章的主题是数据访问层技术，所以作为数据层的调用者，只能是控制器层组件，不可能是数据层内自己的对象，更不可能是表示层组件，如&lt;br /&gt;Struts的 FormBean。&lt;br /&gt;&lt;br /&gt;所以这是一个完美的设计。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;我们看一下这样关键的类的代码，代码很简单：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;/**&lt;br /&gt;Superclass for Struts actions in JPetStore's web tier.&lt;/span&gt;&lt;br /&gt;*&lt;br /&gt;* &amp;lt;p&amp;gt;Looks up the Spring WebApplicationContext via the ServletContext &lt;br /&gt;* and obtains the PetStoreFacade implementation from it, making it&lt;br /&gt;* available to subclasses via a protected getter method.&lt;br /&gt;* &amp;lt;p&amp;gt;As alternative to such a base class, consider using Spring's&lt;br /&gt;* ActionSupport class for Struts, which pre-implements&lt;br /&gt;* WebApplicationContext lookup in a generic fashion.&lt;/span&gt;&lt;br /&gt;*&lt;br /&gt;* @author Juergen Hoeller&lt;br /&gt;* @since 30.11.2003&lt;br /&gt;* @see #getPetStore&lt;br /&gt;* @see org.springframework.web.context.support.WebApplicationContextUtils#getRequiredWebApplicationContext&lt;br /&gt;* @see org.springframework.web.struts.ActionSupport&lt;br /&gt;*/&lt;br /&gt;public abstract class BaseAction extends Action {&lt;br /&gt;&lt;br /&gt;private PetStoreFacade petStore;&lt;br /&gt;&lt;br /&gt;public void setServlet(ActionServlet actionServlet) {&lt;br /&gt;super.setServlet(actionServlet);&lt;br /&gt;if (actionServlet != null) {&lt;br /&gt; // &lt;span style="color: rgb(255, 0, 0);"&gt;fixed by pprun, must be synchronized&lt;/span&gt;&lt;br /&gt; synchronized (this) {&lt;br /&gt;   ServletContext servletContext = actionServlet.getServletContext();&lt;br /&gt;   WebApplicationContext wac =&lt;br /&gt;           WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);&lt;br /&gt;   this.petStore = (PetStoreFacade) wac.getBean("petStore");&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;protected PetStoreFacade getPetStore() {&lt;br /&gt;return petStore;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1. 首先我们从Struts的 Action 派生下来，是为了 override setServlet&lt;br /&gt;方法，super.setServlet(actionServlet) 这一句是没有被覆盖时的默认动作，即，将 web.xml 中配置的&lt;br /&gt;ActionServlet 引用进来，这样所有的 Action 都可引用这个 ActionServlet, 如果需要的话。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2. 但我最主要的目的不是为了重复 1. 这个根本没有必要的代码，而是为了将门面接口的实现类放到这个 BaseAction 中，这样，所有的&lt;br /&gt;BaseAction 子类，就可以直接 getPetStore()&lt;br /&gt;获得门面了，有了门面了，所有的DAO及DAO的方法都是通过这个门面来进行调用的。&lt;span style="font-weight: bold;"&gt;这&lt;br /&gt;就是门面这个词最好的解释。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;3. 我们来看看怎么得到在 applicationContext.xml 配置的门面的实现类:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;bean id="petStore" class="org.springframework.samples.jpetstore.domain.logic.PetStoreImpl"&amp;gt;&lt;/pre&gt;&lt;br /&gt;这个配置告诉我们这个实现类的 Bean  id 为 petStore, class 为门面的实现类 PetStoreImpl.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;        ServletContext servletContext = actionServlet.getServletContext();&lt;br /&gt;   WebApplicationContext wac =&lt;br /&gt;           WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);&lt;br /&gt;   this.petStore = (PetStoreFacade) wac.getBean("petStore");&lt;/pre&gt;&lt;br /&gt;正如我经常强调的，所有的 Java Web 框架都离不开 Servlet, Spring与WEB相关的组件也不例外，它需要&lt;br /&gt;ServletContext 来初始化它的专有名词 WebApplicationContext,&lt;br /&gt;&lt;br /&gt;但只要得到了 servletContext, 初始化工作很容易，利用 Spring 提供的工具类&lt;br /&gt;WebApplicationContextUtils 的 getRequiredWebApplictionContext 方法，将得到的&lt;br /&gt;servletContext　传进去即可。&lt;br /&gt;&lt;br /&gt;那么怎样才能得到 servletContext 呢？如果对 Servlet 熟悉的话，任何 Servlet- abcServlet都有&lt;br /&gt;abcServlet.getServletContext()方法，它其实是&lt;br /&gt;abcServlet.getServletConfig().getServletContext() 的简化版。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;再看看，&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;super.setServlet(actionServlet);&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;所以只需从 actionServlet.getServletContext(); 然后传入到Spring中，这样 Spring 就成了 DAO&lt;br /&gt;与 Struts 的桥梁了：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;        this.petStore = (PetStoreFacade) wac.getBean("petStore");&lt;/pre&gt;&lt;br /&gt;Spring, 关键的东西就是它的配置文件，在程序中表示为接口： ApplicationContext,&lt;br /&gt;对WEB应用就是其子接口：WebApplicationContext。　一旦Sping的这个（些）上下文后，所有在配置文件中的东西，在&lt;br /&gt;Spring 都是 Bean,得到它们是很容易的。因为所有的配置的 Bean 都有一个 id, 并指定了其的类型 class,&lt;br /&gt;且正如我们前面所说，要符合 Bean, 必须需要&lt;br /&gt;默认构造器（如果你定义了构造器的话，那么你不得不要写一个默认构造器，因为这时编译器不再为你生成它了，但如果你一个构造器都没指定的话，可以让编译器&lt;br /&gt;Javac 来为你生成，采用什么策略取决于你，但为了清晰起见，最好任何可初始化的类都给出默认构造器，这也是IDE为什么每次 new&lt;br /&gt;一个类时，它都会为你生成的原因）&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;getBean 的参数即是你所想得到的 Bean 的 id, 在你在 ApplicationContext.xml&lt;br /&gt;中配置时，就指定了，则在应用初始化时就把它 new 出来了，也就是说所有配置的 Bean&lt;br /&gt;在程序一初始化时都给创建出来了，只等待你来用吧。这也就是有时为什么叫 Spring 的上下文为 Bean&lt;br /&gt;容器的原因。（负面影响是，程序的初始化时间大延长了，但对于WEB应用而言，这并不是什么大不了的，谁你天天重启应用服务器呢？）&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;4. web.xml 文件中告诉我们，所有的Action 都是由这个 Servlet 处理的。(具体的内容会在后续的系列中介绍)&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;  &amp;lt;servlet&amp;gt;&lt;br /&gt;&amp;lt;servlet-name&amp;gt;action&amp;lt;/servlet-name&amp;gt;&lt;br /&gt;&amp;lt;servlet-class&amp;gt;org.apache.struts.action.ActionServlet&amp;lt;/servlet-class&amp;gt;&lt;br /&gt;&amp;lt;load-on-startup&amp;gt;3&amp;lt;/load-on-startup&amp;gt;&lt;br /&gt;&amp;lt;/servlet&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;再次证实，所有的 Java Web 框架离不开 Servlet, 如果你们不再怀疑这句话，可以去买本 Servlet&lt;br /&gt;的中文版的书，我是通过看所有的英文版的资料和API来学习的。虽然我没买过 Servlet&lt;br /&gt;相关的书，但并不说明它不重要，恰恰是因为我当时也误解了。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;搜索一下 china-pub, 发现所有与 Servlet 相关的书都是在2002 年之前出的，这说明， Servlet&lt;br /&gt;是一个稳定的技术，自从规范 2.3 版（这一版加入了 Filter)以来，几乎没有引入新的特征，所以没有必要再写新书了，但据说下一版,&lt;br /&gt;Java EE 6 将会有很大的变化，这是为了迎合新技术，如 AJAX。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;&lt;a name="5"&gt;&lt;/a&gt;实体关系图&lt;/h2&gt;&lt;br /&gt;实体关系图 (ERD - Entity Relationship Diagram, 以下是在 JDeveloper&lt;br /&gt;中生成的，很方便，想知道怎么生成的话，我可以在 MSN&lt;br /&gt;上告诉你们步骤，但你们先得告诉我你们想知道，这对于一个项目，如果是建立在已经存在的数据库之上时特别有用，因为一看到这图，所有的关系一目了然。&lt;br /&gt;我想，随着你们的工作经历的增加，你们会意识到，一个项目如果是建立在没有存在的数据库之上时，这是罕见的，也是特别幸运的)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;account       宠物店的用户表示&lt;br /&gt;&lt;br /&gt;orders        购物清单&lt;br /&gt;&lt;br /&gt;lineitem      购物清单中的中的每一项 (可以想象，我们到超市也可以一下买一条烟，两瓶酒&lt;br /&gt;...)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;item          包含商品的详细信息，比如 黄果树烟：单价&lt;br /&gt;46元，厂家 贵州卷烟厂 ...&lt;br /&gt;&lt;br /&gt;supplier      商品提供商，一般也称厂商&lt;br /&gt;&lt;br /&gt;inventory     商品库存信息&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;&lt;a name="6"&gt;&lt;/a&gt;实体关系映射(O/R Mapping)&lt;br /&gt;&lt;br /&gt;&lt;/h2&gt;&lt;h2&gt;&lt;/h2&gt;从上面的实体关系图可以看到:&lt;br /&gt;&lt;br /&gt;account (* .. 0..1) category, 这说明一个 Account 最多可以有一个自己最喜爱的宠物类型，也可以没有。&lt;br /&gt;&lt;br /&gt;account (1 .. *) orders, 这说明一个 Account 可以包含多个 Order&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;a name="6.1"&gt;&lt;/a&gt;Java代码中的关系表示&lt;/h3&gt;我们首先看看这两种关系在 Java 代码中的表示：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Account.java&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;public class Account implements java.io.Serializable ,Comparable {&lt;br /&gt;private Long id;&lt;br /&gt;private int version;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;// fav &amp;lt;- &lt;span style="font-weight: bold;"&gt;fav&lt;/span&gt;orite&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;private Category favCategory;&lt;/span&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;// @OneToMany(mappedBy = "user")&lt;/span&gt; &lt;br /&gt; private Set&amp;lt;Order&amp;gt; orders =&lt;br /&gt;           new HashSet&amp;lt;Order&amp;gt;();&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; public Category getFavCategory() {&lt;br /&gt; return favCategory;&lt;br /&gt;}&lt;br /&gt;public void setFavCategory(Category favCategory) {&lt;br /&gt;this.favCategory = favCategory;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;public Set getOrders() {&lt;br /&gt;return orders;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setOrders(Set&amp;lt;Order&amp;gt; orders) {&lt;br /&gt;this.orders = orders;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;// scaffold code for collection field&lt;/span&gt;&lt;br /&gt;public void addOrder(Order order) {&lt;br /&gt;if (order == null)&lt;br /&gt; throw new IllegalArgumentException("Can't add a null Order.");&lt;br /&gt;this.getOrders().add(order);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Order.java&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;public class Order implements java.io.Serializable, Comparable {&lt;br /&gt;private Long id;&lt;br /&gt;private int version;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;  // @ManyToOne&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;&lt;br /&gt;// @JoinColumn(name="userId", nullable = true, updatable = false)&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;&lt;br /&gt;private Account user;&lt;/span&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;public Account getUser() {&lt;br /&gt;return user;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Category.java&lt;br /&gt;&lt;pre&gt;...&lt;span style="font-family:Georgia,serif;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;h4&gt;&lt;a name="6.1.1"&gt;&lt;/a&gt;单向关系&lt;/h4&gt;&lt;br /&gt;&lt;br /&gt;在 Category.java 中没有看到我们希望看到的如下代码：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style="text-decoration: line-through;"&gt;public class Category implements java.io.Serializable, Comparable {&lt;/span&gt;&lt;br /&gt;&lt;span style="text-decoration: line-through;"&gt;  private Long id;&lt;/span&gt; &lt;span style="text-decoration: line-through;"&gt;  private int version;&lt;/span&gt; &lt;span style="text-decoration: line-through;"&gt;  &lt;/span&gt;&lt;span style="color: rgb(255, 0, 0); text-decoration: line-through;"&gt;&lt;br /&gt;&lt;/span&gt; &lt;span style="text-decoration: line-through;"&gt;  &lt;/span&gt;&lt;span style="color: rgb(255, 0, 0); text-decoration: line-through;"&gt;// @OneToMany(mappedBy = "userId")&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0); text-decoration: line-through;"&gt;&lt;br /&gt;private Set&amp;lt;Account &amp;gt; users=&lt;br /&gt;new HashSet&amp;lt;Account &amp;gt;();&lt;/span&gt;&lt;br /&gt;...&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;这因为设计时考虑到从 Category -&amp;gt; Account&lt;br /&gt;是没有必要的，如：当前显示一种宠物种类“狗”时，有必要显示出所有喜欢狗的用户出来吗？&lt;br /&gt;&lt;br /&gt;既然没必要，所以我们没有将上面的代码加到Category 中去，这样叫单向关联（非双向关联，uni-bidirectional,&lt;br /&gt;association），也就是说，在Java代码中，得到一个 Category 的实例后，是无法从它“导航”(navigate) 到&lt;br /&gt;Account 的，但是反向则是可以的:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;// 不可能&lt;br /&gt;Category cate = ...;&lt;br /&gt;&lt;span style="text-decoration: line-through; color: rgb(255, 0, 0);"&gt;Account a = cate.getUser();&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;// 只能&lt;br /&gt;&lt;br /&gt;Account a = ...;&lt;br /&gt;&lt;br /&gt;Category cate = a.getFavCategory();&lt;br /&gt;&lt;/pre&gt;&lt;h4&gt;&lt;a name="6.1.2"&gt;&lt;/a&gt;双向关系&lt;/h4&gt;&lt;br /&gt;&lt;br /&gt;Account 与 Order 的关系是双向的，因为一个用户进行多次购物，每次都会生成一次清单。而每个购物清单都必须得到是谁的.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;注：注释掉的 @OneToMany 与 @ManytoOne 等，是采用 Java 5 的 Annotation&lt;br /&gt;进行的处理，如果所有的映射都进行这样的处理，我们可以排除使用 hibernate hbm.xml 文件。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;从 Order 到 Account&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Order o = ...&lt;br /&gt;&lt;br /&gt;Account a = o.getUser();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;但注意到 Order.java 中并没有 setUser()&lt;br /&gt;方法，这时我们故意把 user 成员在 Order.java 做成了只读(read-only)了，为什么？&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;因为一个购物单生成了，是不能随便更改帐户的。如果要改，这个单子就作废。基于这个&lt;br /&gt;考虑，只有这样设计才符合现实。&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;从 Account 到 Order&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;        HashSet&amp;lt;Order&amp;gt; orders = getOrders();&lt;br /&gt;   for (Iterator it = orders.iterator(); it.hasNext();) {&lt;br /&gt;       Object elem = (Object) it.next();&lt;br /&gt;       ...&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(255, 0, 0);"&gt;这里首先指出Account.java 中的几个 Bug:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1. 最好使用统一使用泛型 (gerneric type):&lt;br /&gt;&lt;br /&gt;在声明时使用了，但在 getter, setter 中没有使用，前后不统一，因此应该为:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt; // @OneToMany(mappedBy = "user")&lt;/span&gt; &lt;br /&gt;private Set&amp;lt;Order&amp;gt; orders = new HashSet&amp;lt;Order&amp;gt;();&lt;br /&gt;   ...&lt;br /&gt;&lt;br /&gt;public Set&amp;lt;Order&amp;gt; getOrders() {&lt;br /&gt;   return orders;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setOrders(Set&amp;lt;Order&amp;gt; orders) {&lt;br /&gt;   this.orders = orders;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// scaffold code for collection field&lt;br /&gt;public void addOrder(Order order) {&lt;br /&gt;   if (order == null)&lt;br /&gt;       throw new IllegalArgumentException("Can't add a null Order.");&lt;br /&gt;   this.getOrders().add(order);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;2. 理应将 setOrders(Set&amp;lt;Order&amp;gt; orders) 方法作为 private&lt;br /&gt;的，或干脆去掉，因为有了脚手架方法(scaffold method)  adOrder(Order order)，Account&lt;br /&gt;中所有对 Order 的处理应该由脚手架来处理，由它来操作这个集合类, Set&amp;lt;Order&amp;gt; orders,&lt;br /&gt;并维护它们之间的这种双向关系，去掉了 setOrder&lt;br /&gt;方法后，我们需要加另一个脚手架方法来实现从购物单去除一项的功能。（如果没有这项功能的话，那么在我们去超市排队付款时，当一个顾客想取消一个已扫描的&lt;br /&gt;物品时，可能就会听到收银员说，“不好意思，不能取消！”，这显然是不合理的，所以我们需要增加 removeOrder 方法，如下：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;   &lt;span style="color: rgb(255, 0, 0);"&gt; // @OneToMany(mappedBy = "user")&lt;/span&gt; &lt;br /&gt;&lt;br /&gt;private Set&amp;lt;Order&amp;gt; orders = new HashSet&amp;lt;Order&amp;gt;();&lt;br /&gt;&lt;br /&gt;   ...&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;public Set&amp;lt;Order&amp;gt; getOrders() {&lt;br /&gt;   return orders;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;    //public void setOrders(Set&amp;lt;Order&amp;gt; orders) {&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;&lt;br /&gt;//    this.orders = orders;&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;    //}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;// scaffold code for collection field&lt;br /&gt;public void addOrder(Order order) {&lt;br /&gt;   if (order == null)&lt;br /&gt;       throw new IllegalArgumentException("Can't add a null Order.");&lt;br /&gt;   this.getOrders().add(order);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;    public void removeOrder(Order order) {&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;    &lt;br /&gt;  if (order == null)&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;&lt;br /&gt;    throw new IllegalArgumentException("Can't remove a null Order.");&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;    &lt;br /&gt;&lt;br /&gt;  this.getOrders().remove(order);&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;h3&gt;&lt;a name="6.2"&gt;&lt;/a&gt;Hibernate 的关系表示&lt;br /&gt;&lt;/h3&gt;&lt;br /&gt;好，看了我们熟悉的 JAVA 代码中处理这种关系后，我们得看看如果在 Hibernate 映射中声明这种关系了。&lt;br /&gt;&lt;h4&gt;&lt;span style="font-weight: bold;"&gt;&lt;a name="6.2.1"&gt;&lt;/a&gt;account -category&lt;/span&gt;&lt;br /&gt;&lt;/h4&gt;Account.hbm.xml&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;account (* .. 0..1) category  (&lt;span style="color: rgb(255, 153, 0);"&gt;many-to-one&lt;/span&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;        &amp;lt;many-to-one&lt;br /&gt;       name="favCategory"&lt;br /&gt;       column="favCategoryId"&lt;br /&gt;       class="Category"&lt;br /&gt;       foreign-key="FK_favCategoryId"/&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;1. many-to-one 即是 *..1, 但是我们的关系其实是 *..0..1 即是 many-to-one 或 many-to-one&lt;br /&gt;/ many-to-zero&lt;br /&gt;&lt;br /&gt;但目前这种关系都只能通过 many-to-one 来指定，只不过，如果是严格的 many-to-one&lt;br /&gt;关系时，我们要强调一个属性 &lt;span style="font-weight: bold;"&gt;non-null&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;        &amp;lt;&lt;span style="color: rgb(255, 153, 0);"&gt;many-to-one&lt;/span&gt;&lt;br /&gt;       name="favCategory"&lt;br /&gt;       column="favCategoryId"&lt;br /&gt;       class="Category"&lt;br /&gt;       foreign-key="FK_favCategoryId"&lt;br /&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;not-null=false&lt;/span&gt; /&amp;gt;&lt;/pre&gt;&lt;br /&gt;这样就保证了非空.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2.外键 foreign-key, 如果不明确地写出，则 Hibernate&lt;br /&gt;会自动产生一个随机的外键。象我们这样，我们可以在产生的数据库的定义语句中可以看到（如果使用的是 Mysql, 则在 Mysql Query&lt;br /&gt;Browser 中，在hjpetstore 数据库中，选中 account | 右击 | copy SQL to&lt;br /&gt;Clipbroad，然后粘贴在上面的输入框或其它任何文本编辑器的输入地方）：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;CREATE TABLE  `hjpetstore`.`account` (&lt;br /&gt;`accountId` bigint(20) NOT NULL auto_increment,&lt;br /&gt;`version` int(11) NOT NULL,&lt;br /&gt;`username` varchar(80) NOT NULL,&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;`favCategoryId` bigint(20) default NULL,&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;PRIMARY KEY  (`accountId`),&lt;br /&gt;UNIQUE KEY `username` (`username`),&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;KEY `FK_favCategoryId` (`favCategoryId`),&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;&lt;br /&gt;CONSTRAINT `FK_favCategoryId` FOREIGN KEY (`favCategoryId`)&lt;br /&gt;REFERENCES `category` (`categoryId`)&lt;/span&gt;&lt;br /&gt;) ENGINE=InnoDB DEFAULT CHARSET=gbk;&lt;/pre&gt;&lt;br /&gt;3. 关系是由两端组成，指定时 xxx-&lt;span style="color: rgb(255, 0, 0);"&gt;to&lt;/span&gt;-xxx,&lt;br /&gt;to 前面的关系端是当前映射文件对应的实体，在我们上面的例子即是 Account, to 后面的关系端是这个元素要表示的关系实体,&lt;br /&gt;&lt;br /&gt;这个xml 元素（即 many-to-one) 的所有属性的指定都是用来约束 to  后面的关系端的，对于我们上面的例子是&lt;br /&gt;Category.&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt; name="favCategory" 指的是 Account.java 中的成员&lt;/li&gt;&lt;br /&gt;&lt;li&gt; column 指的是这个成员映射的的数据库列&lt;/li&gt;&lt;br /&gt;&lt;li&gt; class 指的是 one 所代表的实体,即 Category&lt;/li&gt;&lt;br /&gt;&lt;li&gt; foreign-key 即用来限制这个表列的值的外键，即是 Catggory 的主键&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;在自己手工写映射文件时，一定要清楚地知道这关系，或许你们现在只是被地接受，没有体会到自己写时的那种混乱：&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;在写 account.hbm.xml 时，为了表示这种关系是要指定 many-to-one 呢？还是 one-to-many 呢？&lt;/li&gt;&lt;br /&gt;&lt;li&gt;one 指的是那个实体，many 又是那个实体，&lt;/li&gt;&lt;br /&gt;&lt;li&gt;在写 account.hbm.xml 是，为什么这里要指定的 class 是Category&lt;/li&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;...&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;为了弄清这些关系，&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;ol&gt;&lt;li&gt;首先必须对 many-to-one, one-to-many,&lt;br /&gt;many-to-many(比较少见）有个清楚的认识，任何一种关系，把两端的实体对调，那么他们的关系就刚好要反过来，如：Account-&amp;gt;&lt;br /&gt;category (many-to-one), category-&amp;gt;account(one-to-many)&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;再有，在写 hbm.xml 文件时，记住，在指定关系映射时， to 前面的端是指当前这个 hbm.xml 文件代表的实体， to&lt;br /&gt;后面的端是对关系的另一端，而这个元素中的任何属性都用来标识并约束关系的另一端的。&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Category.hbm.xml&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;category&lt;/span&gt;&lt;span style="font-weight: bold;"&gt; (0..1 .. *) &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;account (&lt;span style="color: rgb(255, 153, 0);"&gt;one-to-many&lt;/span&gt;)&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;, &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;刚好是account (* .. 0..1) category 的反向&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;同样，因为是单向关系，所以我们&lt;span style="font-weight: bold;"&gt;没有&lt;/span&gt;在其中看到如下的代码&lt;br /&gt;&lt;br /&gt;&lt;pre style="text-decoration: line-through;"&gt;        &amp;lt;!-- Mapping for Account association. --&amp;gt;&lt;br /&gt;   &amp;lt;set name="users"&lt;br /&gt;        inverse="true"&lt;br /&gt;        cascade="save-update"&lt;br /&gt;        access="field"&amp;gt;&lt;br /&gt;       &amp;lt;key column="userId" /&amp;gt;&lt;br /&gt;       &amp;lt;&lt;span style="color: rgb(255, 153, 0);"&gt;one-to-many&lt;/span&gt; class="Account"/&amp;gt;&lt;br /&gt;   &amp;lt;/set&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;从 account - &amp;gt; category  为 many-to-one, 那么反过来就是 one-to-many&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;&lt;a name="6.2.2"&gt;&lt;/a&gt;account - order&lt;/h4&gt;&lt;br /&gt;生成的 SQL DDL:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style="font-weight: bold;"&gt;CREATE TABLE  `hjpetstore`.`account` (&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;`accountId`&lt;/span&gt; bigint(20) NOT NULL auto_increment,&lt;br /&gt;`version` int(11) NOT NULL,&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;`favCategoryId` bigint(20) default NULL,&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;PRIMARY KEY  (`accountId`),&lt;/span&gt;&lt;br /&gt;UNIQUE KEY `username` (`username`),&lt;br /&gt;KEY `FK_favCategoryId` (`favCategoryId`),&lt;br /&gt;CONSTRAINT `FK_favCategoryId` FOREIGN KEY (`favCategoryId`)&lt;br /&gt;REFERENCES `category` (`categoryId`)&lt;br /&gt;) ENGINE=InnoDB DEFAULT CHARSET=gbk;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE  `hjpetstore`.`orders` (&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;`orderId`&lt;/span&gt; bigint(20) NOT NULL auto_increment,&lt;br /&gt;`version` int(11) NOT NULL,&lt;br /&gt;`userId` bigint(20) NOT NULL,&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;PRIMARY KEY  (`orderId`),&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;KEY `FK8D444F05BC594D77` (`userId`),&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;&lt;br /&gt;CONSTRAINT `FK8D444F05BC594D77` FOREIGN KEY (`userId`)&lt;br /&gt;REFERENCES `account` (`accountId`)&lt;/span&gt;&lt;br /&gt;) ENGINE=InnoDB DEFAULT CHARSET=gbk;&lt;/span&gt;&lt;/pre&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;br /&gt;Account.hbm.xml&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;account (1 .. *) order (&lt;/span&gt;&lt;span style="color: rgb(255, 153, 0); font-weight: bold;"&gt;one-to-many&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;        &amp;lt;!-- Mapping for Order association. --&amp;gt;&lt;br /&gt;   &amp;lt;set name="orders"&lt;br /&gt;        inverse="true"&lt;br /&gt;        cascade="save-update"&lt;br /&gt;        access="field"&amp;gt;&lt;br /&gt;       &amp;lt;key column="userId" /&amp;gt;&lt;br /&gt;       &amp;lt;&lt;span style="color: rgb(255, 153, 0);"&gt;one-to-many&lt;/span&gt; class="Order"/&amp;gt;&lt;br /&gt;   &amp;lt;/set&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;1. set 即是 代表集合类 Set&lt;br /&gt;&lt;br /&gt;2. name="orders" 即是 Account.java 的成员为 orders&lt;br /&gt;&lt;br /&gt;3. access="field" 即通过类的成员来访问 orders, 不管其是否为 public 与否；而不是通过&lt;br /&gt;getter/setter 来访问，如果是后者的话，则为 access="property"，但此时必须定义 getter 和 setter,&lt;br /&gt;但我们不是把 setOrders() 注释掉了吗？所以只能是 field 了.&lt;br /&gt;&lt;br /&gt;4. &amp;lt;key column="userId" /&amp;gt;  这个是用来定义这种外键关系的名字, 所以我们可以在表 Order&lt;br /&gt;产生的 DDL 中可以看到 foreign key('userId')，Order的这个外键引用的正是Accoung的主键, accountId: references 'accoung' ('accountId'); 但请注意，我们是在 Account.xml 定义的这些关系，但是在关系的 many 端，我们的例子中(Order)，生成的表中才会出现这种约束关系，这与我们写 SQL 创建表是一样的：&lt;br /&gt;&lt;br /&gt;外键约束关系只会出现在关系的 many端，因为只有关系的多端才需要这个外键来指定这个关系的单端是谁。Order1 需要知道这是order 是属于谁，Order2 也是需要知道这个&lt;br /&gt;order 是属于谁；但是 Account 要么知道他所有的  order, 要么知道他根本还没有 order, 并不可能用&lt;br /&gt;account 来限定表 order 中的一行；所以这就是为什么外键约束总是出现在 many 端的原因吧。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;但在 java 代码中这个外键关系刚刚相反，它总是以 集合类的方式出现在单(one) 端中，比如 orders 存在于 Account.java，所以这种映射也是出现在单端的 hbm.xml 文件中，而在多端中往往只是普通的一个实体引用：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;  // @ManyToOne&lt;br /&gt;// @JoinColumn(name="userId", nullable = true, updatable = false)&lt;br /&gt;private Account user;&lt;/pre&gt;&lt;br /&gt;所以一定注意。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;5. &amp;lt;one-to-many class="Order" /&amp;gt; 这个应该是比较明显了，声明多端，也就是集合类中元素的类型&lt;br /&gt;&lt;br /&gt;6. inverse="true"&lt;br /&gt;&lt;br /&gt;7. cascade="save-update"&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;上面两个属性，是值得好好理解的，因为这个两个属性，对于熟悉SQL及ERD的人来说也并不是容易理解的，因为这个两个属性或多或少是必于&lt;br /&gt;Hibernate或所有 O/R Mapping 框架特有的东西。如果需要深入了解的话，看看《Hibernate In Action》&lt;br /&gt;3.7.4 Making the association bidirectional 是有好处的。不过我这里也想好好讲讲，毕竟这个太重要了。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;为了更好地理解这两概念，现在我们先假设 Order 的成员 user 不再是只读，即存在 setUser 方法，如下：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;  public void setUser(Account account) {&lt;br /&gt; this.user = account;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;因为我们这个例子是个特例，read-write 的成员还是占大多数的。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;现在，如果在客户端有如下代码：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Order order = ...;&lt;br /&gt;Account account = ...;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;order.setUser(account);&lt;/span&gt; &lt;span style="font-weight: bold;"&gt;account.addOrder(order);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;引用自 Hibernate In Action:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;This code is fine, but in this&lt;br /&gt;situation, Hibernate detects two different changes to&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;the in-memory persistent instances.&lt;br /&gt;From the point of view of the database, just&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;one value must be updated to reflect&lt;br /&gt;these changes: the UserId(原文为ITEM_ID) column of the&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Order(原文为&lt;/span&gt;&lt;span style="font-style: italic;"&gt;BID) table. Hibernate doesn’t&lt;br /&gt;transparently detect the fact that the two changes refer to the&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;same database column, since at this&lt;br /&gt;point we’ve done nothing to indicate that this is a bidirectional&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;association.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;We need one more thing in our&lt;br /&gt;association mapping to tell Hibernate to treat&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;this as a bidirectional association:&lt;br /&gt;The inverse attribute tells Hibernate that the&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;collection is a mirror image of the&lt;br /&gt;many-to-one association on the other side:&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Without the inverse attribute, Hibernate would try to execute two&lt;br /&gt;different SQL&lt;br /&gt;&lt;br /&gt;statements, both updating the same foreign key column, when we&lt;br /&gt;manipulate the&lt;br /&gt;&lt;br /&gt;association between the two instances. By specifying inverse="true", we&lt;br /&gt;explicitly&lt;br /&gt;&lt;br /&gt;tell Hibernate which end of the association it should synchronize with&lt;br /&gt;the database.&lt;br /&gt;&lt;br /&gt;In this example, we tell Hibernate that it should propagate changes made&lt;br /&gt;&lt;br /&gt;at the Order&lt;/span&gt;&lt;span style="font-style: italic;"&gt;(原文为&lt;/span&gt;&lt;span style="font-style: italic;"&gt;Bid)&lt;/span&gt;&lt;span style="font-style: italic;"&gt; end of the association to the database,&lt;br /&gt;ignoring changes made only to&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;the orders(原文为bids) collection. Thus if we only call&lt;br /&gt;account.addOrder(order) (原文为 item.getBids().add(bid)), no changes&lt;br /&gt;&lt;br /&gt;will be made persistent. This is consistent with the behavior in Java&lt;br /&gt;without&lt;br /&gt;&lt;br /&gt;Hibernate: If an association is bidirectional, you have to create the&lt;br /&gt;link on two&lt;br /&gt;&lt;br /&gt;sides, not just one.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;这两行代码可以正常编译，但是在这种情形下，Hibernate 将发现这里存在两个改变试图改变内存中的持久化对象（&lt;span style="font-weight: bold;"&gt;为什么叫内存中，而不是数据库中呢？因为Hibernate&lt;br /&gt;会把所有它碰到过的实体对象缓存在一级 Cache ，即所谓的 session&lt;br /&gt;cache中，注意，稍后我们在配置文件中配置的是二级cache，它是在 SessionFactory 级的&lt;/span&gt;）。但从数据库方面来看，&lt;br /&gt;这只需要一个改变即可以反映这种改变（这种改变指的是建立起这种关系，将这两个新建的实体关联起来，即指定 Order 表中的 UserId&lt;br /&gt;列，即外键）。Hibernate 并不明确地知道这一事实：这这两个改变都是指向同一个数据库表的列，因为在此时我们还没有指示这种关系是一个&lt;span style="font-weight: bold;"&gt;双向关系&lt;/span&gt;。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;我们需要在关联关系映射中进一步告诉 Hinbernate 这两个实体的这种关系对待为双向关系：&lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;inverse&lt;/span&gt; 属性告诉&lt;br /&gt;Hibernate 这个集合（即单端中的集合成员，在我们的例子中即为 Account 中的 orders)是另一端的 many-to-one&lt;br /&gt;关系的镜像。(请接下一段翻译)（另一端的 many-to-one 关系即是下面的映射&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;order (* .. 1) account (&lt;span style="color: rgb(255, 153, 0);"&gt;many-to-one&lt;/span&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;    &amp;lt;&lt;span style="color: rgb(255, 153, 0);"&gt;many-to-one&lt;/span&gt; name="user"&lt;br /&gt;            column="userId"&lt;br /&gt;            not-null="true"&lt;br /&gt;            update="false"&lt;br /&gt;            access="field" /&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;我们不重复上面已经介绍过或一看就能理解的属性，如 many-to-one, access 等。&lt;br /&gt;&lt;br /&gt;1. not-null="true" ，即会在SQL中产生：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style="font-weight: bold;"&gt;`userId` bigint(20) &lt;span style="color: rgb(255, 0, 0);"&gt;NOT NULL&lt;/span&gt;,&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;2. update="false" 即是这个属性是 &lt;span style="font-weight: bold;"&gt;read-only&lt;/span&gt;&lt;br /&gt;的 （我们又回到了将 setUser() 方法去掉的情形，因为我们上面的假设只是为了更好地描述问题，因此只要是双向关系就必须在&lt;span style="font-weight: bold;"&gt;集合端&lt;/span&gt;指示地指定 inverse="true'））&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;(上接)&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;没有 inverse 属性，在我们操纵两个实体间的关系时，Hibernate 将会试图执行两个不同的SQL语句来更新同一个外键列。通过指定&lt;br /&gt;inverse="true", 我们明确地告诉 Hibernate 关系的哪端应该将改变同步到数据库中去（即将改变通过 SQL&lt;br /&gt;语句写入到数据库中去），在这个例子中，我告诉 Hibernate 应该将发生在 Order&lt;br /&gt;端的改变传播到数据库中去，而忽略仅仅发生在单端中的集合类成员 orders 的这端改变（即单端中的集合类 ）。因此，如果我们仅仅通过调用&lt;br /&gt;account.addOrder(order),&lt;br /&gt;将不会有任何作用（即不会将这种改变存到数据库中去，也就是说，这种改变在程序退出后将消失。&lt;span style="color: rgb(255, 0, 0);"&gt;很危险是吗，别着急，请看下一段！&lt;/span&gt;）。这种行为是和普通 java&lt;br /&gt;的行为一致的，如果关系是一个双向关系时，我们不得不在关系的两端创建出一个链接，而不是一端。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;正如上段所说，为了达到不因为更改同一个数据库列而执行两条SQL语句，我们付出了&lt;br /&gt;很大代价，改变发生在单端集合成员上的改变如果不明确地调用 session.save(...); 的话，将有可能丢失数据&lt;/span&gt;。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;难道 Hibernate 号称它为透明化持久（transitive persistence) 是徒有虚名的？&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;不！这正是 cascade 的作用。&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;我们上现在的例子中通过指定:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;cascade="save-update"&lt;/pre&gt;&lt;br /&gt;详情请见 Hibernate In Action:&lt;br /&gt;&lt;br /&gt;4.3.2 Cascading persistence with Hibernate&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You can map entity associations in metadata with the following&lt;br /&gt;attributes:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;cascade="none"&lt;/span&gt;, the&lt;br /&gt;default, tells Hibernate to ignore the association.&lt;/li&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;cascade="save-update"&lt;/span&gt;&lt;br /&gt;tells Hibernate to navigate the association when the transaction is&lt;br /&gt;committed and when an object is passed to save() or update() and save&lt;br /&gt;newly instantiated transient instances and persist changes to detached&lt;br /&gt;instances.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;cascade="delete"&lt;/span&gt; tells&lt;br /&gt;Hibernate to navigate the association and delete persistentinstances&lt;br /&gt;when an object is passed to delete().&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;cascade="all" &lt;/span&gt;means to&lt;br /&gt;cascade both save-update and delete, as well ascalls to evict and lock.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;cascade="all-delete-orphan"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;means the same as cascade="all" but, in addition,Hibernate deletes any&lt;br /&gt;persistent entity instance that has been removed(dereferenced) from the&lt;br /&gt;association (for example, from a collection).&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;cascade="delete-orphan"&lt;/span&gt;&lt;br /&gt;Hibernate will delete any persistent entityinstance that has been&lt;br /&gt;removed (dereferenced) from the association (forexample, from a&lt;br /&gt;collection).&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;cascade="save-update" &lt;/span&gt;告诉&lt;br /&gt;Hibernate，当 session.save() 或 session.update()&lt;br /&gt;后，事务操作被提交(committed)之后中，它将导航(natigate)到关系的另一端，将保存新创建的实体实例和对&lt;br /&gt;detached(这个词的翻译需要一段话来解释，简单地讲，是因为 Hibernate&lt;br /&gt;会一次性把好多对象从数据库中取出，然后断开数据库连接，这时，这些取出的对象就处在 detached&lt;br /&gt;状态，而后，对这些对象的改变会在适当的时候通过重新获得数据库连接保存到数据库当中去）作出的改变。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;至于其它的用到的应该不多特别是 all, all-delete-orphan, delete-orphan, 为什么叫 orphan,&lt;br /&gt;举例来说，如果一个用户销户了，从Account表中删除了，而数据库Order表中还保存了他的购物清单，这时这些 order&lt;br /&gt;数据就叫做孤儿，因为此时从 Account 永远访问不到 Order 了。&lt;br /&gt;&lt;br /&gt;但是现实当时，除非特别指出，一般还是让这些孤儿保留比较好，省得一下子所以的记录全没了。所以一般设置为 sava-upate 就可以了。&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;注意：&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;我映射 POJO类 Order 时走过弯路，因为 order 是SQL语言的关键字，所以总是出错，最终我看错误信息是有关 (&lt;span style="font-weight: bold;"&gt;key word&lt;/span&gt;) ，所以我把表的名字加上了一个 's'，如：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;  &amp;lt;!-- Order 为数据库关键字，所以表名不能为 Order.&lt;br /&gt;    这可是花了几小时的代价得出的经验&lt;br /&gt;--&amp;gt;&lt;br /&gt;&amp;lt;class name="Order" table="Orders" lazy="true"&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;&lt;a name="6.3"&gt;&lt;/a&gt;主键映射&lt;br /&gt;&lt;/h4&gt;&lt;br /&gt;Account.hbm.xml 中&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;        &amp;lt;id name="id" type="long" column="accountId" &lt;span style="font-weight: bold;"&gt;&lt;br /&gt;      unsaved-value="null"&lt;/span&gt; access="field"&amp;gt;&lt;br /&gt;       &amp;lt;generator class="native" /&amp;gt;&lt;br /&gt;   &amp;lt;/id&amp;gt;&lt;br /&gt;&lt;br /&gt;   &amp;lt;!-- A versioned entity. --&amp;gt;&lt;br /&gt;   &amp;lt;version name="version"&lt;br /&gt;     access="org.hibernate.property.DirectPropertyAccessor" /&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Order.hbm.xml 中&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;  &amp;lt;id name="id" type="long" column="orderId" unsaved-value="null"&lt;br /&gt;  access="field"&amp;gt;&lt;br /&gt; &amp;lt;generator class="native" /&amp;gt;&lt;br /&gt;&amp;lt;/id&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;version name="version" access="org.hibernate.property.DirectPropertyAccessor" /&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;1. &amp;lt;id&amp;gt; 是专用元素，用来指定主键&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2. &amp;lt;version&amp;gt; 是Hibernate用来作优化处理的, 如果熟悉Hibernate 的 API 的话，会知道它有&lt;br /&gt;session.save(), session.update(), session().saveOrUpdate();而方法&lt;br /&gt;saveOrUpdate() 是方便调用端不用管这个对象是新建的还是前头已创建后这次只进行了更新；这个决定 Hibernate&lt;br /&gt;应该比我们更清楚，因此交给它去做吧。但这个更清楚是需有个前提的，这个前提即是 &amp;lt;version&amp;gt; 它联合 &amp;lt;id 元素的&lt;br /&gt;unsaved-value="null" 属性一起用来区分一个实体对象是新创建的还是已经持久化过后进行更新的。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3. &amp;lt;generator&amp;gt; 元素是指定这个主键产生的机制：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Hibernate 3.x manual&lt;/span&gt; 中 5.1.4.1&lt;br /&gt;Generator，(因为 Hibernate in action&lt;br /&gt;比较老，它没有明确地列出后续版本支持的机制，所以我们这里引用这个文档)有所有值的描述&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;我们之所以指定为 native，是因为我们这个演示项目建立在没有现在数据库的基础上，所以我们完全可以选择最好的机制产生主键。native&lt;br /&gt;会使用你指定的数据库方言来决定使用最适合这种数据库的机制。如：&lt;br /&gt;&lt;br /&gt;oracle 将会使用我们熟悉的 Sequence(Hibernate 会自动生成一个 hibernate_sequence,而所有被指定为&lt;br /&gt;native 的主键将从这个唯一的序列发生器中取出下一值来作为 id 的主键值），&lt;br /&gt;&lt;br /&gt;其它几种常用的数据库 Mysql，DB2 和 MS SQL Server 将会使用 identity&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;但是正如我前面提到的，项目建立在没有遗留数据的情况是罕见的！大多数项目不得不面对一大堆没有很好建立起约束关系，而且使用“自然主键”&lt;br /&gt;(natural primary key)作为主键，这与 Hibernate 的设计理念背道而驰。在Hibernate&lt;br /&gt;看来，主键只是用来唯一地标识这条数据行的，除些之外，不能再有其它含义，但现实中，往往出现&lt;br /&gt;SID(保险号，身份证号）等具有相应含义的列来作为数据库的主键，关于自然主键请参阅：&lt;br /&gt;&lt;br /&gt;&lt;h4 style="font-weight: normal;" class="title"&gt;3.4.3 Choosing primary keys&lt;/h4&gt;&lt;h4 style="font-weight: normal;" class="title"&gt;8.3.1 Legacy schemas and&lt;br /&gt;composite keys&lt;br /&gt;&lt;/h4&gt;&lt;br /&gt;我们说了，如果指定为 native 的机制的话，在初始化一个实体对象时，你根本不需要管这个 id 属性，也就是说你看到带有参数 id&lt;br /&gt;的构造函数，也不可能有setId(long id) 方法，因为hibernate 会生成且只生成一个序列发生器（对 oracle)&lt;br /&gt;，且用其中的值来应对所有的数据表，如：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;create sequence hibernate_sequence &lt;span style="font-weight: bold;"&gt;start with 1&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;初始化了第一个 Order,   则 orderId   = 1;&lt;br /&gt;&lt;br /&gt;初始化了第二个 Order,   则 orderId   = 2;&lt;br /&gt;&lt;br /&gt;初始化了第一个 Account, 则 accountId = 3;&lt;br /&gt;&lt;br /&gt;初始化了第二个 Account, 则 accountId = 4;&lt;br /&gt;&lt;br /&gt;初始化了第三个 Order，　则 orderId   = 5;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;这里存在几个问题首先每个表的主键不再是连续的，再值或多或少依赖于 start with 的值。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;在现实中，自然主键往往一般是连续的，且其长度都是受限的，比如身份证为 15 或　18 位。所以，对于已存在的数据库，只能使用机制 &lt;span style="font-weight: bold;"&gt;assign:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;dl&gt;&lt;dt style="font-weight: bold;"&gt;&lt;span class="term"&gt;&lt;tt class="literal"&gt;assigned&lt;/tt&gt;&lt;/span&gt;&lt;/dt&gt;&lt;dd&gt;&lt;p&gt; lets the application to assign an identifier to the object&lt;br /&gt;before &lt;tt class="literal"&gt;save()&lt;/tt&gt; is called. This is the default&lt;br /&gt;strategy if no &lt;tt class="literal"&gt;&amp;lt;generator&amp;gt;&lt;/tt&gt; element is&lt;br /&gt;specified. &lt;/p&gt;  &lt;/dd&gt;&lt;/dl&gt;这就是说，数据库主键是通过构造函数传进来的，然后这个实体通过调用 &lt;span style="font-family:monospace;"&gt;session.save(new&lt;br /&gt;abcEntity(abcId, ...)); 进行持久化的。此时， Hibernate&lt;br /&gt;将责任交给了你，程序员来做这件事，而且你也正想做这件事。不是吗？如果不这样你怎么来保证你的主键与数据期待的条件相符？。&lt;br /&gt;&lt;br /&gt;或者，如果你的实体对象只提供了默认构造函数，那么此时你必须提供一个 setId(...) 的方法，来给实体对象设置主键。&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;h4&gt;&lt;a name="6.4"&gt;&lt;/a&gt;其他映射&lt;/h4&gt;&lt;br /&gt;至于其它的与 java&lt;br /&gt;代码中的成员一一对应的映射，我想理解了上面的内容的话，应该不会有太多困难。所以请你们打开IDE一一对应着看，如果有不明白的就及时问问，我将乐意解答。&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;组件关系，如Account中对 userAddress 的映射：&amp;lt;component name="userAddr"&lt;br /&gt;...&amp;gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;实体生命周期的管理：父子关系，这也是UML中的强互合关系（如：人与胳膊的关系，人是需要负责胳膊的生命周期管理的，即人不存在了，胳膊也&lt;br /&gt;就不复存在了。）&lt;/li&gt;&lt;br /&gt;&lt;li&gt;映射类的继承关系&lt;/li&gt;&lt;br /&gt;&lt;li&gt;多对多关系&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h4&gt;&lt;a name="6.5"&gt;&lt;/a&gt;二级缓存映射&lt;/h4&gt;&lt;br /&gt;这一主题是我目前还未深入的，详情请见 &lt;span style="font-weight: bold;"&gt;Hibernate 3.xmanual&lt;/span&gt;　19.2. The Second Level Cache&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;最主要的是在映射中加上&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;cache usage="read-write"/&amp;gt;&lt;/pre&gt;&lt;br /&gt;或&lt;br /&gt;&lt;pre&gt;&amp;lt;cache usage="read-only/&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;或其它更高级的设置。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;read-only, 就是说实体对象被从数据库中取出后，不再会发生改变时，指定这个属性可以获得更好的性能。&lt;br /&gt;&lt;br /&gt;但如果需要改变时，你别无选择，必须指定 read-write.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;象这个项目中的与库存有关关的实体就是 read-only的，因为我们这个例子并没有包括后的库存管理功能，如果包含了的话，则Category/Inverntory/Product 等等可能也不能指定为read-only 了，因为它们也需要在管理后台中进行更新的。&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;h2&gt;&lt;span style="font-weight: bold;"&gt;&lt;a name="6.6"&gt;&lt;/a&gt;Hibernate 配置文件&lt;/span&gt;&lt;/h2&gt;Hibernate 的全局配置一般会在 Hibernate.cfg.xml 文件中，但我们这个项目使用了&lt;br /&gt;Spring, 所以它以Spring 的方式集成进来了，这就是 WEB_INF 下面的几个 dataAccessContext-&lt;br /&gt;开头的几个文件的内容，具体用哪个会在部署系列中详细介绍的。目前是用哪个，看 web.xml 中的定义：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;  &amp;lt;!--&lt;br /&gt;- Location of the XML file that defines the root application context.&lt;br /&gt;- Applied by ContextLoaderServlet.&lt;br /&gt;--&amp;gt;&lt;br /&gt;&amp;lt;context-param&amp;gt;&lt;br /&gt;&amp;lt;param-name&amp;gt;contextConfigLocation&amp;lt;/param-name&amp;gt;&lt;br /&gt;&amp;lt;!-- local datasource --&amp;gt;&lt;br /&gt;&amp;lt;param-value&amp;gt;&lt;br /&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;/WEB-INF/dataAccessContext-hibernate.xml /WEB-INF/applicationContext.xml&lt;/span&gt;&lt;br /&gt;&amp;lt;/param-value&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- jndi datasource and JTA (for a transactional JNDI DataSource)&lt;br /&gt;&amp;lt;param-value&amp;gt;&lt;br /&gt; /WEB-INF/dataAccessContext-hibernate-jndi.xml /WEB-INF/applicationContext.xml&lt;br /&gt;&amp;lt;/param-value&amp;gt;&lt;br /&gt;--&amp;gt;&lt;br /&gt;&amp;lt;/context-param&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;正如我单独列出一小结，我本想详细介绍一下这个文件的内容，但看了一下，如果仔细读了系列一的话，其实大部分内容已经提及过了，且　dataAccessContext-hibernate.xml文件的内容还算轻松。你们好好看看，看有问题否？&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;其实这个文件中只有以下几项内容，且其内容是一项项嵌套的：&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;dataSource 数据源的指定，除非你们公司有更好的实现，一般可能就会是 C3P0 了。它被 sessionFactory使用了&lt;/li&gt;&lt;br /&gt;&lt;li&gt;sessionFactory, 关键是它包含的&lt;br /&gt;&amp;lt;property&amp;gt;子元素，一一指定吧。其中指定了二级缓存的的提供者:hibernate.cache.provider_class。&lt;br /&gt;它被 transactionManager 和所有DAO使用了&lt;/li&gt;&lt;br /&gt;&lt;li&gt;transactionManager 事务管理器，管理所有从 &amp;lt;property&amp;gt; 中指定的&lt;br /&gt;sessionFactory 获得的 session 操作的事务&lt;/li&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;剩下就是所有 DAO 的配置了&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;h3&gt;&lt;a name="6.7"&gt;&lt;/a&gt;Ehcache&lt;/h3&gt;&lt;br /&gt;象我们的第二项中指定了二级缓存的提供者为:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;        &amp;lt;prop key="hibernate.cache.use_query_cache"&amp;gt;true&amp;lt;/prop&amp;gt;&lt;br /&gt;   &amp;lt;prop key="hibernate.cache.provider_class"&amp;gt;&lt;br /&gt;       org.hibernate.cache.EhCacheProvider&amp;lt;/prop&amp;gt;&lt;/pre&gt;&lt;br /&gt;那么默认情况下 EhCacheProvider 将会在 CLASSPATH 中寻找它的配置文件 ehcache.xml,&lt;br /&gt;一般情况下，它会放在源文件的包的根目录下，这就是在 netbeans 显示在Projects 中 Source Packages 下的&lt;br /&gt;&amp;lt;default package&amp;gt; 中的 ehcache.xml 文件。但如果 Ehcahe&lt;br /&gt;没有在类路径中找到配置文件，那么它会启动它的故障防护功能，会使用默认的配置ehcache-failsafe.xml，展开库（Projects&lt;br /&gt;中　hibernateJpetstore | libraries | encache-1.2.3.jar | 无名包 |&lt;br /&gt;ehcache-failsafe.xml).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;这个配置文件中的属性有：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;ehcache&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- Sets the path to the directory where cache .data files are created.&lt;br /&gt;&lt;br /&gt;    If the path is a Java System Property it is replaced by&lt;br /&gt;    its value in the running VM.&lt;br /&gt;&lt;br /&gt;    The following properties are translated:&lt;br /&gt;    user.home - User's home directory&lt;br /&gt;    user.dir - User's current working directory&lt;br /&gt;    java.io.tmpdir - Default temp file path --&amp;gt;&lt;br /&gt;&amp;lt;!--&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;指定缓存文件存放的目录&lt;/span&gt;&lt;br /&gt;在运行的服务器的 tmp 目录下，如：&lt;br /&gt;.netbeans\5.5dev\apache-tomcat-5.5.17_base\temp\ehcache&lt;br /&gt;--&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;diskStore path="java.io.tmpdir/ehcache"/&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!--Default Cache configuration. These will applied to&lt;br /&gt;      caches programmatically created through&lt;br /&gt;   the CacheManager.&lt;br /&gt;&lt;br /&gt;   The following attributes are required: &lt;span style="color: rgb(255, 0, 0);"&gt;(必须的选项)&lt;/span&gt;&lt;br /&gt;   - Sets the maximum number of objects that will be created in memory &lt;span style="color: rgb(255, 0, 0);"&gt;&lt;br /&gt;   - (最多多少个对象将被缓存在内存中)&lt;/span&gt;&lt;br /&gt;   maxElementsInMemory&lt;br /&gt;&lt;br /&gt;   - Sets whether elements are eternal.&lt;br /&gt;   - If eternal,  timeouts are ignored and the &lt;span style="color: rgb(255, 0, 0);"&gt;&lt;/span&gt;&lt;br /&gt;   eternal                    &lt;br /&gt;   &lt;br /&gt;   - Sets whether elements can overflow to disk when the in-memory cache&lt;br /&gt;   - has reached the maxInMemory limit. &lt;span style="color: rgb(255, 0, 0);"&gt;&lt;br /&gt;   - (是否将溢流的元素，即超过第一项配置的最大个数时，是否将元素写到硬盘中去？)&lt;/span&gt;                              &lt;span style="color: rgb(255, 0, 0);"&gt;&lt;/span&gt;&lt;br /&gt;   overflowToDisk             &lt;br /&gt;                                    &lt;span style="color: rgb(255, 0, 0);"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;   The following attributes are optional: &lt;span style="color: rgb(255, 0, 0);"&gt;(可选的选项)&lt;br /&gt;&lt;br /&gt;&lt;/span&gt; - Sets the time to idle for an element before it expires.&lt;br /&gt;    - i.e. The maximum amount of time between accesses before an element expires&lt;br /&gt;    - Is only used if the element is not eternal.&lt;br /&gt;    - Optional attribute. A value of 0 means that an Element can idle for infinity.&lt;br /&gt;    - The default value is 0.&lt;br /&gt;　　　 - &lt;span style="color: rgb(255, 0, 0);"&gt;(元素可以呆在内存中的最长的空闲时间，即两次访问之间的间隔，如果超过这个数，元素将过期，即从缓存中移走，&lt;/span&gt;&lt;br /&gt;    - &lt;span style="color: rgb(255, 0, 0);"&gt;下次再访问这个元素时，需从持久化存储中取出。仅对非外部化元素有效。默认为0，表示元素永不过期)&lt;br /&gt;&lt;/span&gt; timeToIdleSeconds &lt;span style="color: rgb(255, 0, 0);"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    - Sets the time to live for an element before it expires.&lt;br /&gt;    - i.e. The maximum time between creation time and when an element expires.&lt;br /&gt;    - Is only used if the element is not eternal.&lt;br /&gt;    - Optional attribute. A value of 0 means that and Element can live for infinity.&lt;br /&gt;    - The default value is 0.&lt;span style="color: rgb(255, 0, 0);"&gt;&lt;br /&gt;    - (元素在创建后多少秒后将被销毁, 默认为0，表示永远不销毁）&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;       timeToLiveSeconds&lt;br /&gt;&lt;br /&gt;   - Whether the disk store persists between restarts of the Virtual Machine.&lt;br /&gt;   - The default value is false.&lt;br /&gt;   -&lt;span style="color: rgb(255, 0, 0);"&gt;(在JVM重启时，是否将内存中的元素写到硬盘。默认为 false)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;&lt;/span&gt;       diskPersistent &lt;br /&gt;   &lt;br /&gt;   - The number of seconds between runs of the disk expiry thread. The default value&lt;br /&gt;   - is 120 seconds. &lt;span style="color: rgb(255, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(255, 0, 0);font-family:Arial;"  lang="EN-US"&gt;设定缓存在硬盘上的生存时间&lt;/span&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;)&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;&lt;/span&gt;&lt;br /&gt;   diskExpiryThreadIntervalSeconds&lt;span style="color: rgb(255, 0, 0);"&gt;&lt;/span&gt;&lt;br /&gt;   --&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;defaultCache&lt;br /&gt;maxElementsInMemory="10000"&lt;br /&gt;eternal="false"&lt;br /&gt;overflowToDisk="true"&lt;br /&gt;timeToIdleSeconds="120"&lt;br /&gt;timeToLiveSeconds="120"&lt;br /&gt;diskPersistent="false"&lt;br /&gt;diskExpiryThreadIntervalSeconds="120"/&amp;gt;&lt;br /&gt;&amp;lt;/ehcache&amp;gt;  &lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;上面这个文件指定的是默认配置，但如果要对某一实体进行特定的配置时，只需要追加一个元素，取名为该实体的名称即可。&lt;br /&gt;&lt;br /&gt;&amp;lt;cache name="&lt;span style="font-weight: bold;"&gt;org.springframework.samples.jpetstore.domain.Order&lt;/span&gt;"&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;maxElementsInMemory="10000"&lt;br /&gt;&lt;br /&gt;eternal="false" timeToIdleSeconds="300" timeToLiveSeconds="600"&lt;br /&gt;&lt;br /&gt;overflowToDisk="true" /&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;a name="7"&gt;&lt;/a&gt;总结&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;是的，要短时间内完全理解 O/R mapping&lt;br /&gt;是不容易的。但理解那怕一部分都有可能对今后的项目的ER（实体关系）有更清楚的认识，并设计出更加合理的数据层。&lt;br /&gt;&lt;br /&gt;其实，这些不光对 Hibernate 有用，对 EJB 实体 Bean, 对普通的JDBC的数据库建模也同样有效的。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;理解了最困难的部分，后续的系列将会简单多了。下一系列，控制层。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-3728988415692991792?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/3728988415692991792/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=3728988415692991792' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/3728988415692991792'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/3728988415692991792'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2006/08/hibernate-jpetstore.html' title='Hibernate Jpetstore 之二 数据层技术'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-1909959192221599449</id><published>2006-07-21T13:32:00.000+08:00</published><updated>2007-05-11T15:13:54.339+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate'/><title type='text'>Hibernate 字符类型映射 (Hibernate character/String mapping types)</title><content type='html'>&lt;span style="font-size:130%;"&gt;Oralce 数据库映射注意事项：&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;1. 如果数据库中的类型为 char(1), 则映射为 &lt;/span&gt;&lt;span class="term"&gt;&lt;tt class="literal"&gt;&lt;span style="font-weight: bold;"&gt;character 或 char&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;// SQL&lt;br /&gt;PUBLISHED char(1)&lt;br /&gt;&lt;br /&gt;// POJO java&lt;br /&gt;char published;&lt;br /&gt;&lt;br /&gt;// mapping&lt;br /&gt;&lt;/tt&gt;&lt;/span&gt;&amp;lt;property name="published" type="character"&amp;gt;&lt;br /&gt;   &amp;lt;column name="PUBLISHED" length="1" /&amp;gt;&lt;br /&gt;&amp;lt;/property&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;若映射成了 string 的话，在数据类型校验时会出错:&lt;br /&gt;&lt;span class="term"&gt;&lt;tt class="literal"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/tt&gt;&lt;/span&gt;&lt;span class="term"&gt;&lt;tt class="literal"&gt;// POJO java&lt;/tt&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="term"&gt;&lt;tt class="literal"&gt;String &lt;span style="font-family: courier new;"&gt;published;&lt;/span&gt;&lt;/tt&gt;&lt;/span&gt;&lt;span class="term"&gt;&lt;span style="font-family: courier new;" class="literal"&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;// mapping&lt;br /&gt;&lt;br /&gt;&amp;lt;property name="published" type="string"&amp;gt;&lt;br /&gt;   &amp;lt;column name="PUBLISHED" length="1" /&amp;gt;&lt;br /&gt;&amp;lt;/property&amp;gt;&lt;br /&gt;&lt;br /&gt;类似的错误输出为：&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;Wrong column type: PUBLISHED, expected: varchar2(1 char)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;      at org.hibernate.mapping.Table.validateColumns(Table.java:261)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;2. 如果为 varchar2(1), 则映射为 string&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="term"&gt;&lt;tt class="literal"&gt;// SQL&lt;/tt&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="term"&gt;&lt;tt class="literal"&gt;INCLUDES_SS_LIB varchar2(1)&lt;br /&gt;&lt;br /&gt;&lt;/tt&gt;&lt;/span&gt;&lt;span class="term"&gt;&lt;tt class="literal"&gt;// POJO java&lt;/tt&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="term"&gt;&lt;tt class="literal"&gt;String &lt;/tt&gt;&lt;span style="font-family: courier new;" class="literal"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;includedSsLib&lt;/span&gt;&lt;span class="term"&gt;&lt;span style="font-family: courier new;" class="literal"&gt;;   &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;// mapping&lt;br /&gt;&amp;lt;property name="includesSsLib" type="string"&amp;gt;&lt;br /&gt;   &amp;lt;column name="INCLUDES_SS_LIB" length="1" /&amp;gt;&lt;br /&gt;&amp;lt;/property&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;若映射成了 character 的话，在数据类型校验时会出错：&lt;br /&gt;&lt;span class="term"&gt;&lt;tt class="literal"&gt;&lt;/tt&gt;&lt;/span&gt;&lt;span class="term"&gt;&lt;tt class="literal"&gt;&lt;br /&gt;&lt;/tt&gt;&lt;/span&gt;&lt;span class="term"&gt;&lt;tt class="literal"&gt;// POJO java&lt;/tt&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; char includedSsLib&lt;/span&gt;&lt;span class="term"&gt;&lt;span style="font-family: courier new;" class="literal"&gt;;   &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;// mapping&lt;br /&gt;&lt;br /&gt;&amp;lt;property name="includesSsLib" type="character"&amp;gt;&lt;br /&gt;   &amp;lt;column name="INCLUDES_SS_LIB" length="1" /&amp;gt;&lt;br /&gt;&amp;lt;/property&amp;gt;&lt;br /&gt;&lt;br /&gt;类似的错误输出为：&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;Wrong column type: CHECKED, expected: char(1 char)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;      at org.hibernate.mapping.Table.validateColumns(Table.java:261)&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/171648533238476397-1909959192221599449?l=pprun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pprun.blogspot.com/feeds/1909959192221599449/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=171648533238476397&amp;postID=1909959192221599449' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/1909959192221599449'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/171648533238476397/posts/default/1909959192221599449'/><link rel='alternate' type='text/html' href='http://pprun.blogspot.com/2007/05/hibernate-hibernate-basic-mapping-types.html' title='Hibernate 字符类型映射 (Hibernate character/String mapping types)'/><author><name>P.P.Run</name><uri>http://www.blogger.com/profile/13581879314028219470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='23' src='http://1.bp.blogspot.com/_bpUunzIgcNA/SxFf5ES50yI/AAAAAAAAAS8/F1QrUKf2Mzk/S220/woniu.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-171648533238476397.post-4611755262851168553</id><published>2006-07-10T21:28:00.000+08:00</published><updated>2008-12-11T01:08:14.810+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate'/><title type='text'>Hibernate JPetstore 系列之一: 总体架构</title><content type='html'>&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;h2&gt;&lt;span style="font-size:100%;"&gt;文档内容&lt;/span&gt;&lt;/h2&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;概览&lt;/li&gt;&lt;br /&gt;&lt;li&gt;应用组件结构图&lt;/li&gt;&lt;br /&gt;&lt;li&gt;组件剖析&lt;br /&gt;&lt;/li&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;表示层&lt;br /&gt;&lt;/li&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;前端跳转首页&lt;/li&gt;&lt;br /&gt;&lt;li&gt;WEB安全目录&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Struts WEB应用基本配置&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;li&gt;控制层&lt;/li&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Spring (“春天”)来到&lt;/li&gt;&lt;br /&gt;&lt;li&gt;在 web.xml 文件中的配置&lt;/li&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;1. 应用上下文的机动性&lt;/li&gt;&lt;br /&gt;&lt;li&gt;2. Log4J 日志属性文件&lt;/li&gt;&lt;br /&gt;&lt;li&gt;3. Spring 的上下文配置文件位置&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;li&gt;Spring 上下文件配置&lt;/li&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;applicationContext.xml 门面的配置&lt;/li&gt;&lt;br /&gt;&lt;li&gt;属性占位符(placeholder) 配置&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;li&gt;Struts 控制层组件Action 访问 applicationContext.xml 配置的所有 Bean&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;li&gt;数据层&lt;/li&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;数据源及其所使用支持的连接池定义&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Hibernate 会话厂SessionFactory&lt;/li&gt;&lt;br /&gt;&lt;li&gt;hibernate.hbm2ddl.auto配置的值&lt;/li&gt;&lt;br /&gt;&lt;li&gt;JDBC 属性配置&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;h2&gt;概览&lt;/h2&gt;&lt;br /&gt;JPetstore原始的实现(来自于Spring 的 Sample) 包含了两个WEB表示层的实现，一个是 Struts, 另一个则是&lt;br /&gt;SpringMVC。我们主要介绍 基于Struts 的实现，因这种方案至少目前来说更普遍。&lt;br /&gt;另一方面，原版的DAO实现采用的是 iBatis, 同样是因为框架的采用率问题，我们将它移植成&lt;br /&gt;基于 Hibernate 的版本。 &lt;span style="font-weight: bold;"&gt;项目最终的源码将在系列结束时一并给出。&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;a name="arch_diagram"&gt;&lt;/a&gt;应用组件结构图&lt;/h3&gt;&lt;br /&gt;&lt;div style="text-align: right;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_bpUunzIgcNA/RkMqGKKBVuI/AAAAAAAAAAc/W81-qF_QN34/s1600-h/arch.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_bpUunzIgcNA/RkMqGKKBVuI/AAAAAAAAAAc/W81-qF_QN34/s400/arch.png" alt="" id="BLOGGER_PHOTO_ID_5062936691388536546" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;h2&gt;&lt;a name="components"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;组件剖析&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: right;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;h3&gt;&lt;a name="representation_tier"&gt;&lt;/a&gt;表示层&lt;/h3&gt;&lt;br /&gt;表示层一般也叫视图层，主要是用户接口。&lt;br /&gt;此应用是基于JSP 和标准标记库(JSTL)，以及Struts 的实现，主要包括：&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt; $hibernateJpetstore/web/WEB-INF/jsp/struts/ 目录下的所有文件, &lt;/li&gt;&lt;br /&gt;&lt;li&gt;前端自动跳转首页&lt;br /&gt;$hibernateJpetstore/web/index.jsp. (该目录下的 index.html 及 help.html&lt;br /&gt;是我用于测试的文件，产品时应该移除)&lt;/li&gt;&lt;br /&gt;&lt;li&gt; $hibernateJpetstore/web/WEB-INF/struts-config.xml 文件&lt;/li&gt;&lt;br /&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;这里有两个重要的概念：前端跳转首页和WEB安全目录。&lt;br /&gt;&lt;h4&gt;&lt;a name="front_redirection"&gt;&lt;/a&gt;前端跳转首页&lt;/h4&gt;前端跳转页是用来当你未指定具体的页面，而直接输入类似于 &lt;span class="blue"&gt;http://www.site.com/ 时能直接进入到网站的首页。&lt;br /&gt;&lt;/span&gt;&lt;div style="text-align: right;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;span class="921372908-18012007"&gt;&lt;h4&gt;&lt;a name="web_securet"&gt;&lt;/a&gt;WEB安全目录&lt;/h4&gt;&lt;br /&gt;&lt;div style="text-align: right;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;如果细心观察 struts-config.xml 文件，我们可以看到，大部分(其实是除了跳回首页的跳转)跳转的目的地都是位于&lt;br /&gt;/WEB-INF/ 目录下的JSP页面。根据Servlet 规范，这个目录是不能让用户直接访问的，比如在浏览器中直接输入&lt;br /&gt;http://localhost:8080/应用上下文/WEB-INF/abc.jsp，服务器是不能让用户直接查看此目录下的所有文件的。因为该目&lt;br /&gt;录是整个应用的配置的生死攸关的文件。不可以随便查看。&lt;br /&gt;但是，这些文件是可以由服务器端组件调用的。所以目前大部分的框架，特别是SpringMVC&lt;br /&gt;都是将它所控制的页面也一同放入到这个目录下，这样一来就避免了用户(或都恶意者)跳过应用的控制流程直接请求某个页面的危险，虽然，在每个页面中都可以&lt;br /&gt;进行某些逻辑判断，比如用户是否登录了。但是如果这一逻辑被新手忘记了的话，如果这个页面被放在与了首页所在的同一位置(即所谓的&lt;br /&gt;public-html) 目录下的话，这将是系统的安全漏洞了。&lt;br /&gt;所以之前的一些书上的所谓的 jarkata 目录方案其实是有缺陷的。(即我们的 NetBeans IDE中所默认生成的目录结构是有缺陷的)。&lt;br /&gt;&lt;pre&gt;&amp;lt;forward name="global-signon" path="/WEB-INF/jsp/struts/SignonForm.jsp"/&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;h4&gt;&lt;a name="struts_basic_setup"&gt;&lt;/a&gt;Struts WEB应用基本配置&lt;/h4&gt;&lt;br /&gt;&lt;div style="text-align: right;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;所以，对于基于 Struts 的WEB应用，表示层最基于的配置为：&lt;br /&gt;web.xml 文件：&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;指定 struts 的前端 Servlet, 及其的URL映射(即其的控制范围)&lt;/li&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;通过一个首页(或者一个链接)跳转到Struts 的管辖范围中。&lt;/li&gt;&lt;br /&gt;&lt;li&gt;WEB-INF/struts-config.xml 文件&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;关于表示层的详细介绍将会在后续的系列-- 表示层技术中介绍。比如： Struts 的 ActionForm 就是相当于 JSP +&lt;br /&gt;Javabeans 设计中的Javabeans, 因此，ActionForm 是属于 表示层的组件。&lt;br /&gt;&lt;h2&gt;&lt;a name="controller_tier"&gt;&lt;/a&gt;控制层&lt;/h2&gt;&lt;br /&gt;&lt;div style="text-align: right;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;控制层处在表示层与数据层之间的部分，其目的是为了使表示层与数据层脱耦(即表示层不能直接跟数据层通信--&lt;br /&gt;将用户提交的表单数据直接更新到数据层，数据层也不能在数据更新后直接通知表示层)。&lt;br /&gt;在 HibernateJpetstore 中，主要由以下几部分组成：&lt;br /&gt;(值得提前说明的是，由于Spring 框架是一个“粘合剂”，所以在我们的这个应用中，它跨越了控制层和数据层的配置，如果使用了SpringMVC&lt;br /&gt;的话，那么它将在应用的所有层中起作用。)&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;$hibernateJpetstore/src/org.springframework/samples/jpetstore/domain/logic/&lt;br /&gt;(我个人认为这个目录不应该放在 domain&lt;br /&gt;下，应该为$&lt;br /&gt;hibernateJpetstore/src/org.springframework/samples/jpetstore/logic,&lt;br /&gt;因为domain 是商业逻辑层范畴--&lt;br /&gt;一般为数据层的上层，但又不在控制层中，所以这样就出现了四层了，但如果严格按照MVC来划分的话，一般是把实体对象/领域对象 domain 规作&lt;br /&gt;数据层，因为它与DAO紧密相关的)&lt;/li&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;$hibernateJpetstore/src/org.springframework/samples/jpetstore/web/struts/&lt;br /&gt;目录下的所有 Action 的子类&lt;/li&gt;&lt;br /&gt;&lt;li&gt;$hibernateJpetstore/web/WEB-INF/struts-config.xml&lt;/li&gt;&lt;br /&gt;&lt;li&gt;$hibernateJpetstore/web/WEB-INF/applicationContext.xml&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;$hibernateJpetstore/web/WEB-INF/mail.properties&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;$hibernateJpetstore/src/org.springframework/samples/jpetstore/domain/logic/&lt;br /&gt;目录只有 PetStoreFacade.java, PetStoreImpl.java 和&lt;br /&gt;SendOrderConfirmationEmailAdvice.java 对我们有用，忽略其它文件，因为它们被用在 SpringMVC 中。&lt;br /&gt;PetStoreFacade.java, PetStoreImpl.java 分别为门面接口及其实现&lt;br /&gt;SendOrderConfirmationEmailAdvice.java 是一个 SpringAOP(面向方面) 的的一个&lt;br /&gt;Advice, 在Spring 的主配置文件 applicationContext.xml中指定在门面接口的&lt;br /&gt;PetStoreFacade.insertOrder() 方法成功调用后会调用此类的 afterReturning&lt;br /&gt;方法，此方法是向用户发一封定单确认邮件。&lt;br /&gt;struts-config.xml 即是 struts 的配置核心文件&lt;br /&gt;applicationContext.xml 是 Spring 的配置核心文件，正如前面所说，由于 Spring&lt;br /&gt;支持模块化配置，所以此文件并不包含所有的配置。&lt;br /&gt;mail.properties 邮件主机配置文件，因为在发邮件时需要 SMTP&lt;br /&gt;(简单邮件传输协议)服务，你们可能会象我当初一样问，为什么J2EE 不内置一个 SMTP服务器呢，如果是这样，我们又会想要&lt;br /&gt;POP/POP3服务器，协议有成千上万种，不可能在J2EE中包含一切。&lt;br /&gt;最后，我们看看Spring是怎样将这几部分“粘合”起来的：&lt;br /&gt;&lt;h3&gt;&lt;a name="spring_comming"&gt;&lt;/a&gt;Spring (“春天”)来到&lt;/h3&gt;&lt;br /&gt;&lt;div style="text-align: right;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;h4&gt;&lt;a name="settings_in_web.xml"&gt;&lt;/a&gt;在 web.xml 文件中的配置&lt;/h4&gt;&lt;br /&gt;&lt;div style="text-align: right;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;h5&gt;&lt;a name="flexibility_of_web_context"&gt;&lt;/a&gt;1. 应用上下文的机动性&lt;/h5&gt;&lt;br /&gt;&lt;div style="text-align: right;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;pre&gt;  &amp;lt;context-param&amp;gt;&lt;br /&gt;&amp;lt;param-name&amp;gt;webAppRootKey&amp;lt;/param-name&amp;gt;&lt;br /&gt;&amp;lt;param-value&amp;gt;petstore.root&amp;lt;/param-value&amp;gt;&lt;br /&gt;&amp;lt;/context-param&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;这个配置是将应用的上下文路径机动性的处理，也就是其位置是最终应用放置的位置，比如：如果最终应用部署到 Tomcat 中，如果Tomcat&lt;br /&gt;被装在&lt;br /&gt;D:\Tomcat\ 中，再假设应用的上下文被设置为 /hjpetstore 的话，则最终 petstore.root 的值为&lt;br /&gt;D:\Tomcat\webapps\hjpetstore\,&lt;br /&gt;这样一来，所有依赖这一位置的配置就有了一个相对的基础(我们都应该知道，文件的相对路径比绝对路径方便处理 )。比如应用的日志文件，因此在&lt;br /&gt;log4j 的配置文件(WEB-INF\log4j.properties)中有：&lt;br /&gt;&lt;pre&gt;log4j.appender.logfile.File=&lt;span style="color: rgb(255, 0, 0);"&gt;${petstore.root}&lt;/span&gt;/WEB-INF/petstore.log&lt;/pre&gt;&lt;br /&gt;这个配置指定了日志文件最终的位置，其实原版本不是这样的，我之所以这样配是在测试阶段方便，真实的产品环境可以考虑这样子，放在应用的一个专门的日志目&lt;br /&gt;录下：&lt;br /&gt;&lt;pre&gt;&lt;span class="921372908-18012007"&gt;&lt;span&gt;log4j.appender.logfile.File=${petstore.root}/log/petstore.log&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;h5&gt;&lt;a name="Log4J_properties_file"&gt;&lt;/a&gt;2. Log4J 日志属性文件&lt;/h5&gt;&lt;br /&gt;如下配置指定了 log4j 配置文件所在地：&lt;br /&gt;&lt;pre&gt;&amp;lt;context-param&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;param-name&amp;gt;log4jConfigLocation&amp;lt;/param-name&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;param-value&amp;gt;/WEB-INF/log4j.properties&amp;lt;/param-value&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/context-param&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;这个文件Spring 特有的，用于支持 log4j 的类，注意如果应用是配置到 JBoss 当中去的话，则不能在 web.xml&lt;br /&gt;中配置这个类，因为 JBoss 有自己的一套用于支持 log4j 的配置，如果&lt;br /&gt;在两个地方都指定，那么就会出现冲突。所以在使用 JBoss 时，就不需要这个配置了(注释掉，或者移除掉即可)&lt;br /&gt;&lt;pre&gt;  &amp;lt;listener&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;listener-class&amp;gt;&lt;br /&gt;org.springframework.web.util.Log4jConfigListener&amp;lt;&lt;br /&gt;/listener-class&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/listene&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;h5&gt;&lt;a name="spring_context_file_location"&gt;&lt;/a&gt;3. Spring 的上下文配置文件位置&lt;/h5&gt;&lt;br /&gt;&lt;div style="text-align: right;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;span class="921372908-18012007"&gt;&lt;br /&gt;&lt;pre&gt;  &amp;lt;context-param&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;param-name&amp;gt;contextConfigLocation&amp;lt;/param-name&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- local datasource --&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;param-value&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(255, 0, 0);"&gt;      /WEB-INF/dataAccessContext-hibernate.xml /WEB-INF/applicationContext.xml&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/param-value&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/context-param&amp;gt;&lt;span style="font-family:Georgia,serif;"&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;这里把应用的两个Spring 配置文件一同指定了，重要的是这个值一定是以 &lt;span style="font-weight: bold; color: rgb(255, 0, 0);"&gt;'/' &lt;/span&gt;开头，且多个文件间&lt;br /&gt;是以空格隔开的(不是以逗号分隔的).&lt;br /&gt;注意，有些地方也把 applicationContext.xml 文件叫做 Spring 根上下文配置文件，因为通常，如果Spring&lt;br /&gt;不是用在WEB环境下，则不可能有个 web.xml 文件，所以Spring通过只会在CLASSPATH 中找&lt;br /&gt;applicationContext.xml 文件，其它的配置文件是通过在 applicationContext.xml&lt;br /&gt;文件中导入的，如下语句：&lt;br /&gt;&lt;pre&gt;&amp;lt;import resource="dataAccessContext-hibernate.xml"/&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;h4&gt;&lt;a name="spring_context"&gt;&lt;/a&gt;Spring 上下文件配置&lt;/h4&gt;&lt;br /&gt;&lt;h5&gt;&lt;a name="facade_in_applicationContext.xml"&gt;&lt;/a&gt;applicationContext.xml&lt;br /&gt;门面的配置&lt;/h5&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;bean id="petStore" class="org.springframework.samples.jpetstore.domain.logic.PetStoreImpl"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;property name="accountDao" ref="accountDao"/&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;property name="categoryDao" ref="categoryDao"/&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;property name="productDao" ref="productDao"/&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;property name="itemDao" ref="itemDao"/&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;property name="orderDao" ref="orderDao"/&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h5&gt;&lt;a name="properties_placeholder"&gt;&lt;/a&gt;属性占位符(placeholder) 配置&lt;/h5&gt;&lt;br /&gt;属性占位符(placeholder) 定义，这样在后续的配置中就可以使用指定的属性文件(这里是，mail.properties 和&lt;br /&gt;jdbc.properties) 配置的 key=value 中的 ${key} 来得到属性的值。&lt;br /&gt;语法 &lt;span style="color: rgb(255, 0, 0);"&gt;${"jdbc.username"}&lt;/span&gt;&lt;br /&gt;的意思是使用属性 "jdbc.username" 的值(&lt;span style="color: rgb(255, 0, 0);"&gt;$ {...&lt;br /&gt;}&lt;/span&gt; 在规则表达式中总是&lt;span style="color: rgb(255, 0, 0);"&gt;“求值”&lt;/span&gt;的意思)，&lt;br /&gt;&lt;span class="921372908-18012007"&gt;&lt;br /&gt;&lt;pre&gt;  &amp;lt;!-- Configurer that replaces ${...} placeholders with values from properties files --&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- (in this case, mail and JDBC related properties) --&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;property name="locations"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;list&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;value&amp;gt;WEB-INF/mail.properties&amp;lt;/value&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;value&amp;gt;WEB-INF/jdbc.properties&amp;lt;/value&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/list&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/property&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;h4&gt;&lt;a name="Struts_Action_access_spring_bean"&gt;&lt;/a&gt;Struts 控制层组件Action&lt;br /&gt;访问&lt;br /&gt;applicationContext.xml 配置的所有 Bean&lt;/h4&gt;&lt;br /&gt;注意，Spring 是一个“粘合剂”角色，但如果为了引入 Spring 的功能，我们需要在&lt;br /&gt;表示层，控制层，或数据层做太多手脚的话，这样是不理想的，因为模块化的原则就是要尽量达到不让使用者知道自己的实现细节。在我们的应用中，的确有几个地&lt;br /&gt;方出现了 Spring 的类：&lt;br /&gt;在应用的所有 Action 的基类 BaseAction中 定义&lt;br /&gt;&lt;span class="921372908-18012007"&gt;&lt;br /&gt;&lt;pre&gt;import javax.servlet.ServletContext;&lt;br /&gt;&lt;br /&gt;import org.apache.struts.action.Action;&lt;br /&gt;import org.apache.struts.action.ActionServlet;&lt;br /&gt;&lt;br /&gt;import org.springframework.samples.jpetstore.domain.logic.PetStoreFacade;&lt;br /&gt;import org.springframework.web.context.WebApplicationContext;&lt;br /&gt;import org.springframework.web.context.support.WebApplicationContextUtils;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;&lt;br /&gt;* 我们在这个基类中得到了 Spring 定义的 WebApplicationContext (ApplicationContext的子类),&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt; * 有了它，就可以调用 getBean("传入配置文件中该Bean 的 ID"); 来获得 Bean 的实例. 这里我们只想&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt; * 获得门面的实现类，有了它就可以在此类的所有子类，即 XXXAction 中调用门面的方法进行DAO操作, 如下：&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt; * getPetStore().XXX()&lt;/span&gt;;&lt;br /&gt;*&lt;br /&gt;*&lt;br /&gt;* &amp;lt;p&amp;gt;另一种方法可以直接使用 Spring's 自带为 Struts 准备的 ActionSupport.&lt;br /&gt;* 有兴趣可以试一下。&lt;br /&gt;*&lt;br /&gt;*&lt;br /&gt;*/&lt;br /&gt;public abstract class BaseAction extends Action {&lt;br /&gt;&lt;br /&gt;private PetStoreFacade petStore;&lt;br /&gt;&lt;br /&gt;public void setServlet(ActionServlet actionServlet) {&lt;br /&gt;super.setServlet(actionServlet);&lt;br /&gt;if (actionServlet != null) {&lt;br /&gt;// fixed by pprun, must be synchronized&lt;br /&gt;synchronized (this) {&lt;br /&gt;ServletContext servletContext = actionServlet.getServletContext();&lt;br /&gt;WebApplicationContext wac =&lt;br /&gt;WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);&lt;br /&gt;this.petStore = (PetStoreFacade) wac.getBean("petStore"); &lt;span style="color: rgb(255, 0, 0);"&gt;// 门面 Bean 在 applicationContext.xml 文件中的 id="petStore"&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;protected PetStoreFacade getPetStore() {&lt;br /&gt;return petStore;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;关于控制层的详细介绍将会在后续的系列-- 控制层技术中介绍&lt;br /&gt;&lt;h2&gt;&lt;a name="data_tier"&gt;&lt;/a&gt;数据层&lt;/h2&gt;&lt;br /&gt;&lt;div style="text-align: right;"&gt;&lt;small&gt;&lt;br /&gt;&lt;/small&gt;&lt;/div&gt;&lt;br /&gt;数据层，有些书上偶尔把商业逻辑层与之混淆在一起，因为商业实体(或者叫领域对象 Domail)通过是与数据库中的表存在着很紧密的联系的。&lt;br /&gt;在此应用中，由以下几部分组成：&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;$hibernateJpetstore/src/org.springframework/samples/jpetstore/dao/&lt;/li&gt;&lt;br /&gt;&lt;li&gt;$hibernateJpetstore/src/org.springframework/samples/jpetstore/domain/&lt;/li&gt;&lt;br /&gt;&lt;li&gt;$hibernateJpetstore/src/org.springframework/samples/jpetstore/dao.hibernate/&lt;/li&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;$hibernateJpetstore/web/WEB-INF/applicationContext.xml &lt;/li&gt;&lt;br /&gt;&lt;li&gt;$hibernateJpetstore/web/WEB-INF/dataAccessContext-hibernate.xml &lt;/li&gt;&lt;br /&gt;&lt;li&gt;$hibernateJpetstore/web/WEB-INF/jdbc.properties&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;$hibernateJpetstore/src/org.springframework/samples/jpetstore/dao/&lt;br /&gt;包中定义的所有DAO接口(每个接口所支持的增、删、改、查方法)&lt;br /&gt;$hibernateJpetstore/src/org.springframework/samples/jpetstore/domain/&lt;br /&gt;包中定义的是商业实体对象及每个对象的 hbm.xml 文件&lt;br /&gt;$hibernateJpetstore/src/org.springframework/samples/jpetstore/dao.hibernate/&lt;br /&gt;是采用 Hibernate 实现的DAO接口&lt;br /&gt;$hibernateJpetstore/web/WEB-INF/dataAccessContext-hibernate.xml&lt;br /&gt;数据访问层的属性配置(Spring 上下文配置的一部分)，由于DAO实现是采用 hibernate 实现的，所以这里还包括了传统的&lt;br /&gt;Hibernate.cfg.xml 及所有实体的 hbm.xml 文件的配置：&lt;br /&gt;&lt;h3&gt;&lt;a name="datasource"&gt;&lt;/a&gt;数据源及其所使用支持的连接池定义&lt;/h3&gt;&lt;br /&gt;&lt;div style="text-align: right;"&gt;&lt;small&gt;&lt;br /&gt;&lt;/small&gt;&lt;/div&gt;&lt;br /&gt;这里采用的局部的(local)连接池框架是 &lt;a href="http://www.mchange.com/projects/c3p0/"&gt;C3P0&lt;br /&gt;&lt;br /&gt;&lt;/a&gt;, (此外还有类似的连接池框架，如 Apache Commons &lt;a href="http://jakarta.apache.org/commons/dbcp/"&gt;DBCP&lt;/a&gt;)，之所以称之为局部的，是因为它&lt;br /&gt;不依赖于特定的应用服务器所支持的内置的连接池实现(每个应用服务器都有自已的对数据库的连接方案)，那个连接池一般叫做 JNDI&lt;br /&gt;数据源，因为在应用服务器启动后，会将配置的所有数据源(当然还包含其他对象)把它们存放到 JNDI( Java Name Directory&lt;br /&gt;Interface, Java 名称目录接口，相当于注册表，用于存入全局配置信息)中供部署的应用使用。&lt;br /&gt;&lt;span class="921372908-18012007"&gt;&lt;br /&gt;&lt;pre&gt; &amp;lt;bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"&amp;gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;&amp;lt;!-- 以下配置都是使用 jdbc.properties 属性文件中的配置，而之所以可以这样写，就是因为有 属性占位符配置的原因 --&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;lt;property name="driverClass" value="${jdbc.driverClassName}"/&amp;gt;&lt;br /&gt;&amp;lt;property name="jdbcUrl" value="${jdbc.url}"/&amp;gt;&lt;br /&gt;&amp;lt;property name="user" value="${jdbc.username}"/&amp;gt;&lt;br /&gt;&amp;lt;property name="password" value="${jdbc.password}"/&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;&amp;lt;!-- 连接池维持的最小的连接个数 --&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;lt;property name="minPoolSize" value="5"/&amp;gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;&amp;lt;!-- 连接池维持的最大的连接个数 --&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;lt;property name="maxPoolSize" value="20"/&amp;gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;&amp;lt;!-- 最大空闲时间, 当某个连接在这个时间内没活动后将从池中移除，前提是池中至少多于最少的连接数: minPoolSize --&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;lt;property name="maxIdleTime" value="1800"/&amp;gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;&amp;lt;!-- 为加强准备语句的执行性能，此参数指定被缓存的 PreparedStatement 的个数 --&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;lt;property name="maxStatements" value="50"/&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;这些属性在下面的 jdbc.properties 文件中指定。&lt;br /&gt;&lt;h3&gt;&lt;a name="Hibernate_SessionFactory"&gt;&lt;/a&gt;Hibernate 会话厂 SessionFactory&lt;/h3&gt;&lt;br /&gt;&lt;div style="text-align: right;"&gt;&lt;small&gt;&lt;br /&gt;&lt;/small&gt;&lt;/div&gt;&lt;br /&gt;Session 就是用于每次与数据库会话的，因此需要：&lt;br /&gt;数据库的配置参数，这些参数就是 上面的数据源指定的! 因此我们只需引用即可：&lt;span style="font-family:monospace;"&gt; ref="dataSource"；&lt;br /&gt;实体映射配置&lt;br /&gt;hibernate.cfg.xml 配置&lt;br /&gt;结果缓存配置(这里使用的是开源的 ehcache)&lt;br /&gt;&lt;/span&gt;&lt;span class="921372908-18012007"&gt;&lt;br /&gt;&lt;pre&gt;  &amp;lt;!-- Hibernate SessionFactory --&amp;gt;&lt;br /&gt;&amp;lt;bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"&amp;gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;&amp;lt;!-- 引用前面定义的数据源 --&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;lt;property name="dataSource" ref="dataSource"/&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;&amp;lt;!-- 所有实体映射文件列表, 所有的 hbm.xml 文件 --&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;lt;property name="mappingResources"&amp;gt;&lt;br /&gt;&amp;lt;list&amp;gt;&lt;br /&gt;&amp;lt;value&amp;gt;org/springframework/samples/jpetstore/domain/Account.hbm.xml&amp;lt;/value&amp;gt;&lt;br /&gt;&amp;lt;value&amp;gt;org/springframework/samples/jpetstore/domain/Banner.hbm.xml&amp;lt;/value&amp;gt;&lt;br /&gt;&amp;lt;value&amp;gt;org/springframework/samples/jpetstore/domain/Category.hbm.xml&amp;lt;/value&amp;gt;&lt;br /&gt;&amp;lt;value&amp;gt;org/springframework/samples/jpetstore/domain/Inventory.hbm.xml&amp;lt;/value&amp;gt;&lt;br /&gt;&amp;lt;v
