﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-Terry的Blog-随笔分类-转载</title><link>http://www.blogjava.net/terry-zj/category/5774.html</link><description>&lt;script src="http://www.google-analytics.com/urchin.js" type="text/javascript"&gt;
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
_uacct = "UA-285051-1";
urchinTracker();
&lt;/script&gt;
</description><language>zh-cn</language><lastBuildDate>Thu, 30 Aug 2007 16:53:57 GMT</lastBuildDate><pubDate>Thu, 30 Aug 2007 16:53:57 GMT</pubDate><ttl>60</ttl><item><title>sourceforge Top 25 Projects</title><link>http://www.blogjava.net/terry-zj/archive/2007/08/30/141531.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Thu, 30 Aug 2007 13:52:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2007/08/30/141531.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/141531.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2007/08/30/141531.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/141531.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/141531.html</trackback:ping><description><![CDATA[&nbsp;1. Azureus<br>https://sourceforge.net/projects/azureus<br>Azureus is a powerful, full-featured, cross-platform bittorrent client.<br><br>2. phpMyAdmin<br>https://sourceforge.net/projects/phpmyadmin<br>phpMyAdmin is a tool written in PHP intended to handle the<br>administration of MySQL over the Web. Currently it can create and drop<br>databases, create/drop/alter tables, delete/edit/add fields, execute any<br>SQL statement, manage keys on fields.<br><br>3. Notepad++<br>https://sourceforge.net/projects/notepad-plus<br>Notepad++ is a generic source code editor (it tries to be anyway) and<br>Notepad replacement written in C++ with the win32 API. The aim of<br>Notepad++ is to offer a slim and efficient binary with a totally<br>customizable GUI.<br><br>4. OpenProj - Project Management<br>项目管理<br>https://sourceforge.net/projects/openproj<br>OpenProj by Projity is a desktop replacement of Microsoft Project.<br>OpenProj has equivalent functionality, a familiar user interface and<br>even opens existing MSProject files. OpenProj is interoperable with<br>Project, with a Gantt Chart and PERT chart etc.<br><br>5. ZK - Simply Ajax and Mobile<br>小型 AJAX html/xul 应用<br>https://sourceforge.net/projects/zk1<br>ZK is Ajax framework enriching Web apps with little programming. With<br>event-driven and markup languages, development is as simple as<br>programming desktops and authoring HTML/XUL pages. ZK supports scripting<br>lang including Java, JavaScript, Ruby, Groovy...<br><br>6. dimdim meeting server<br>视频会议<br>https://sourceforge.net/projects/dimdim<br>Dimdim is an open source web meeting product with features like<br>Application, Desktop and Presentation sharing with A/V streaming and<br>chat. No attendee installation - all features are available through a<br>web browser. Dimdim can be integrated with Moodle.<br><br>7. ADempiere Bazaar<br>CRM等<br>https://sourceforge.net/projects/adempiere<br>Adempiere is an ERP Bazaar for Open Source Developers that contribute<br>improvements of Compiere, CRM, Shopfloor, POS, Helpdesk, Financials<br>Accounting, Supply Chain, Knowledge and Business apps in an open and<br>unabated fashion. Focus is on the Community.<br><br>8. Zenoss Core - Enterprise IT Monitoring<br>网关软件<br>https://sourceforge.net/projects/zenoss<br>Zenoss Core is an enterprise network and systems management application<br>written in Python/Zope. Zenoss provides an integrated product for<br>monitoring availability, performance, events and configuration across<br>layers and across platforms.<br><br>9. Openbravo ERP<br>ERP软件<br>https://sourceforge.net/projects/openbravo<br>Web based ERP for SMEs, built on proven MVC &amp; MDD framework that<br>facilitate customization &amp; maintenance of code. Already in production,<br>it encompasses a broad range of functionalities such as finance, supply<br>chain, project mgmt, manufacturing &amp; much more<br><br>10. FreeCol<br>扑克游戏<br>https://sourceforge.net/projects/freecol<br>FreeCol is an open version of Colonization. It is a Civilization-like<br>game in which the player has to conquer the new world.<br><br>11. FileZilla<br>https://sourceforge.net/projects/filezilla<br>FileZilla is a fast FTP and SFTP client for Windows with a lot of<br>features. FileZilla Server is a reliable FTP server.<br><br>12. WebCalendar<br>https://sourceforge.net/projects/webcalendar<br>WebCalendar is a PHP application used to maintain a calendar for a<br>single user or an intranet group of users. It can also be configured as<br>an event calendar.<br><br>13. PhpGedView<br>???<br>https://sourceforge.net/projects/phpgedview<br>PhpGedView parses GEDCOM 5.5 genealogy files and displays them on the<br>internet in formats and charts that you are familiar with.It also allows<br>relatives to edit their genealogy online and collaborate together on<br>their research.<br><br>14. MediaInfo<br>多媒体管理<br>https://sourceforge.net/projects/mediainfo<br>Get technical information and tags of a lot of multimedia files.<br>Supported formats : - Video : AVI/OGM/MKV/MPG/VOB/MP4/3GP/... - Audio :<br>MP3/OGG/MKA/MP4/AAC/...<br><br>15. 7-Zip<br>https://sourceforge.net/projects/sevenzip<br>7-Zip is a file archiver with the high compression ratio. The program<br>supports 7z, ZIP, CAB, RAR, ARJ, LZH, CHM, GZIP, BZIP2, Z, TAR, CPIO,<br>RPM and DEB formats. Compression ratio in the new 7z format is 30-50%<br>better than ratio in ZIP format.<br><br>16. KeePass Password Safe<br>密码保存工具（windows）<br>https://sourceforge.net/projects/keepass<br>KeePass Password Safe is a free, open source, light-weight and<br>easy-to-use password manager for Windows. You can store your passwords<br>in a highly-encrypted database, which is locked with one master password<br>or key file.<br><br>17. MinGW - Minimalist GNU for Windows<br>GCC编程工具（windows）<br>https://sourceforge.net/projects/mingw<br>MinGW: A native Win32 port of the GNU Compiler Collection (GCC), with<br>freely distributable import libraries and header files for building<br>native Windows applications; includes extensions to the MSVC runtime to<br>support C99 functionality.<br><br>18. XOOPS Dynamic Web CMS<br>https://sourceforge.net/projects/xoops<br>XOOPS is a dynamic web content management system written in PHP for the<br>MySQL database. Its object orientation makes it an ideal tool for<br>developing small or large community websites, intra company and<br>corporate portals, weblogs and much more.<br><br>19. FreeMind<br>知识和内容管理工具<br>https://sourceforge.net/projects/freemind<br>A mind mapper, and at the same time an easy-to-operate hierarchical<br>editor with strong emphasis on folding. These two are not really two<br>different things, just two different descriptions of a single<br>application. Often used for knowledge and content mgmt.<br><br>20. Arianne RPG<br>RPG游戏<br>https://sourceforge.net/projects/arianne<br>Arianne is a multiplayer online engine to develop turn based and real<br>time games providing a simple way of creating the game server rules and<br>clients like Stendhal. Marauroa, our server, uses Java and MySQL for<br>hosting hundreds of players on a solo host.<br><br>21. OrangeHRM - Human Resource Management<br>人力资源管理<br>https://sourceforge.net/projects/orangehrm<br>OrangeHRM developed by OrangeHRM Inc is an Open Source HR Information<br>Systems(HRIS) that assists you in managing company's human resources.<br>Through scalable modular architecture it covers main areas of Personnel<br>Management/HRM such as PIM, ESS &amp; Leave.<br><br>22. Gallery<br>https://sourceforge.net/projects/gallery<br>A slick, intuitive web based photo gallery. Gallery is easy to install,<br>configure and use. Gallery photo management includes automatic<br>thumbnails, resizing, rotation, and more. Authenticated users and<br>privileged albums make this great for communities.<br><br>23. Pidgin<br>https://sourceforge.net/projects/pidgin<br>Pidgin is a GTK+ instant messaging application for Windows and Unix. It<br>supports AIM, ICQ, Jabber/XMPP, MSN, Yahoo!, Bonjour, Gadu-Gadu, IRC,<br>QQ, SILC, SIMPLE and more. See http://pidgin.im.sixxs.org/about.php for more<br>information.<br><br>24. XBMC (Xbox Media Center)<br>Xbox软件<br>https://sourceforge.net/projects/xbmc<br>XBMC (Xbox Media Center) is a free multimedia player jukebox for<br>Microsoft Xbox game console, it is capable of playing back almost all<br>known video, audio and picture formats from the Xbox harddrive, DVD-ROM<br>drive, a local-network, and even the internet.<br><br>25. JasperReports - Java Reporting<br>java 分析工具<br>https://sourceforge.net/projects/jasperreports<br>JasperReports, the market leading open source business intelligence and<br>reporting engine. This project is being moved to<br>http://www.jasperforge.org.sixxs.org/. This project is the home for all things<br>Jasper, Reports, Analysis, Server, and Intelligence.<br><br><br>http://www.newsmth.net/bbscon.php?bid=99&amp;id=1138814<img src ="http://www.blogjava.net/terry-zj/aggbug/141531.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2007-08-30 21:52 <a href="http://www.blogjava.net/terry-zj/archive/2007/08/30/141531.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转发(forward)、包含(include)及转向(redirect)的区别与联系</title><link>http://www.blogjava.net/terry-zj/archive/2006/10/11/74530.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Wed, 11 Oct 2006 05:41:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2006/10/11/74530.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/74530.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2006/10/11/74530.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/74530.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/74530.html</trackback:ping><description><![CDATA[forward,include,redirect是jsp中web页面(jsp或servelt)的三种不同的路由关系，三个貌似相同，其实还是有许多差别的，而了解这些细微的差别，在web开发中是很重要的。<br />说明：<br />一、forward、include由javax.servlet.RequestDispatcher来封装,由包容器container提供RequestDispatcher接口的实现，其中声明如下：<br />void forward(ServletRequest req,ServletResponse res)<br />void include(ServeltRequest req,ServletResponse res)<br />可以通过两种方式得到RequestDispatcher:<br />1、ServletContext.getRequestDispatcher(String path);<br />其中这里的path必须开始为"/"，即这里的path必须相对于context的root.<br />2、ServeltRequest.getRequestDispatcher(String path)<br />这里的path可以为相对路径,如果path开始为"/",则也认为是从context的root开始的。<br />二、Redirect由HttpServletResponse.sendRedirect(String location)来支持<br />差别：<br />三个都可以对用户的request进行转发，但是还是有许多的不同，差别最主要集中在如下几个方面：<br />1、forward与include共亨Request范围内的对象,而redirect则不行，即：如果一个javabean被声明为request范围的话，则被forward到的资源也可以访问这个javabean,而redriect则不行。<br />2、forward与include基本上都是转发到context内部的资源，而redirect可以重定向到外部的资源,如： req.sendRedriect("<a href="http://www.mocuai.com">http://www.mocuai.com</a>");<br /><br />以上来源 <a href="http://www.cn-java.com/target/news.php?news_id=3176">http://www.cn-java.com/target/news.php?news_id=3176</a><br /><br />充<br />struts-config.xml <br />&lt;forward name="succ"  path="/pages/dynabean2.jsp" <font style="BACKGROUND-COLOR: #ff0000">redirect="true"</font>/&gt;<br />设置redirect="true"后 转向目标页面时效果和redirect一致。<br /><img src ="http://www.blogjava.net/terry-zj/aggbug/74530.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2006-10-11 13:41 <a href="http://www.blogjava.net/terry-zj/archive/2006/10/11/74530.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Web IM</title><link>http://www.blogjava.net/terry-zj/archive/2006/10/10/74375.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Tue, 10 Oct 2006 12:45:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2006/10/10/74375.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/74375.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2006/10/10/74375.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/74375.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/74375.html</trackback:ping><description><![CDATA[
		<p> meebo    <a href="http://ebuddy.com/#BETA">http://</a><a href="http://www.meebo.com">www.meebo.com</a><br />比较早的Web IM,支持AIM、ICQ、Yahoo! Messenger、Jabber、Gtalk和MSN。 </p>
		<p>ebuddy    <a href="http://ebuddy.com/#BETA">http://ebuddy.com/#BETA</a><br />支持MSN、Yahoo、AIM，提供Wap登陆。 </p>
		<p>Web QQ    <a href="http://webqq.qq.com/">http://webqq.qq.com/</a><br />QQ 的 Web IM，已经可以使用了。 </p>
		<p>mabber    <a href="http://www.mabber.com/">http://www.mabber.com/</a><br />Beta中,支持AIM、ICQ、Yahoo! Messenger、Jabber、Gtalk和MSN，速度比较慢。 </p>
		<p>AIM    <a href="http://www.aim.com/get_aim/express/aim_expr.adp">http://www.aim.com/get_aim/express/aim_expr.adp</a><br />AIM自己的Web IM。 </p>
		<p>MSN    <a href="http://webmessenger.msn.com/">http://webmessenger.msn.com/</a><br />Microsoft 自己的Web IM。 </p>
		<p>ICQ    <a href="http://www.icq.com/download/icq2go/">http://www.icq.com/download/icq2go/</a><br />ICQ开发的的ICQ Web IM。 </p>
		<p>koolim    <a href="http://www.koolim.com/">http://www.koolim.com/</a><br />支持AIM、ICQ、Yahoo! Messenger、Jabber、Gtalk、MSN。 <br />imhaha    <a href="http://www.imhaha.com/">http://www.imhaha.com/</a><br />支持QQ哟，另外还支持MSN、Yahoo!Messenger，AIM。<br /> <br />radiusim    <a href="http://www.radiusim.com/">http://www.radiusim.com/</a><br />支持AIM、Yahoo messager!、MSN、Gtalk。</p>
<img src ="http://www.blogjava.net/terry-zj/aggbug/74375.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2006-10-10 20:45 <a href="http://www.blogjava.net/terry-zj/archive/2006/10/10/74375.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>AMV问题大全 (转载http://www.hao3gp.com/v_46520.html)</title><link>http://www.blogjava.net/terry-zj/archive/2006/07/20/59165.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Thu, 20 Jul 2006 05:03:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2006/07/20/59165.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/59165.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2006/07/20/59165.html#Feedback</comments><slash:comments>30</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/59165.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/59165.html</trackback:ping><description><![CDATA[
		<p>问题1：什么是AMV视频<br />回答：AMV是MP3/MP4上播放的一种视频格式。AMV格式具有较高压缩比例以及画面质量。通过AMV转换工具转换出来的影音文件一分钟的容量约为1.8MB。你可以通过察看自己的MP3/MP4产品说明书来知道自己的机器是否支持AMV视频格式。</p>
		<p> </p>
		<p>问题2：我的MP3能看多大的AMV<br />回答：MP3/MP4的屏幕大小尺寸如下：<br />1.0英寸 屏幕大小96×64<br />1.1英寸 屏幕大小96×64 <br />1.2英寸 屏幕大小160×128<br />1.3英寸 屏幕大小160×128<br />1.5英寸 屏幕大小128×128<br />1.8英寸 屏幕大小128×160<br />目前市场上最常见的是1.5英寸和1.8英寸的MP3/MP4。<br />MP3/MP4只能播放比自己屏幕尺寸小的AMV视频，例如1.8寸的就可以播放96×64、128×96、160×120的视频。而1.5寸的则无法播放160×120的AMV视频。</p>
		<p> </p>
		<p>问题3：为什么我的AMV不能满屏播放<br />回答：我们先来看下MP3/MP4的屏幕大小：<br />1.5寸屏幕是128×128也就是1:1<br />1.8寸屏幕是160×128也就是5:4<br />而我们知道，大部分的视频的标准比例是4:3，而宽屏电影是16:9。这就是为什么我们看宽屏电影会有上下两条黑色的遮幅。<br />这样问题就清楚了，所有下载的视频都是4:3的标准比例，于是放到1.5寸的机器里就是128×96；而放到1.8寸机器里就是160×120，看起来就不是满屏了。如果下载的是宽屏电影的话，则上下会被遮挡的更多。</p>
		<p> </p>
		<p>问题4：为什么我看128×128满屏会感觉画面不全<br />回答：128×128的视频虽然看起来是满屏的，但其实是在170×128的视频上切割而成的，于是视频在宽度上就会别截掉很多。看起来是满屏的，其实是看不到全画面的。</p>
		<p> </p>
		<p>
				<br />问题5：为什么我播放一半会提示格式错误<br />回答：因为现在MP3/MP4采用的解码芯片各不相同，而压制出来的AMV并不能保证兼容所有的MP3/MP4机器。因此可能会出现播放一半提示错误的问题。</p>
		<p> </p>
		<p>
				<br />问题6：怎么制作AMV<br />回答：如何制作AMV请参阅：<a href="http://www.go2tv.net/read.php?tid-1892.html">http://www.go2tv.net/read.php?tid-1892.html</a></p>
		<p> </p>
		<p>
				<br />问题7：为什么我制作RMVB时出错了<br />回答：视频的转换本来就是很复杂的一件事情。各种视频有着各种各样不同的视频音频编码（可参见<a href="http://www.go2tv.net/read.php?tid-215.html">http://www.go2tv.net/read.php?tid-215.html</a>）。要转换RMVB就必须要有RMVB的解码程序，需要安装real的解码器。但是有时虽然两个文件是同一个视频格式例如RMVB但其实它们采用的视频编码可能是完全不同的，所以有的RMVB能够顺利的转成AMV，有的就不行！<br />对于不能转的RMVB，有一个方法是先把它转成3GP再转到AMV。</p>
		<p> </p>
		<p>
				<br />问题8：为什么我转换AMV时提示磁盘已满<br />回答：AMV转换精灵在使用过程中有一个很奇怪的BUG！在转换较大的文件时会提示磁盘已满！<br />这个需要安装AMV转换精灵的那个磁盘空间大于4G！</p>
		<p> </p>
		<p>
				<br />问题9：为什么我下载的AMV文件是RAR文档<br />回答：不知道什么原因，在有些朋友的机器上AMV文件会被关联到RAR文件上。双击后会调用WINRAR打开。解决方式是改变AMV文件的关联，关联到AMV播放器即可。或者每次都用AMV播放器来打开，而不是用双击！</p>
		<p> </p>
		<p>
				<br />问题10：为什么在电脑上不能看AMV文件<br />回答：电脑上要看AMV文件需要特殊的播放软件－AMV播放器！<br />可以在：<a href="http://www.go2tv.net/read.php?tid-1892.html">http://www.go2tv.net/read.php?tid-1892.html</a> 下载到转换器和播放器</p>
		<p> </p>
		<p>
				<br />问题11：哪里有AMV制作工具下载<br />回答：可以在：<a href="http://www.go2tv.net/read.php?tid-1892.html">http://www.go2tv.net/read.php?tid-1892.html</a> 下载到转换器和播放器以及有详细教程</p>
		<p> </p>
		<p>
				<br />问题12：能不能把128×96 AMV转换成160×120的AMV<br />回答：AMV转换工具不支持AMV格式作为源文件，也就是无法从AMV转换到AMV。</p>
		<p> </p>
		<p>问题13：为什么我的视频文件转成AMV后大了很多啊<br />回答：视频文件的大小是由它的编码率来决定的，相同时间长度的视频有越高的kbps就会有越大的文件。而AMV转换工具默认的图像品质是middle，它的编码率比较高，如果选择high就会更高。同时还因为AMV压缩算法的不同，以及声音编码的不同，所以会造成AMV文件比源文件要大的结果。</p>
		<p> </p>
		<p>问题14：我转换出来的AMV文件上下颠倒，怎么办啊？<br />回答：找到 AMVConverter的安装目录进入，打开 AmvTransform.ini 文件（可用window自带的记事本打开），找到BMPADJUST字段并修改。<br />BMPADJUST，对应的意义如下：<br />BMPADJUST=0 - 正常<br />BMPADJUST=1 - 画面垂直翻转<br />BMPADJUST=2 - 画面水平翻转<br />BMPADJUST=3 - 画面180 度旋转<br />BMPADJUST=4 - 画面顺时针 90 度旋转<br />BMPADJUST=5 - 画面逆时针 90 度旋转<br />修改后保存退出，重新启动AMVConverter即可。</p>
		<p> </p>
		<p>问题15：哪里有1.8寸160×120的AMV制作工具下载<br />回答：160×120转换器下载：<a href="http://www.go2tv.net/read.php?tid-3792.html">http://www.go2tv.net/read.php?tid-3792.html</a></p>
		<p> </p>
		<p>
				<br />问题16：如何在AMV里加入大一些的字幕？<br />回答：AMV转换工具是无法加载字幕的。想要在AMV中加载大字幕，只有通过两次转换的方式。可以给影片加载字幕的软件很多，例如可以先使用EO VIDEO，Easy RealMedia Producer，SmartMovie Converter等工具为源文件加上大的字幕！再用AMV转换工具把加了大字幕的源文件转换成AMV文件</p>
<img src ="http://www.blogjava.net/terry-zj/aggbug/59165.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2006-07-20 13:03 <a href="http://www.blogjava.net/terry-zj/archive/2006/07/20/59165.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>学习spring的好站</title><link>http://www.blogjava.net/terry-zj/archive/2006/07/07/57215.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Fri, 07 Jul 2006 15:48:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2006/07/07/57215.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/57215.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2006/07/07/57215.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/57215.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/57215.html</trackback:ping><description><![CDATA[http://www.javaworld.com.tw/confluence/display/opensrc/Spring<img src ="http://www.blogjava.net/terry-zj/aggbug/57215.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2006-07-07 23:48 <a href="http://www.blogjava.net/terry-zj/archive/2006/07/07/57215.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何写一份好的工程师简历-转载</title><link>http://www.blogjava.net/terry-zj/archive/2006/06/23/54605.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Fri, 23 Jun 2006 01:09:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2006/06/23/54605.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/54605.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2006/06/23/54605.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/54605.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/54605.html</trackback:ping><description><![CDATA[
		<p>转自 <a href="http://googlechinablog.com/2006/06/blog-post_14.html">http://googlechinablog.com/2006/06/blog-post_14.html</a><br /><br />如何写一份好的工程师简历</p>
		<p>2006年6月14日 上午 10:15:00<br />发表者：王忻，Google 工程师 </p>
		<p>最近三年作为 Google（谷歌）的软件工程师，我每周会帮人事部门审查简历，决定要不要给他们面试。Google 这几年的发展让很多许多优秀的工程师都前来申请。到目前为止，我已经看了上千份简历，有些简历留下的印象比别的好很多。尤其是最近亲戚朋友常常问我如何修改他们的简历，所以我积累了一些常见的错误避免的提议，在此跟大家交流一下。</p>
		<p>1．谈到你做过的技术时，应该提到用的程序语言、你的个人贡献和产品细节。</p>
		<p>有时我看到有人把过去的经验在简历上一笔带过，比如说：</p>
		<p>• 在三人小组里，为电子邮件软件写了些 features。</p>
		<p>这是远远不够的，看简历的人希望了解你做的工作的难度和对本公司有多少联系，所以你最好写的具体一些。譬如：</p>
		<p>• 用 C++ 语言写了网络电子邮件的自动 backups。在三人小组里，专门负责设计和写储存服务器。从设计开始， 一年后把这个功能 feature 的用户推到了三千。</p>
		<p>2．多讲事实, 少用形容词。</p>
		<p>看简历的人读你的简历时，需要做判断，所以在简历里需要事实和数目。如果你写“迅速的提高了软件的操作效率”，看简历的人很难判断你成就的难度。但如果你写“在3个星期内，把软件的操作效率提高了40%” 就好多了。</p>
		<p>有些谦虚的朋友们不愿意把话说满，所以你也可以用这个办法。你如果说自己“突出”或“在项目上常常被请去救火”，听起来难免会有点骄傲。但你也可以用不能否认的事实来说明你的观点，如“《纽约日报》评这个产品为‘突出’”，或“加入了三个原本已落后于计划的项目小组，但经过努力和组员一起把它们都按时完成了。”</p>
		<p>3．你获得的奖、商业的荣誉或表扬、受用户欢迎的产品和你做过的有难度的业余项目都该包括在简历里。</p>
		<p>我有位朋友在硅谷一个著名的硬件公司做了六年，她设计的 IP phone（网络电话）为公司赚了上亿的收入，被公司与商业报道多次评了奖。我有一次在旧金山的高速公路上驾车时，看到路边有她产品的广告牌；还有一次我去上海度假时，竟然发现上海公路边上也有！</p>
		<p>不久，这位朋友决定换工作，请我看看她的简历。我惊讶的发现，她居然轻描淡写的写了一句-- "1998 – 2004：网络电话产品的硬件工程师组长" 和她的职责。</p>
		<p>"产品赢的奖呢？它为公司赚的钱呢？" 我追问到。</p>
		<p>"那些也该写吗？" 她说。</p>
		<p>当然该写。</p>
		<p>有人问，业余时间做的项目可不可以写？我觉得只要你的项目有代表性能说明对你的能力，都该包括。</p>
		<p>4．分清主次，删掉相比之下不起眼的成绩，以免冲淡更加突出的成绩。</p>
		<p>有朋友问，写简历是不是写的越多越好？譬如：</p>
		<p>在甲公司做暑假实习生——<br />* 改善电子游戏的数值分类算法， 减少了内存要求 10%。<br />* 用 Java 写了 3000 行用户界面程序。<br />* 每周做两小时的人工测试。</p>
		<p>你在申请软件工程师的职位时，我觉得前两点比较相关，第三点其实就不必写了。有时我看到有的简历里会提到，"按时完成了任务，产品符合原计划规格"。但读简历的人通常会认为这是理所当然的，而你把这些声明出来反而减弱简历的效果。</p>
		<p>写一份简历不容易，但写好了也会带来成就感 （和好工作！）。 Google （谷歌）在中国广召各方面的人才，你不妨可以给我们投个简历！我们不但在信息检索方面招雇工程师，还有计算机图形、用户界面、硬件、Windows、质量保证员和系统管理员等方面。更多信息，请您访问这里。</p>
		<p>谢谢阅读！大家感兴趣的话，下次我可以介绍“如何预备软件工程师的面试”。</p>
<img src ="http://www.blogjava.net/terry-zj/aggbug/54605.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2006-06-23 09:09 <a href="http://www.blogjava.net/terry-zj/archive/2006/06/23/54605.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Introducing to Spring Framework（中文修订版） 转载</title><link>http://www.blogjava.net/terry-zj/archive/2006/06/21/54163.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Wed, 21 Jun 2006 03:42:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2006/06/21/54163.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/54163.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2006/06/21/54163.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/54163.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/54163.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 转载地址： http://forum.javaeye.com/viewtopic.php?t=4919  中文http://www.theserverside.com/tt/articles/article.tss?l=SpringFramework 英文Introducing to Spring Framework						作者：Rod Johnson 译者：yanger，taow...&nbsp;&nbsp;<a href='http://www.blogjava.net/terry-zj/archive/2006/06/21/54163.html'>阅读全文</a><img src ="http://www.blogjava.net/terry-zj/aggbug/54163.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2006-06-21 11:42 <a href="http://www.blogjava.net/terry-zj/archive/2006/06/21/54163.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>代理模式(Proxy pattern) 转载</title><link>http://www.blogjava.net/terry-zj/archive/2006/06/20/53937.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Tue, 20 Jun 2006 03:46:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2006/06/20/53937.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/53937.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2006/06/20/53937.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/53937.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/53937.html</trackback:ping><description><![CDATA[
		<p>1. 代理模式 <br />代理模式的作用是：为其他对象提供一种代理以控制对这个对象的访问。在某些情况下，一个客户不想或者不能直接引用另一个对象，而代理对象可以在客户端和目标对象之间起到中介的作用。 <br />代理模式一般涉及到三个角色： <br />抽象角色：声明真实对象和代理对象的共同接口； <br />代理角色：代理对象角色内部含有对真实对象的引用，从而可以操作真实对象，同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时，代理对象可以在执行真实对象操作时，附加其他的操作，相当于对真实对象进行封装。 <br />真实角色：代理角色所代表的真实对象，是我们最终要引用的对象。</p>
		<p>以下以《Java与模式》中的示例为例： </p>
		<p>抽象角色： <br />abstract public class Subject {<br />   abstract public void request(); <br />}  </p>
		<p>真实角色：实现了Subject的request()方法。 <br />public class RealSubject extends Subject { <br />    public RealSubject() { } <br />    <br />    public void request() { <br />        System.out.println("From real subject."); <br />    } <br />} </p>
		<p>代理角色： <br />public class ProxySubject extends Subject { <br />    private RealSubject realSubject; //以真实角色作为代理角色的属性 </p>
		<p>    public ProxySubject() { } </p>
		<p>
				<br />    public void request() { //该方法封装了真实对象的request方法 <br />        preRequest(); </p>
		<p>        if( realSubject == null ) { </p>
		<p>            realSubject = new RealSubject(); <br />        } </p>
		<p>        realSubject.request(); //此处执行真实对象的request方法 </p>
		<p>        postRequest(); <br />    }</p>
		<p>
				<br />    private void preRequest() { <br />        //something you want to do before requesting <br />    }</p>
		<p>    private void postRequest() { <br />        //something you want to do after requesting <br />    } <br />} </p>
		<p>客户端调用： <br />Subject sub=new ProxySubject(); <br />Sub.request(); </p>
		<p>由以上代码可以看出，客户实际需要调用的是RealSubject类的request()方法，现在用ProxySubject来代理 RealSubject类，同样达到目的，同时还封装了其他方法(preRequest(),postRequest())，可以处理一些其他问题。 </p>
		<p>另外，如果要按照上述的方法使用代理模式，那么真实角色必须是事先已经存在的，并将其作为代理对象的内部属性。但是实际使用时，一个真实角色必须对应一个 代理角色，如果大量使用会导致类的急剧膨胀；此外，如果事先并不知道真实角色，该如何使用代理呢？这个问题可以通过Java的动态代理类来解决。<br /> <br />2.动态代理类 </p>
		<p>Java动态代理类位于Java.lang.reflect包下，一般主要涉及到以下两个类： </p>
		<p>(1). Interface InvocationHandler：该接口中仅定义了一个方法Object：invoke(Object obj,Method method, Object[] args)。在实际使用时，第一个参数obj一般是指代理类，method是被代理的方法，如上例中的request()，args为该方法的参数数组。 这个抽象方法在代理类中动态实现。 </p>
		<p>
				<br />(2).Proxy：该类即为动态代理类，作用类似于上例中的ProxySubject，其中主要包含以下内容： </p>
		<p>Protected Proxy(InvocationHandler h)：构造函数，估计用于给内部的h赋值。 </p>
		<p>Static Class getProxyClass (ClassLoader loader, Class[] interfaces)：获得一个代理类，其中loader是类装载器，interfaces是真实类所拥有的全部接口的数组。 </p>
		<p>Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)：返回代理类的一个实例，返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)。 </p>
		<p> </p>
		<p>所谓Dynamic Proxy是这样一种class：它是在运行时生成的class，在生成它时你必须提供一组interface给它，然后该class就宣称它实现了这些 interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然啦，这个Dynamic Proxy其实就是一个Proxy，它不会替你作实质性的工作，在生成它的实例时你必须提供一个handler，由它接管实际的工作。</p>
		<p>在使用动态代理类时，我们必须实现InvocationHandler接口，以第一节中的示例为例： </p>
		<p>抽象角色(之前是抽象类，此处应改为接口)： </p>
		<p>public interface Subject { <br />   abstract public void request(); <br />} </p>
		<p>具体角色RealSubject：<br />public class RealSubject implements Subject{</p>
		<p>  public RealSubject(){}</p>
		<p>  public void request(){<br />    System.out.println("From real subject.");<br />  }</p>
		<p>} </p>
		<p>
				<br />代理处理器： <br />import java.lang.reflect.Method;</p>
		<p>import java.lang.reflect.InvocationHandler;</p>
		<p>public class DynamicSubject implements InvocationHandler {<br />  private Object sub;<br />  public DynamicSubject() {}</p>
		<p>  public DynamicSubject(Object obj) {<br />    sub = obj;<br />  }</p>
		<p>public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {<br />   System.out.println("before calling " + method);<br />   method.invoke(sub,args);</p>
		<p>   System.out.println("after calling " + method);<br />   return null;<br /> }</p>
		<p>}</p>
		<p> </p>
		<p>该代理类的内部属性为Object类，实际使用时通过该类的构造函数DynamicSubject(Object obj)对其赋值；此外，在该类还实现了invoke方法，该方法中的 </p>
		<p>method.invoke(sub,args); </p>
		<p>其实就是调用被代理对象的将要被执行的方法，方法参数sub是实际的被代理对象，args为执行被代理对象相应操作所需的参数。通过动态代理类，我们可以在调用之前或之后执行一些相关操作。 </p>
		<p>客户端： </p>
		<p>import java.lang.reflect.InvocationHandler; <br />import java.lang.reflect.Proxy; <br />import java.lang.reflect.Constructor; <br />import java.lang.reflect.Method; </p>
		<p>public class Client { </p>
		<p>static public void main(String[] args) throws Throwable { </p>
		<p>   RealSubject rs = new RealSubject(); //在这里指定被代理类 <br />   InvocationHandler ds = new DynamicSubject(rs); <br />   Class cls = rs.getClass(); </p>
		<p>   //以下是一次性生成代理<br />   Subject subject = (Subject) Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(),ds ); <br />   subject.request(); </p>
		<p>} </p>
		<p>程序运行结果：<br />before calling public abstract void Subject.request()<br />From real subject.<br />after calling public abstract void Subject.request()</p>
		<p>通过这种方式，被代理的对象(RealSubject)可以在运行时动态改变，需要控制的接口(Subject接口)可以在运行时改变，控制的方式(DynamicSubject类)也可以动态改变，从而实现了非常灵活的动态代理关系。<br /> <br /><br />转载地址：<br /><a href="http://www.java3z.com/cwbwebhome/article/article2/2300.jsp?id=846">http://www.java3z.com/cwbwebhome/article/article2/2300.jsp?id=846</a><br /><a href="http://www.csdn.net/develop/Article/26/26750.shtm">http://www.csdn.net/develop/Article/26/26750.shtm</a> </p>
<img src ="http://www.blogjava.net/terry-zj/aggbug/53937.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2006-06-20 11:46 <a href="http://www.blogjava.net/terry-zj/archive/2006/06/20/53937.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>电子商务信函写作技巧</title><link>http://www.blogjava.net/terry-zj/archive/2006/06/08/51405.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Thu, 08 Jun 2006 09:03:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2006/06/08/51405.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/51405.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2006/06/08/51405.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/51405.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/51405.html</trackback:ping><description><![CDATA[电子商务信函写作技巧 <br />转载<a href="http://ec.icxo.com/htmlnews/2004/07/27/276390.htm">http://ec.icxo.com/htmlnews/2004/07/27/276390.htm</a><br /><br /><p><font class="font14">1）跟新买家建立联系 <br /><br />Dear Mr. Jones: <br /><br />We understand from your information posted on Alibaba.com that you are in the market for textiles. We would like to take this opportunity to introduce our company and products, with the hope that we may work with Bright Ideas Imports in the future. <br /><br />We are a joint venture specializing in the manufacture and export of textiles. We have enclosed our catalog, which introduces our company in detail and covers the main products we supply at present. You may also visit our online company introduction at <a href="http://xxxxxxxxxx.icxo.com/" target="_blank"><font color="#003399">Http://xxxxxxxxxx.icxo.com</font></a> which includes our latest product line. <br /><br />Should any of these items be of interest to you, please let us know. We will be happy to give you a quotation upon receipt of your detailed requirements. <br /><br />We look forward to receiving your enquires soon. <br /><br />Sincerely, <br /><br />John Roberts <br /><br />Company:XXXXXXX <br />ADD:XXXXXXX <br />TEL:XXXXXXXX <br />FAX:XXXXXXXXX <br />EMAIL:XXXXXXXXX <a href="http://www.xxxxxxxxxx/" target="_blank"><font color="#003399">HTTP://WWW.XXXXXXXXXX</font></a><br /><br />2）对新买家要求建立业务联系的回复 <br /><br />Dear Mr. Jones: <br /><br />We have received your letter of 9th April showing your interest in our complete product information. <br /><br />Our product lines mainly include high quality textile products. To give you a general idea of the various kinds of textiles now available for export, we have enclosed a catalogue and a price list. You may also visit our online company introduction at <a href="http://xxxxxxxxxx.icxo.com/" target="_blank"><font color="#003399">Http://xxxxxxxxxx.icxo.com</font></a> which includes our latest product line. <br /><br />We look forward to your specific enquiries and hope to have the opportunity to work together with you in the future. <br /><br />Sincerely, <br /><br />John Roberts <br /><br />Company:XXXXXXX <br />ADD:XXXXXXX <br />TEL:XXXXXXXX <br />FAX:XXXXXXXXX <br />EMAIL:XXXXXXXXX <a href="http://www.xxxxxxxxxx/" target="_blank"><font color="#003399">HTTP://WWW.XXXXXXXXXX</font></a><br /><br />3）向老客户介绍公司的最新产品信息 <br /><br />Dear Mr. Jones: <br /><br />We have refreshed our online catalog at <a href="http://xxxxxxxxxxx.com,/" target="_blank"><font color="#003399">http://xxxxxxxxxxx.com,</font></a> and now it covers the latest new products, which are now available from stock. <br /><br />We believe that you will find some attractive additions to our product line. Once you have had time to study the supplement, please let us know if you would like to take the matter further. We would be very happy to send samples to you for close inspection. <br /><br />We will keep you informed on our progress and look forward to hearing from you. <br /><br />Sincerely, <br /><br />John Roberts <br /><br />Company:XXXXXXX <br />ADD:XXXXXXX <br />TEL:XXXXXXXX <br />FAX:XXXXXXXXX <br />EMAIL:XXXXXXXXX <a href="http://www.xxxxxxxxxx/" target="_blank"><font color="#003399">HTTP://WWW.XXXXXXXXXX</font></a><br /></font></p><img src ="http://www.blogjava.net/terry-zj/aggbug/51405.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2006-06-08 17:03 <a href="http://www.blogjava.net/terry-zj/archive/2006/06/08/51405.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>访问被屏蔽的Google搜索引擎的常用方法</title><link>http://www.blogjava.net/terry-zj/archive/2006/06/05/50404.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Mon, 05 Jun 2006 00:35:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2006/06/05/50404.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/50404.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2006/06/05/50404.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/50404.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/50404.html</trackback:ping><description><![CDATA[
		<p>本文将给出一些能够正常访问被屏蔽的Google搜索引擎的常用方法以及Google的IP地址表。</p>
		<p>　　在Google.com里面进行搜索的时候，经常会遇到突然出现“该页无法显示”的提示，并且之后的十多分钟都无法正常连接Google，这里给出一些方法，可以解决大部分Google无法访问或进不去的问题。</p>
		<p>　　1、如果是搜索过程中出现“该页无法显示”的提示，接着就无法访问Google，那么对于ADSL用户，可以尝试断开网络连接，然后重新拨号上网，这样你的IP地址就发生了变化，这时候就可以正常访问Google了。（其原理是防火墙只是针对IP封用户，而不是针对独立电脑）</p>
		<p>　　2、如果一开始就无法访问Google，那么请把下面这一行：</p>
		<p>　　216.239.63.104　<a href="http://www.google.com">www.google.com</a> 或 64.233.171.99　<a href="http://www.google.com">www.google.com</a> 或 216.239.53.99　<a href="http://www.google.com">www.google.com</a></p>
		<p>　　添加到：C:\WINDOWS\system32\drivers\etc\hosts文件里，就着访问Google看看是否正常。（其原理是提供较为少用的Google镜像访问）</p>
		<p>　　3、使用附录中的Google的镜像IP地址来访问Google，那么多的IP，应该不至于全都封了吧。</p>
		<p>　　4、使用Google.cn来访问Google，不过请注意，Google.cn服务器也在美国，因此搜索词语的时候也会出现“该页无法显示”的可能。</p>
		<p>　　5、如果碰到DNS劫持的封锁方法，那么需要选择正确的DNS服务器，将主DNS设置成国外根服务器的DNS，然后辅助DNS设置成国外的DNS。具体做法：在拨号网络或网卡属性里设置，主DNS设成 202.12.27.33，辅助DNS：202.216 .228.18（日本DNS）大家还可以自己找一些快的国外DNS。 （其原理是DNS劫持只能够控制国内的DNS服务器，而对于国外的DNS服务器则无能为力，因此只要不使用国内的DNS即可）</p>
		<p>　　6、对于GMail，使用http访问访问的话最好不要选择“带有聊天功能的标准视图”，否则容易被封。</p>
		<p>　　7、尽量使用<a href="https://mail.google.com">https://mail.google.com</a> 来访问GMail，这将极大提高访问的稳定性，并且在GMail里使用GTalk也不会被封。（其原理是对于加密的https，防火墙无能为力）</p>
		<p>　　8、使用加密的代理服务器软件来访问Google，当然目前的一些加密的代理服务器都不是很稳定，速度也不是很理想。</p>
		<p>　　当然，上面的方法有时可能会实效，我觉得最简单的方法应该是来自Google的，就是提供一个支持https版本的Google搜索，这可以一劳永逸地解决目前几乎所有的问题，而且我知道增加这个版本对于Google来说应该是举手之劳的事情，并且GMail都已经提供了，那么为什么对于我们用的更多的Web搜索不提供呢？https是安全访问网站的一个重要的方法，目前还没有看到能截获https的加密数据的防火墙，那么与其提供Google.cn，其实还不如提供一个https的Google更实用。</p>
		<p>　　当然，在大多数国家，使用https访问Google都显得很多余，但请Google理解https对于中国用户的重要性，并且实现https访问也是轻而易举的事情，又何乐而不为呢。</p>
		<p>　　附录：Google的IP地址一览表：<a href="http://216.239.37.103">http://216.239.37.103</a> <a href="http://216.239.57.99">http://216.239.57.99</a> <a href="http://64.233.187.107">http://64.233.187.107</a><br /><a href="http://216.239.37.105">http://216.239.37.105</a> <a href="http://216.239.59.103">http://216.239.59.103</a> <a href="http://64.233.187.89">http://64.233.187.89</a><br /><a href="http://216.239.37.106">http://216.239.37.106</a> <a href="http://216.239.59.104">http://216.239.59.104</a> <a href="http://64.233.187.99">http://64.233.187.99</a><br /><a href="http://216.239.37.107">http://216.239.37.107</a> <a href="http://216.239.59.105">http://216.239.59.105</a> <a href="http://66.102.11.104">http://66.102.11.104</a><br /><a href="http://216.239.39.100">http://216.239.39.100</a> <a href="http://216.239.59.106">http://216.239.59.106</a> <a href="http://66.102.11.105">http://66.102.11.105</a><br /><a href="http://216.239.39.102">http://216.239.39.102</a> <a href="http://216.239.59.107">http://216.239.59.107</a> <a href="http://66.102.11.106">http://66.102.11.106</a><br /><a href="http://216.239.39.103">http://216.239.39.103</a> <a href="http://216.239.59.147">http://216.239.59.147</a> <a href="http://66.102.11.107">http://66.102.11.107</a><br /><a href="http://216.239.39.106">http://216.239.39.106</a> <a href="http://216.239.59.98">http://216.239.59.98</a> <a href="http://66.102.11.99">http://66.102.11.99</a><br /><a href="http://216.239.39.107">http://216.239.39.107</a> <a href="http://216.239.59.99">http://216.239.59.99</a> <a href="http://66.102.7.104">http://66.102.7.104</a><br /><a href="http://216.239.51.100">http://216.239.51.100</a> <a href="http://216.239.63.104">http://216.239.63.104</a> <a href="http://66.102.7.105">http://66.102.7.105</a><br /><a href="http://216.239.51.103">http://216.239.51.103</a> <a href="http://216.239.63.91">http://216.239.63.91</a> <a href="http://66.102.7.106">http://66.102.7.106</a><br /><a href="http://216.239.53.102">http://216.239.53.102</a> <a href="http://216.239.63.93">http://216.239.63.93</a> <a href="http://66.102.7.107">http://66.102.7.107</a><br /><a href="http://216.239.53.103">http://216.239.53.103</a> <a href="http://216.239.63.99">http://216.239.63.99</a> <a href="http://66.102.7.147">http://66.102.7.147</a><br /><a href="http://216.239.53.104">http://216.239.53.104</a> <a href="http://64.233.161.104">http://64.233.161.104</a> <a href="http://66.102.7.18">http://66.102.7.18</a><br /><a href="http://216.239.53.106">http://216.239.53.106</a> <a href="http://64.233.161.105">http://64.233.161.105</a> <a href="http://66.102.7.19">http://66.102.7.19</a><br /><a href="http://216.239.53.107">http://216.239.53.107</a> <a href="http://64.233.161.106">http://64.233.161.106</a> <a href="http://66.102.7.89">http://66.102.7.89</a><br /><a href="http://216.239.53.99">http://216.239.53.99</a> <a href="http://64.233.161.107">http://64.233.161.107</a> <a href="http://66.102.7.91">http://66.102.7.91</a><br /><a href="http://216.239.55.102">http://216.239.55.102</a> <a href="http://64.233.161.89">http://64.233.161.89</a> <a href="http://66.102.7.95">http://66.102.7.95</a><br /><a href="http://216.239.57.103">http://216.239.57.103</a> <a href="http://64.233.163.104">http://64.233.163.104</a> <a href="http://66.102.7.99">http://66.102.7.99</a><br /><a href="http://216.239.57.104">http://216.239.57.104</a> <a href="http://64.233.163.106">http://64.233.163.106</a> <a href="http://66.102.9.104">http://66.102.9.104</a><br /><a href="http://216.239.57.105">http://216.239.57.105</a> <a href="http://64.233.163.99">http://64.233.163.99</a> <a href="http://66.102.9.105">http://66.102.9.105</a><br /><a href="http://216.239.57.106">http://216.239.57.106</a> <a href="http://64.233.183.91">http://64.233.183.91</a> <a href="http://66.102.9.106">http://66.102.9.106</a><br /><a href="http://216.239.57.107">http://216.239.57.107</a> <a href="http://64.233.183.93">http://64.233.183.93</a> <a href="http://66.102.9.107">http://66.102.9.107</a><br /><a href="http://216.239.57.147">http://216.239.57.147</a> <a href="http://64.233.183.99">http://64.233.183.99</a> <a href="http://66.102.9.147">http://66.102.9.147</a><br /><a href="http://216.239.57.98">http://216.239.57.98</a> <a href="http://64.233.187.104">http://64.233.187.104</a> <a href="http://66.102.9.99">http://66.102.9.99</a></p>
		<p>转载自月光博客 [ <a href="http://www.williamlong.info">http://www.williamlong.info</a> ]</p>
<img src ="http://www.blogjava.net/terry-zj/aggbug/50404.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2006-06-05 08:35 <a href="http://www.blogjava.net/terry-zj/archive/2006/06/05/50404.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SQL优化是重点(转载)</title><link>http://www.blogjava.net/terry-zj/archive/2006/03/30/38291.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Thu, 30 Mar 2006 09:32:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2006/03/30/38291.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/38291.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2006/03/30/38291.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/38291.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/38291.html</trackback:ping><description><![CDATA[
		<p>信息系统访问量又不大，瓶颈一般不会出现在应用层，极有可能在数据库这一层，不用急着看程序。先找出逻辑读取次数最多的SQL，硬盘读取次数最多的SQL，找到SQL，对于SQL进行优化。看看有没有发生全表扫描的地方。 <br />一般发生全表扫描，极有可能是没有建立合理的索引，或者索引由于左边引用函数或其它原因造成索引失效。 <br />对于运行一年多的系统，最好要自己写一个自动重建索引的程序，定时重建索引。 <br />或者使用TOAD工具帮你重建索引。 </p>
		<p>另外在看一下数据库的CPU占用率，如果占用率在经常在80%－100%，那一定要是SQL或存储过程及trigger中写的不好。 </p>
		<p>不需要从应用层找SQL，方向性错误，太累，也看不出效果。 <br />而应当使用pl/SQL, toad等工具，分析出最bad的SQL语句，一看到这些语句后，再修改应用层的查询就是了。又快又方便。 </p>
		<p> </p>
		<p>-- 逻辑读多的SQL <br />select * from (select buffer_gets, sql_text <br />from v$sqlarea <br />where buffer_gets &gt; 500000 <br />order by buffer_gets desc) where rownum&lt;=30; </p>
		<p>-- 执行次数多的SQL <br />select sql_text,executions from <br />(select sql_text,executions from v$sqlarea order by executions desc) <br />where rownum&lt;81; </p>
		<p>-- 读硬盘多的SQL <br />select sql_text,disk_reads from <br />(select sql_text,disk_reads from v$sqlarea order by disk_reads desc) <br />where rownum&lt;21; </p>
		<p>-- 排序多的SQL <br />select sql_text,sorts from <br />(select sql_text,sorts from v$sqlarea order by sorts desc) <br />where rownum&lt;21; </p>
		<p>--分析的次数太多，执行的次数太少，要用绑变量的方法来写sql <br />set pagesize 600; <br />set linesize 120; <br />select substr(sql_text,1,80) "sql", count(*), sum(executions) "totexecs" <br />from v$sqlarea <br />where executions &lt; 5 <br />group by substr(sql_text,1,80) <br />having count(*) &gt; 30 <br />order by 2;<br /><br />转载地址 <a href="http://forum.javaeye.com/viewtopic.php?t=19464">http://forum.javaeye.com/viewtopic.php?t=19464</a></p>
<img src ="http://www.blogjava.net/terry-zj/aggbug/38291.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2006-03-30 17:32 <a href="http://www.blogjava.net/terry-zj/archive/2006/03/30/38291.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>最佳开源软件一览(转载)</title><link>http://www.blogjava.net/terry-zj/archive/2006/01/09/27217.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Mon, 09 Jan 2006 02:03:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2006/01/09/27217.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/27217.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2006/01/09/27217.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/27217.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/27217.html</trackback:ping><description><![CDATA[<P class=postdate>最佳开源软件一览<BR></P>
<P class=tags>&nbsp;</P>
<DIV class=content>
<UL>
<LI><A href="http://www.7-zip.org/" target=_blank>7-Zip 4.16 Beta</A>：文件压缩工具，可与Windows资源管理器集成<BR>
<LI><A href="http://a-note.sourceforge.net/" target=_blank>A Note 4.2.1</A>：可在Windows桌面放置便笺，并可提供闹钟提醒功能<BR>
<LI><A href="http://www.xs4all.nl/%7Eedienske" target=_blank>Abakt 0.9</A>：能够以压缩方式对文档进行备份<BR>
<LI><A href="http://www.abisource.com/" target=_blank>Abiword 2.27</A>：Windows写字板的替代程序，功能有所加强<BR>
<LI><A href="http://www.thekompany.com/home" target=_blank>Aethera 1.21</A>：提供日历、通讯录、任务表及提醒功能，并且内置了e-mail客户端<BR>
<LI><A href="http://www.antp.be/software/moviecatalog/" target=_blank>Ant Movie Catalog 3.5</A>：将你收藏的DVD影碟归档，并添加说明信息<BR>
<LI><A href="http://www.antp.be/software/renamer" target=_blank>Ant Renamer 2.0.8</A>：易用的文件重命名工具，并具备灵活的筛选机制<BR>
<LI><A href="http://audacity.sourceforge.net/" target=_blank>Audacity 1.2.3</A>：对音频文件进行编辑、优化并添加特效<BR>
<LI><A href="http://axcrypt.sourceforge.net/" target=_blank>Axcrypt 1.6.1</A>：对程序进行加密，可与Windows资源管理器集成<BR>
<LI><A href="http://www.blender3d.com/" target=_blank>Blender 3D 2.36</A>：三维对象的建模、渲染<BR>
<LI><A href="http://borg-calendar.sourceforge.net/" target=_blank>Borg Calendar 1.4.2</A>：提供桌面日历、任务列表、通讯录功能，支持多用户<BR>
<LI><A href="http://cdexos.sourceforge.net/" target=_blank>Cdex 1.51</A>：将音乐CD转换为wav或者mp3格式<BR>
<LI><A href="http://cinepaint.movieeditor.com/" target=_blank>Cinepaint</A> 0.19：专业的图像编辑软件<BR>
<LI><A href="http://www.clamwin.com/" target=_blank>Clam Win 0.83</A>：病毒扫描工具<BR>
<LI><A href="http://www.coolmon.org/" target=_blank>Cool Mon 1.0.1003</A>：系统检测工具<BR>
<LI><A href="http://coolplayer.sourceforge.net/" target=_blank>Cool Player 215</A>：一款精简的音频播放软件<BR>
<LI><A href="http://www.gnome.org/projects/dia" target=_blank>Dia 0.94</A>：绘制图表和流程图<BR>
<LI><A href="http://doubletype.sourceforge.net/" target=_blank>Double Type 0.2.1</A>：设计自己的Truetype字体<BR>
<LI><A href="http://www.egroupware.org/" target=_blank>Egroupware 1.0.0.006</A>：一款包含日历、新闻、联系人等模块的工作流系统<BR>
<LI><A href="http://www.heidi.ie/" target=_blank>Eraser 5.7</A>：永久地删除硬盘中的数据<BR>
<LI><A href="http://filezilla.sourceforge.net/" target=_blank>Filezilla 2.2.12c</A>：FTP客户端<BR>
<LI><A href="http://www.mozilla.net.cn/firefox/" target=_blank>Firefox 2</A>：Web浏览器，支持并列显示多个网页<BR>
<LI><A href="http://freemind.sourceforge.net/" target=_blank>Freemind 0.8</A>：能以直观形象的图示建立起各个概念之间的联系<BR>
<LI><A href="http://gaim.sourceforge.net/" target=_blank>Gaim 1.4.0</A>：同时支持ICQ、Aim、MSN、Yahoo的即时通信软件<BR>
<LI><A href="http://ganttproject.sourceforge.net/" target=_blank>Ganttproject 1.11.1</A>：项目管理软件，帮助你进行时间安排及资源分配<BR>
<LI><A href="http://www.gnupg.org/" target=_blank>GnuPG Add-ons</A>：对邮件进行加密<BR>
<LI><A href="http://healthmonitor.sourceforge.net/" target=_blank>Health Monitor 2.1 Monitors</A>：Windows状态监测工具，出现问题时可以给出警报<BR>
<LI><A href="http://www.inkscape.org/" target=_blank>Inkscape 0.41</A>：向量图形设计工具，可用来绘制地图、技术图纸或公司logo<BR>
<LI><A href="http://www.jdictionary.info/" target=_blank>JDictionary 1.8</A>：超过140万词条的百科辞典<BR>
<LI><A href="http://keepass.sourceforge.net/" target=_blank>Kee Pass 0.99b</A>：管理你的密码<BR>
<LI><A href="http://www.tranglos.com/" target=_blank>Keynote 1.6.5</A>：字处理软件和数据库的结合体，带有良好的搜索机制<BR>
<LI><A href="http://mediaportal.sourceforge.net/" target=_blank>Media Portal 0.1.1.1</A>：视频、DVD、音频、图片播放工具，同时支持电视和电台广播<BR>
<LI><A href="http://massid3lib.sourceforge.net/" target=_blank>MP3 Tag Tools 1.2.008</A>：mp3的文件ID标签编辑工具<BR>
<LI><A href="http://mp3gain.sourceforge.net/" target=_blank>MP3 Gain 1.2.5</A>：在不影响音质的情况下调节mp3歌曲的音量<BR>
<LI><A href="http://www.mozilla.nightrat.net/nvu" target=_blank>NVU 1.0</A>：所见即所得的HTML编辑工具，带有相当专业的网页制作功能<BR>
<LI><A href="http://www.openoffice.org/" target=_blank>Open Office 2.0 Beta</A>：文字处理、电子数据表、演示工具和数据库<BR>
<LI><A href="http://sector7g.wurzel6.de/pdfcreator/index_en.htm" target=_blank>PDF-Creator 0.8.1</A>：可被安装为打印机并将文档输出为pdf文件<BR>
<LI><A href="http://poptray.crause.co.za/" target=_blank>Poptray 3.10</A>：在后台监控邮件账号，当有新邮件进入时对你进行提醒<BR>
<LI><A href="http://sourceforge.net/projects/pwgen-win" target=_blank>PW-Gen 1.4.0</A>：为你生成64位到128位的安全密码<BR>
<LI><A href="http://www.rssowl.org/" target=_blank>RSS-Owl 1.1</A>：RSS阅读器<BR>
<LI><A href="http://smartision-sc.sourceforge.net/" target=_blank>Screencopy 2.3</A>：屏幕拷贝工具<BR>
<LI><A href="http://syn.sourceforge.net/" target=_blank>Syn Text Editor 2.1.0.46</A>：文本编辑器，支持多种程序语言的命令语法<BR>
<LI><A href="http://taskswitchxp.sourceforge.net/" target=_blank>Task SwitchXP Pro 1.1.2</A>：扩展了Windows任务管理器的功能和外观<BR>
<LI><A href="http://www.gimp.org/" target=_blank>The Gimp 2.2.4</A>：支持图层管理、特效润饰的图像编辑软件<BR>
<LI><A href="http://www.mozilla.com/thunderbird/" target=_blank>Thunderbird 1.07</A>：e-mail客户端，支持Imap/Pop3账户，带有垃圾邮件过滤器和虚拟文件夹<BR>
<LI><A href="http://truecrypt.sourceforge.net/" target=_blank>True Crypt 3.1a</A>：对文件或硬盘分区进行加密，也可以对U盘等移动存储介质进行加密<BR>
<LI><A href="http://francis.dupont.free.fr/truedownloader" target=_blank>True Downloader 0.82</A>：FTP和HTTP链接的下载管理工具，可以监视剪贴板<BR>
<LI><A href="http://www.tvbrowser.org/" target=_blank>TV-Browser 1.0.1</A>：自动更新每天的电视节目表<BR>
<LI><A href="http://www.virtualdub.org/" target=_blank>Virtual Dub 1.5.10</A>：视频编辑和捕获软件，支持mpeg-1和avi视频格式<BR>
<LI><A href="http://virtuawin.sourceforge.net/" target=_blank>Virtual Win 2.1</A>：可管理最多9个虚拟桌面，你可以用热键进行桌面切换<BR>
<LI><A href="http://www.videolan.org/" target=_blank>VLC Media Player 0.8.1</A>：媒体播放器，支持DVD、VCD、CD、mpeg和DivX等格式<BR>
<LI><A href="http://www.httrack.com/" target=_blank>Web HTTrack 3.33</A>：离线浏览器，可将Internet网页保存到本地硬盘中<BR>
<LI><A href="http://www.palma.com.au/winroll" target=_blank>Winroll 2.0</A>：点击标题栏后就可将程序窗口最小化<BR>
<LI><A href="http://musik.berlios.de/" target=_blank>WX Musik 0.4.1</A>：音频播放及管理软件<BR>
<LI><A href="http://www.apachefriends.org/" target=_blank>Xampp 1.42</A> ：Web服务器软件包，包含Apache、PHP和MySQL <BR></LI></UL></DIV><img src ="http://www.blogjava.net/terry-zj/aggbug/27217.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2006-01-09 10:03 <a href="http://www.blogjava.net/terry-zj/archive/2006/01/09/27217.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一篇关于session的好文（转载）</title><link>http://www.blogjava.net/terry-zj/archive/2006/01/05/26749.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Thu, 05 Jan 2006 09:21:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2006/01/05/26749.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/26749.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2006/01/05/26749.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/26749.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/26749.html</trackback:ping><description><![CDATA[<P>作者：郎云鹏（dev2dev ID: hippiewolf）</P>
<P>摘要：虽然session机制在web应用程序中被采用已经很长时间了，但是仍然有很多人不清楚session机制的本质，以至不能正确的应用这一技术。本文将详细讨论session的工作机制并且对在Java web application中应用session机制时常见的问题作出解答。</P>
<P>目录：<BR>一、术语session<BR>二、HTTP协议与状态保持<BR>三、理解cookie机制<BR>四、理解session机制<BR>五、理解javax.servlet.http.HttpSession<BR>六、HttpSession常见问题<BR>七、跨应用程序的session共享<BR>八、总结<BR>参考文档</P>
<P>一、术语session<BR>在我的经验里，session这个词被滥用的程度大概仅次于transaction，更加有趣的是transaction与session在某些语境下的含义是相同的。</P>
<P>session，中文经常翻译为会话，其本来的含义是指有始有终的一系列动作/消息，比如打电话时从拿起电话拨号到挂断电话这中间的一系列过程可以称之为一个session。有时候我们可以看到这样的话“在一个浏览器会话期间，...”，这里的会话一词用的就是其本义，是指从一个浏览器窗口打开到关闭这个期间①。最混乱的是“用户（客户端）在一次会话期间”这样一句话，它可能指用户的一系列动作（一般情况下是同某个具体目的相关的一系列动作，比如从登录到选购商品到结账登出这样一个网上购物的过程，有时候也被称为一个transaction），然而有时候也可能仅仅是指一次连接，也有可能是指含义①，其中的差别只能靠上下文来推断②。</P>
<P>然而当session一词与网络协议相关联时，它又往往隐含了“面向连接”和/或“保持状态”这样两个含义，“面向连接”指的是在通信双方在通信之前要先建立一个通信的渠道，比如打电话，直到对方接了电话通信才能开始，与此相对的是写信，在你把信发出去的时候你并不能确认对方的地址是否正确，通信渠道不一定能建立，但对发信人来说，通信已经开始了。“保持状态”则是指通信的一方能够把一系列的消息关联起来，使得消息之间可以互相依赖，比如一个服务员能够认出再次光临的老顾客并且记得上次这个顾客还欠店里一块钱。这一类的例子有“一个TCP session”或者“一个POP3 session”③。</P>
<P>而到了web服务器蓬勃发展的时代，session在web开发语境下的语义又有了新的扩展，它的含义是指一类用来在客户端与服务器之间保持状态的解决方案④。有时候session也用来指这种解决方案的存储结构，如“把xxx保存在session里”⑤。由于各种用于web开发的语言在一定程度上都提供了对这种解决方案的支持，所以在某种特定语言的语境下，session也被用来指代该语言的解决方案，比如经常把Java里提供的javax.servlet.http.HttpSession简称为session⑥。</P>
<P>鉴于这种混乱已不可改变，本文中session一词的运用也会根据上下文有不同的含义，请大家注意分辨。<BR>在本文中，使用中文“浏览器会话期间”来表达含义①，使用“session机制”来表达含义④，使用“session”表达含义⑤，使用具体的“HttpSession”来表达含义⑥</P>
<P>二、HTTP协议与状态保持<BR>HTTP协议本身是无状态的，这与HTTP协议本来的目的是相符的，客户端只需要简单的向服务器请求下载某些文件，无论是客户端还是服务器都没有必要纪录彼此过去的行为，每一次请求之间都是独立的，好比一个顾客和一个自动售货机或者一个普通的（非会员制）大卖场之间的关系一样。</P>
<P>然而聪明（或者贪心？）的人们很快发现如果能够提供一些按需生成的动态信息会使web变得更加有用，就像给有线电视加上点播功能一样。这种需求一方面迫使HTML逐步添加了表单、脚本、DOM等客户端行为，另一方面在服务器端则出现了CGI规范以响应客户端的动态请求，作为传输载体的HTTP协议也添加了文件上载、cookie这些特性。其中cookie的作用就是为了解决HTTP协议无状态的缺陷所作出的努力。至于后来出现的session机制则是又一种在客户端与服务器之间保持状态的解决方案。</P>
<P>让我们用几个例子来描述一下cookie和session机制之间的区别与联系。笔者曾经常去的一家咖啡店有喝5杯咖啡免费赠一杯咖啡的优惠，然而一次性消费5杯咖啡的机会微乎其微，这时就需要某种方式来纪录某位顾客的消费数量。想象一下其实也无外乎下面的几种方案：<BR>1、该店的店员很厉害，能记住每位顾客的消费数量，只要顾客一走进咖啡店，店员就知道该怎么对待了。这种做法就是协议本身支持状态。<BR>2、发给顾客一张卡片，上面记录着消费的数量，一般还有个有效期限。每次消费时，如果顾客出示这张卡片，则此次消费就会与以前或以后的消费相联系起来。这种做法就是在客户端保持状态。<BR>3、发给顾客一张会员卡，除了卡号之外什么信息也不纪录，每次消费时，如果顾客出示该卡片，则店员在店里的纪录本上找到这个卡号对应的纪录添加一些消费信息。这种做法就是在服务器端保持状态。</P>
<P>由于HTTP协议是无状态的，而出于种种考虑也不希望使之成为有状态的，因此，后面两种方案就成为现实的选择。具体来说cookie机制采用的是在客户端保持状态的方案，而session机制采用的是在服务器端保持状态的方案。同时我们也看到，由于采用服务器端保持状态的方案在客户端也需要保存一个标识，所以session机制可能需要借助于cookie机制来达到保存标识的目的，但实际上它还有其他选择。</P>
<P>三、理解cookie机制 <BR>cookie机制的基本原理就如上面的例子一样简单，但是还有几个问题需要解决：“会员卡”如何分发；“会员卡”的内容；以及客户如何使用“会员卡”。</P>
<P>正统的cookie分发是通过扩展HTTP协议来实现的，服务器通过在HTTP的响应头中加上一行特殊的指示以提示浏览器按照指示生成相应的cookie。然而纯粹的客户端脚本如Javascript或者VBscript也可以生成cookie。</P>
<P>而cookie的使用是由浏览器按照一定的原则在后台自动发送给服务器的。浏览器检查所有存储的cookie，如果某个cookie所声明的作用范围大于等于将要请求的资源所在的位置，则把该cookie附在请求资源的HTTP请求头上发送给服务器。意思是麦当劳的会员卡只能在麦当劳的店里出示，如果某家分店还发行了自己的会员卡，那么进这家店的时候除了要出示麦当劳的会员卡，还要出示这家店的会员卡。</P>
<P>cookie的内容主要包括：名字，值，过期时间，路径和域。<BR>其中域可以指定某一个域比如.google.com，相当于总店招牌，比如宝洁公司，也可以指定一个域下的具体某台机器比如<A href="http://www.google.com">www.google.com</A>或者froogle.google.com，可以用飘柔来做比。<BR>路径就是跟在域名后面的URL路径，比如/或者/foo等等，可以用某飘柔专柜做比。<BR>路径与域合在一起就构成了cookie的作用范围。<BR>如果不设置过期时间，则表示这个cookie的生命期为浏览器会话期间，只要关闭浏览器窗口，cookie就消失了。这种生命期为浏览器会话期的cookie被称为会话cookie。会话cookie一般不存储在硬盘上而是保存在内存里，当然这种行为并不是规范规定的。如果设置了过期时间，浏览器就会把cookie保存到硬盘上，关闭后再次打开浏览器，这些cookie仍然有效直到超过设定的过期时间。</P>
<P>存储在硬盘上的cookie可以在不同的浏览器进程间共享，比如两个IE窗口。而对于保存在内存里的cookie，不同的浏览器有不同的处理方式。对于IE，在一个打开的窗口上按Ctrl-N（或者从文件菜单）打开的窗口可以与原窗口共享，而使用其他方式新开的IE进程则不能共享已经打开的窗口的内存cookie；对于Mozilla Firefox0.8，所有的进程和标签页都可以共享同样的cookie。一般来说是用javascript的window.open打开的窗口会与原窗口共享内存cookie。浏览器对于会话cookie的这种只认cookie不认人的处理方式经常给采用session机制的web应用程序开发者造成很大的困扰。</P>
<P>下面就是一个goolge设置cookie的响应头的例子<BR>HTTP/1.1 302 Found<BR>Location: <A href="http://www.google.com/intl/zh-CN/">http://www.google.com/intl/zh-CN/</A><BR>Set-Cookie: PREF=ID=0565f77e132de138:NW=1:TM=1098082649:LM=1098082649:S=KaeaCFPo49RiA_d8; expires=Sun, 17-Jan-2038 19:14:07 GMT; path=/; domain=.google.com<BR>Content-Type: text/html</P>
<P><IMG alt="" hspace=0 src="D:\home\200562922161847.jpg" align=baseline border=0></P>
<P><BR>这是使用HTTPLook这个HTTP Sniffer软件来俘获的HTTP通讯纪录的一部分</P>
<P><IMG alt="" hspace=0 src="D:\home\200562922167755.jpg" align=baseline border=0></P>
<P><BR>浏览器在再次访问goolge的资源时自动向外发送cookie</P>
<P>&nbsp;<IMG alt="" hspace=0 src="D:\home\2005629221613750.jpg" align=baseline border=0></P>
<P><BR>使用Firefox可以很容易的观察现有的cookie的值<BR>使用HTTPLook配合Firefox可以很容易的理解cookie的工作原理。</P>
<P><IMG alt="" hspace=0 src="D:\home\2005629221620917.jpg" align=baseline border=0></P>
<P><BR>IE也可以设置在接受cookie前询问</P>
<P>&nbsp;<IMG alt="" hspace=0 src="D:\home\2005629221623485.jpg" align=baseline border=0></P>
<P><BR>这是一个询问接受cookie的对话框。</P>
<P>四、理解session机制<BR>session机制是一种服务器端的机制，服务器使用一种类似于散列表的结构（也可能就是使用散列表）来保存信息。</P>
<P>当程序需要为某个客户端的请求创建一个session的时候，服务器首先检查这个客户端的请求里是否已包含了一个session标识 - 称为session id，如果已包含一个session id则说明以前已经为此客户端创建过session，服务器就按照session id把这个session检索出来使用（如果检索不到，可能会新建一个），如果客户端请求不包含session id，则为此客户端创建一个session并且生成一个与此session相关联的session id，session id的值应该是一个既不会重复，又不容易被找到规律以仿造的字符串，这个session id将被在本次响应中返回给客户端保存。</P>
<P>保存这个session id的方式可以采用cookie，这样在交互过程中浏览器可以自动的按照规则把这个标识发挥给服务器。一般这个cookie的名字都是类似于SEEESIONID，而。比如weblogic对于web应用程序生成的cookie，JSESSIONID=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764，它的名字就是JSESSIONID。</P>
<P>由于cookie可以被人为的禁止，必须有其他机制以便在cookie被禁止时仍然能够把session id传递回服务器。经常被使用的一种技术叫做URL重写，就是把session id直接附加在URL路径的后面，附加方式也有两种，一种是作为URL路径的附加信息，表现形式为<A href="http://...../xxx;jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764">http://...../xxx;jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764</A><BR>另一种是作为查询字符串附加在URL后面，表现形式为<A href="http://...../xxx?jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764">http://...../xxx?jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764</A><BR>这两种方式对于用户来说是没有区别的，只是服务器在解析的时候处理的方式不同，采用第一种方式也有利于把session id的信息和正常程序参数区分开来。<BR>为了在整个交互过程中始终保持状态，就必须在每个客户端可能请求的路径后面都包含这个session id。</P>
<P>另一种技术叫做表单隐藏字段。就是服务器会自动修改表单，添加一个隐藏字段，以便在表单提交时能够把session id传递回服务器。比如下面的表单<BR>&lt;form name="testform" action="/xxx"&gt;<BR>&lt;input type="text"&gt;<BR>&lt;/form&gt;<BR>在被传递给客户端之前将被改写成<BR>&lt;form name="testform" action="/xxx"&gt;<BR>&lt;input type="hidden" name="jsessionid" value="ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764"&gt;<BR>&lt;input type="text"&gt;<BR>&lt;/form&gt;<BR>这种技术现在已较少应用，笔者接触过的很古老的iPlanet6(SunONE应用服务器的前身)就使用了这种技术。<BR>实际上这种技术可以简单的用对action应用URL重写来代替。</P>
<P>在谈论session机制的时候，常常听到这样一种误解“只要关闭浏览器，session就消失了”。其实可以想象一下会员卡的例子，除非顾客主动对店家提出销卡，否则店家绝对不会轻易删除顾客的资料。对session来说也是一样的，除非程序通知服务器删除一个session，否则服务器会一直保留，程序一般都是在用户做log off的时候发个指令去删除session。然而浏览器从来不会主动在关闭之前通知服务器它将要关闭，因此服务器根本不会有机会知道浏览器已经关闭，之所以会有这种错觉，是大部分session机制都使用会话cookie来保存session id，而关闭浏览器后这个session id就消失了，再次连接服务器时也就无法找到原来的session。如果服务器设置的cookie被保存到硬盘上，或者使用某种手段改写浏览器发出的HTTP请求头，把原来的session id发送给服务器，则再次打开浏览器仍然能够找到原来的session。</P>
<P>恰恰是由于关闭浏览器不会导致session被删除，迫使服务器为seesion设置了一个失效时间，当距离客户端上一次使用session的时间超过这个失效时间时，服务器就可以认为客户端已经停止了活动，才会把session删除以节省存储空间。</P>
<P>五、理解javax.servlet.http.HttpSession<BR>HttpSession是Java平台对session机制的实现规范，因为它仅仅是个接口，具体到每个web应用服务器的提供商，除了对规范支持之外，仍然会有一些规范里没有规定的细微差异。这里我们以BEA的Weblogic Server8.1作为例子来演示。</P>
<P>首先，Weblogic Server提供了一系列的参数来控制它的HttpSession的实现，包括使用cookie的开关选项，使用URL重写的开关选项，session持久化的设置，session失效时间的设置，以及针对cookie的各种设置，比如设置cookie的名字、路径、域，cookie的生存时间等。</P>
<P>一般情况下，session都是存储在内存里，当服务器进程被停止或者重启的时候，内存里的session也会被清空，如果设置了session的持久化特性，服务器就会把session保存到硬盘上，当服务器进程重新启动或这些信息将能够被再次使用，Weblogic Server支持的持久性方式包括文件、数据库、客户端cookie保存和复制。</P>
<P>复制严格说来不算持久化保存，因为session实际上还是保存在内存里，不过同样的信息被复制到各个cluster内的服务器进程中，这样即使某个服务器进程停止工作也仍然可以从其他进程中取得session。</P>
<P>cookie生存时间的设置则会影响浏览器生成的cookie是否是一个会话cookie。默认是使用会话cookie。有兴趣的可以用它来试验我们在第四节里提到的那个误解。</P>
<P>cookie的路径对于web应用程序来说是一个非常重要的选项，Weblogic Server对这个选项的默认处理方式使得它与其他服务器有明显的区别。后面我们会专题讨论。</P>
<P>关于session的设置参考[5] <A href="http://e-docs.bea.com/wls/docs70/webapp/weblogic_xml.html#1036869">http://e-docs.bea.com/wls/docs70/webapp/weblogic_xml.html#1036869</A></P>
<P>六、HttpSession常见问题<BR>（在本小节中session的含义为⑤和⑥的混合）</P>
<P><BR>1、session在何时被创建<BR>一个常见的误解是以为session在有客户端访问时就被创建，然而事实是直到某server端程序调用HttpServletRequest.getSession(true)这样的语句时才被创建，注意如果JSP没有显示的使用 &lt;<A href="mailto:%@page">%@page</A> session="false"%&gt; 关闭session，则JSP文件在编译成Servlet时将会自动加上这样一条语句HttpSession session = HttpServletRequest.getSession(true);这也是JSP中隐含的session对象的来历。</P>
<P>由于session会消耗内存资源，因此，如果不打算使用session，应该在所有的JSP中关闭它。</P>
<P>2、session何时被删除<BR>综合前面的讨论，session在下列情况下被删除a.程序调用HttpSession.invalidate();或b.距离上一次收到客户端发送的session id时间间隔超过了session的超时设置;或c.服务器进程被停止（非持久session）</P>
<P>3、如何做到在浏览器关闭时删除session<BR>严格的讲，做不到这一点。可以做一点努力的办法是在所有的客户端页面里使用javascript代码window.oncolose来监视浏览器的关闭动作，然后向服务器发送一个请求来删除session。但是对于浏览器崩溃或者强行杀死进程这些非常规手段仍然无能为力。</P>
<P>4、有个HttpSessionListener是怎么回事<BR>你可以创建这样的listener去监控session的创建和销毁事件，使得在发生这样的事件时你可以做一些相应的工作。注意是session的创建和销毁动作触发listener，而不是相反。类似的与HttpSession有关的listener还有HttpSessionBindingListener，HttpSessionActivationListener和HttpSessionAttributeListener。</P>
<P>5、存放在session中的对象必须是可序列化的吗<BR>不是必需的。要求对象可序列化只是为了session能够在集群中被复制或者能够持久保存或者在必要时server能够暂时把session交换出内存。在Weblogic Server的session中放置一个不可序列化的对象在控制台上会收到一个警告。我所用过的某个iPlanet版本如果session中有不可序列化的对象，在session销毁时会有一个Exception，很奇怪。</P>
<P>6、如何才能正确的应付客户端禁止cookie的可能性<BR>对所有的URL使用URL重写，包括超链接，form的action，和重定向的URL，具体做法参见[6]<BR><A href="http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770">http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770</A></P>
<P>7、开两个浏览器窗口访问应用程序会使用同一个session还是不同的session<BR>参见第三小节对cookie的讨论，对session来说是只认id不认人，因此不同的浏览器，不同的窗口打开方式以及不同的cookie存储方式都会对这个问题的答案有影响。</P>
<P>8、如何防止用户打开两个浏览器窗口操作导致的session混乱<BR>这个问题与防止表单多次提交是类似的，可以通过设置客户端的令牌来解决。就是在服务器每次生成一个不同的id返回给客户端，同时保存在session里，客户端提交表单时必须把这个id也返回服务器，程序首先比较返回的id与保存在session里的值是否一致，如果不一致则说明本次操作已经被提交过了。可以参看《J2EE核心模式》关于表示层模式的部分。需要注意的是对于使用javascript window.open打开的窗口，一般不设置这个id，或者使用单独的id，以防主窗口无法操作，建议不要再window.open打开的窗口里做修改操作，这样就可以不用设置。</P>
<P>9、为什么在Weblogic Server中改变session的值后要重新调用一次session.setValue<BR>做这个动作主要是为了在集群环境中提示Weblogic Server session中的值发生了改变，需要向其他服务器进程复制新的session值。</P>
<P>10、为什么session不见了<BR>排除session正常失效的因素之外，服务器本身的可能性应该是微乎其微的，虽然笔者在iPlanet6SP1加若干补丁的Solaris版本上倒也遇到过；浏览器插件的可能性次之，笔者也遇到过3721插件造成的问题；理论上防火墙或者代理服务器在cookie处理上也有可能会出现问题。<BR>出现这一问题的大部分原因都是程序的错误，最常见的就是在一个应用程序中去访问另外一个应用程序。我们在下一节讨论这个问题。</P>
<P>七、跨应用程序的session共享</P>
<P>常常有这样的情况，一个大项目被分割成若干小项目开发，为了能够互不干扰，要求每个小项目作为一个单独的web应用程序开发，可是到了最后突然发现某几个小项目之间需要共享一些信息，或者想使用session来实现SSO(single sign on)，在session中保存login的用户信息，最自然的要求是应用程序间能够访问彼此的session。</P>
<P>然而按照Servlet规范，session的作用范围应该仅仅限于当前应用程序下，不同的应用程序之间是不能够互相访问对方的session的。各个应用服务器从实际效果上都遵守了这一规范，但是实现的细节却可能各有不同，因此解决跨应用程序session共享的方法也各不相同。</P>
<P>首先来看一下Tomcat是如何实现web应用程序之间session的隔离的，从Tomcat设置的cookie路径来看，它对不同的应用程序设置的cookie路径是不同的，这样不同的应用程序所用的session id是不同的，因此即使在同一个浏览器窗口里访问不同的应用程序，发送给服务器的session id也可以是不同的。</P>
<P><IMG alt="" hspace=0 src="D:\home\2005629221626822.jpg" align=baseline border=0><BR>&nbsp; </P>
<P>根据这个特性，我们可以推测Tomcat中session的内存结构大致如下。</P>
<P><IMG alt="" hspace=0 src="D:\home\2005629221626479.jpg" align=baseline border=0><BR>&nbsp;</P>
<P>笔者以前用过的iPlanet也采用的是同样的方式，估计SunONE与iPlanet之间不会有太大的差别。对于这种方式的服务器，解决的思路很简单，实际实行起来也不难。要么让所有的应用程序共享一个session id，要么让应用程序能够获得其他应用程序的session id。</P>
<P>iPlanet中有一种很简单的方法来实现共享一个session id，那就是把各个应用程序的cookie路径都设为/（实际上应该是/NASApp，对于应用程序来讲它的作用相当于根）。<BR>&lt;session-info&gt;<BR>&lt;path&gt;/NASApp&lt;/path&gt;<BR>&lt;/session-info&gt;</P>
<P>需要注意的是，操作共享的session应该遵循一些编程约定，比如在session attribute名字的前面加上应用程序的前缀，使得setAttribute("name", "neo")变成setAttribute("app1.name", "neo")，以防止命名空间冲突，导致互相覆盖。</P>
<P><BR>在Tomcat中则没有这么方便的选择。在Tomcat版本3上，我们还可以有一些手段来共享session。对于版本4以上的Tomcat，目前笔者尚未发现简单的办法。只能借助于第三方的力量，比如使用文件、数据库、JMS或者客户端cookie，URL参数或者隐藏字段等手段。</P>
<P>我们再看一下Weblogic Server是如何处理session的。</P>
<P><IMG alt="" hspace=0 src="D:\home\2005629221630550.jpg" align=baseline border=0><BR>&nbsp; </P>
<P>从截屏画面上可以看到Weblogic Server对所有的应用程序设置的cookie的路径都是/，这是不是意味着在Weblogic Server中默认的就可以共享session了呢？然而一个小实验即可证明即使不同的应用程序使用的是同一个session，各个应用程序仍然只能访问自己所设置的那些属性。这说明Weblogic Server中的session的内存结构可能如下</P>
<P><IMG alt="" hspace=0 src="D:\home\2005629221630874.jpg" align=baseline border=0><BR>&nbsp;</P>
<P>对于这样一种结构，在session机制本身上来解决session共享的问题应该是不可能的了。除了借助于第三方的力量，比如使用文件、数据库、JMS或者客户端cookie，URL参数或者隐藏字段等手段，还有一种较为方便的做法，就是把一个应用程序的session放到ServletContext中，这样另外一个应用程序就可以从ServletContext中取得前一个应用程序的引用。示例代码如下，</P>
<P>应用程序A<BR>context.setAttribute("appA", session); </P>
<P>应用程序B<BR>contextA = context.getContext("/appA");<BR>HttpSession sessionA = (HttpSession)contextA.getAttribute("appA"); </P>
<P>值得注意的是这种用法不可移植，因为根据ServletContext的JavaDoc，应用服务器可以处于安全的原因对于context.getContext("/appA");返回空值，以上做法在Weblogic Server 8.1中通过。</P>
<P>那么Weblogic Server为什么要把所有的应用程序的cookie路径都设为/呢？原来是为了SSO，凡是共享这个session的应用程序都可以共享认证的信息。一个简单的实验就可以证明这一点，修改首先登录的那个应用程序的描述符weblogic.xml，把cookie路径修改为/appA访问另外一个应用程序会重新要求登录，即使是反过来，先访问cookie路径为/的应用程序，再访问修改过路径的这个，虽然不再提示登录，但是登录的用户信息也会丢失。注意做这个实验时认证方式应该使用FORM，因为浏览器和web服务器对basic认证方式有其他的处理方式，第二次请求的认证不是通过session来实现的。具体请参看[7] secion 14.8 Authorization，你可以修改所附的示例程序来做这些试验。</P>
<P>八、总结<BR>session机制本身并不复杂，然而其实现和配置上的灵活性却使得具体情况复杂多变。这也要求我们不能把仅仅某一次的经验或者某一个浏览器，服务器的经验当作普遍适用的经验，而是始终需要具体情况具体分析。</P>
<P>关于作者：<BR>郎云鹏（dev2dev ID: hippiewolf），软件工程师，从事J2EE开发<BR>电子邮件：<A href="mailto:langyunpeng@yahoo.com.cn">langyunpeng@yahoo.com.cn</A><BR>地址：大连软件园路31号科技大厦A座大连博涵咨询服务有限公司</P>
<P>参考文档：<BR>[1] Preliminary Specification <A href="http://wp.netscape.com/newsref/std/cookie_spec.html">http://wp.netscape.com/newsref/std/cookie_spec.html</A><BR>[2] RFC2109 <A href="http://www.rfc-editor.org/rfc/rfc2109.txt">http://www.rfc-editor.org/rfc/rfc2109.txt</A><BR>[3] RFC2965 <A href="http://www.rfc-editor.org/rfc/rfc2965.txt">http://www.rfc-editor.org/rfc/rfc2965.txt</A><BR>[4] The Unofficial Cookie FAQ <A href="http://www.cookiecentral.com/faq/">http://www.cookiecentral.com/faq/</A><BR>[5] <A href="http://e-docs.bea.com/wls/docs70/webapp/weblogic_xml.html#1036869">http://e-docs.bea.com/wls/docs70/webapp/weblogic_xml.html#1036869</A><BR>[6] <A href="http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770">http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770</A><BR>[7] RFC2616 <A href="http://www.rfc-editor.org/rfc/rfc2616.txt">http://www.rfc-editor.org/rfc/rfc2616.txt</A></P>
<P><BR>代码下载：<A href="http://dev2dev.bea.com.cn/images/paihang_article/041020/sampleApp.zip">http://dev2dev.bea.com.cn/images/paihang_article/041020/sampleApp.zip</A><BR><BR>转载地址：<A href="http://www.supcode.com/Article/html/4/43/2005/06/29/216335472190.shtml">http://www.supcode.com/Article/html/4/43/2005/06/29/216335472190.shtml</A></P><img src ="http://www.blogjava.net/terry-zj/aggbug/26749.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2006-01-05 17:21 <a href="http://www.blogjava.net/terry-zj/archive/2006/01/05/26749.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>session功能实现原理(转载)</title><link>http://www.blogjava.net/terry-zj/archive/2005/12/30/26078.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Fri, 30 Dec 2005 08:11:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2005/12/30/26078.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/26078.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2005/12/30/26078.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/26078.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/26078.html</trackback:ping><description><![CDATA[<P>HTTP协议（<A href="http://www.w3.org/Protocols/">http://www.w3.org/Protocols/</A>）是“一次性单向”协议。 <BR>服务端不能主动连接客户端，只能被动等待并答复客户端请求。客户端连接服务端，发出一个HTTP Request，服务端处理请求，并且返回一个HTTP Response给客户端，本次HTTP Request-Response Cycle结束。 <BR>我们看到，HTTP协议本身并不能支持服务端保存客户端的状态信息。于是，Web Server中引入了session的概念，用来保存客户端的状态信息。 <BR>这里用一个形象的比喻来解释session的工作方式。假设Web Server是一个商场的存包处，HTTP Request是一个顾客，第一次来到存包处，管理员把顾客的物品存放在某一个柜子里面（这个柜子就相当于Session），然后把一个号码牌交给这个顾客，作为取包凭证（这个号码牌就是Session ID）。顾客（HTTP Request）下一次来的时候，就要把号码牌（Session ID）交给存包处（Web Server）的管理员。管理员根据号码牌（Session ID）找到相应的柜子（Session），根据顾客（HTTP Request）的请求，Web Server可以取出、更换、添加柜子（Session）中的物品，Web Server也可以让顾客（HTTP Request）的号码牌和号码牌对应的柜子（Session）失效。顾客（HTTP Request）的忘性很大，管理员在顾客回去的时候（HTTP Response）都要重新提醒顾客记住自己的号码牌（Session ID）。这样，顾客（HTTP Request）下次来的时候，就又带着号码牌回来了。 <BR>我们可以看到，Session ID实际上是在客户端和服务端之间通过HTTP Request和HTTP Response传来传去的。 </P>
<P>我们看到，号码牌（Session ID）必须包含在HTTP Request里面。关于HTTP Request的具体格式，请参见HTTP协议（<A href="http://www.w3.org/Protocols/">http://www.w3.org/Protocols/</A>）。这里只做一个简单的介绍。 <BR>在Java Web Server（即Servlet/JSP Server）中，Session ID用jsessionid表示（请参见Servlet规范）。 <BR>HTTP Request一般由3部分组成： <BR>（1）Request Line <BR>这一行由HTTP Method（如GET或POST）、URL、和HTTP版本号组成。 <BR>例如，GET <A href="http://www.w3.org/pub/WWW/TheProject.html">http://www.w3.org/pub/WWW/TheProject.html</A> HTTP/1.1 <BR>GET <A href="http://www.google.com/search?q=Tomcat">http://www.google.com/search?q=Tomcat</A> HTTP/1.1 <BR>POST <A href="http://www.google.com/search">http://www.google.com/search</A> HTTP/1.1 <BR>GET <A href="http://www.somsite.com/menu.do;jsessionid=1001">http://www.somsite.com/menu.do;jsessionid=1001</A> HTTP/1.1 </P>
<P>（2）Request Headers <BR>这部分定义了一些重要的头部信息，如，浏览器的种类，语言，类型。Request Headers中还可以包括Cookie的定义。例如： <BR>User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0) <BR>Accept-Language: en-us <BR>Cookie: jsessionid=1001 </P>
<P>（3）Message Body <BR>如果HTTP Method是GET，那么Message Body为空。 <BR>如果HTTP Method是POST，说明这个HTTP Request是submit一个HTML Form的结果， <BR>那么Message Body为HTML Form里面定义的Input属性。例如， <BR>user=guest <BR>password=guest <BR>jsessionid=1001 <BR>主意，如果把HTML Form元素的Method属性改为GET。那么，Message Body为空，所有的Input属性都会加在URL的后面。你在浏览器的URL地址栏中会看到这些属性，类似于 <BR><A href="http://www.somesite/login.do?user=guest&amp;password=guest&amp;jsessionid=1001">http://www.somesite/login.do?user=guest&amp;password=guest&amp;jsessionid=1001</A> </P>
<P>从理论上来说，这3个部分（Request URL，Cookie Header, Message Body）都可以用来存放Session ID。由于Message Body方法必须需要一个包含Session ID的HTML Form，所以这种方法不通用。 <BR>一般用来实现Session的方法有两种： <BR>（1）URL重写。 <BR>Web Server在返回Response的时候，检查页面中所有的URL，包括所有的连接，和HTML Form的Action属性，在这些URL后面加上“;jsessionid=XXX”。 <BR>下一次，用户访问这个页面中的URL。jsessionid就会传回到Web Server。 <BR>（2）Cookie。 <BR>如果客户端支持Cookie，Web Server在返回Response的时候，在Response的Header部分，加入一个“set-cookie: jsessionid=XXXX”header属性，把jsessionid放在Cookie里传到客户端。 <BR>客户端会把Cookie存放在本地文件里，下一次访问Web Server的时候，再把Cookie的信息放到HTTP Request的“Cookie”header属性里面，这样jsessionid就随着HTTP Request返回给Web Server。 </P>
<P>我们来看Tomcat5的源代码如何支持jsessionid。 <BR>org.apache.coyote.tomcat5.CoyoteResponse类的toEncoded()方法支持URL重写。 <BR>String toEncoded(String url, String sessionId) { <BR>… <BR>StringBuffer sb = new StringBuffer(path); <BR>if( sb.length() &gt; 0 ) { // jsessionid can't be first. <BR>sb.append(";jsessionid="); <BR>sb.append(sessionId); <BR>} <BR>sb.append(anchor); <BR>sb.append(query); <BR>return (sb.toString()); <BR>} </P>
<P>我们来看org.apache.coyote.tomcat5.CoyoteRequest的两个方法configureSessionCookie() <BR>doGetSession()用Cookie支持jsessionid. </P>
<P>/** <BR>* Configures the given JSESSIONID cookie. <BR>* <BR>* @param cookie The JSESSIONID cookie to be configured <BR>*/ <BR>protected void configureSessionCookie(Cookie cookie) { <BR>… <BR>} </P>
<P>HttpSession doGetSession(boolean create){ <BR>… <BR>// Creating a new session cookie based on that session <BR>if ((session != null) &amp;&amp; (getContext() != null) <BR>&amp;&amp; getContext().getCookies()) { <BR>Cookie cookie = new Cookie(Globals.SESSION_COOKIE_NAME, <BR>session.getId()); <BR>configureSessionCookie(cookie); <BR>((HttpServletResponse) response).addCookie(cookie); <BR>} <BR>… <BR>} </P>
<P>Session的典型应用是存放用户的Login信息，如用户名，密码，权限角色等信息，应用程序（如Email服务、网上银行等系统）根据这些信息进行身份验证和权限验证</P><img src ="http://www.blogjava.net/terry-zj/aggbug/26078.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2005-12-30 16:11 <a href="http://www.blogjava.net/terry-zj/archive/2005/12/30/26078.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>让Java程序自带JRE（转载）</title><link>http://www.blogjava.net/terry-zj/archive/2005/12/30/26023.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Fri, 30 Dec 2005 03:23:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2005/12/30/26023.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/26023.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2005/12/30/26023.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/26023.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/26023.html</trackback:ping><description><![CDATA[<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用Java开发程序，发布时总要考虑的问题就是怎么在使用者的机器上装好JRE。要考虑的问题很多：使用者有没有能力独自安装JRE，<BR>使用者已有的JRE和我们需要的版本是不是一致，会不会出现版本问题，等等。使用.NET要考虑的问题就少些。现在.NET CLR似乎已经很普及<BR>了，看好多D版的Win XP都会自己安装最新的.NET CLR，而且似乎它的安装界面也比JRE友好些。彻底解决安装JRE的问题的方案，就是让我<BR>们的应用程序自己背着JRE！这样，我们的程序就像传统的Win32应用程序一样，双击就可以执行，不用管所在的机器上是否有JRE，是什么版<BR>本的JRE，无论怎样，我有我自己的！要做到这一点，其实非常容易。</FONT></P>
<P><BR><FONT size=2>王森在他的《Java深度历险》（强力推荐这本书，内容少而精）的第一章就解释了JDK，JRE，JVM之间的关系。解释了我们执行java.exe时<BR>发生的事情。其中提到，java.exe依照一套逻辑来寻找可以用的JRE，首先查找自己�诘哪柯枷掠忻挥蠮RE（据王森讲这样说不确切，我没有<BR>JDK全部的源代码，在此无从考证）；其次查找自己的父目录下有没有JRE；最后才是查询Windows的注册表。</FONT></P>
<P><BR><FONT size=2>通常我们在安装好了JRE的机器上的任何一个目录下都可以执行java.exe。因为它在安装时被复制到了windows的system32目录下，而后者<BR>无论如何都会在path环境变量中。这个java.exe最终必然会访问注册表来确定真正的JRE的所在地。若我们要求每一个应用程序都自带JRE，<BR>必然不能走这条路。但，逻辑的第二条讲，java.exe会在它的父目录下查找JRE，解决方案就在这一条中。</FONT></P>
<P><BR><FONT size=2>假设我们的应用程序打好了包，叫做MyApp.jar，放在MyApp的目录下。我们在MyApp目录下，可以执行java –jar MyApp.jar来运行我们<BR>的程序。我们安装的是JRE 1.5，在C:\Program Files\Java\jre1.5.0下。现在，我们只需要简单的将jre1.5.0目录搬到MyApp目录下，顺<BR>便改个容易写的名字比如叫jre。现在，我们的应用程序就象这样：</FONT></P>
<P><FONT size=2>MyApp</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MyApp.jar</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Jre</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Jre1.5.0目录下的全部内容</FONT></P>
<P><FONT size=2>Java.exe就在jre目录下的bin目录中。根据第二条逻辑，java.exe会在它的父目录中查找jre，实验证实，它会查找lib目录，而lib就在jre目<BR>录下。因此，这样java.exe就会确定jre的所在然后正常执行java程序，不会去管我们是否安装了JRE，注册表中是否有注册项这些杂事了。</FONT></P>
<P><FONT size=2>试一下，在命令行下进入MyApp的目录下，假设它在C盘，将path指向MyApp下的JRE：</FONT></P>
<P><FONT size=2>set path=c:\MyApp\jre\bin</FONT></P>
<P><FONT size=2>然后运行：</FONT></P>
<P><FONT size=2>java –verbose –jar MyApp.jar</FONT></P>
<P><FONT size=2>加上verbose参数以确定我们确实用了这一套被搬出了家的JRE。</FONT></P>
<P><FONT size=2>程序可以运行，并且在命令行输出的前几行，可以看到：</FONT></P>
<P><FONT size=2>[Opened C:\MyApp\jre\lib\rt.jar]</FONT></P>
<P><FONT size=2>[Opened C:\MyApp\jre\lib\jsse.jar]</FONT></P>
<P><FONT size=2>[Opened C:\MyApp\jre\lib\jce.jar]</FONT></P>
<P><FONT size=2>[Opened C:\MyApp\jre\lib\charsets.jar]</FONT></P>
<P><FONT size=2>因此程序读取的确实是它的私有的JRE。</FONT></P>
<P><FONT size=2>至此，我们似乎完成了任务。但是现在我们的私有JRE仍不完美，缺点是太大。JRE 1.5有接近70MB，作为我们的私有的JRE，好多内容都是<BR>可以抛弃的。Jre目录下的license都可以不要，bin下的执行文件只需要保留java.exe或者javaw.exe，lib下只要保留<BR>rt，jsse，jce，charsets几个库就可以了。除了i386和zi两个子目录外，其余的子目录都可以不要。Zi下只需要保留自己地区的子目录和其下<BR>的一些文件就可以。Lib下除了库之外的属性文件等等都要保留。这样清理一番，JRE仍然有接近50MB。还可以继续清理几个库文件里面不需<BR>要的内容，这需要仔细的整理，会很费功夫。最好能写出一个自动工具帮助我们整理它们。从Sun公司上下到的JMF里面附带的用Java写的媒<BR>体播放器就自带了JRE，只有几个MB。</FONT></P>
<P><BR><FONT size=2>清理过后需要运行几遍我们的应用程序，以确保我们的JRE不缺少东西。</FONT></P>
<P><FONT size=2>如果我们希望能有一个程序直接启动我们的应用程序，那就还要费些功夫。最简单的方法是弄出一个快捷方式来，但是快捷方式的路径不能是相<BR>对的，不方便我们安装。我想到的方案就是用Win32程序包装一下。在VS.NET下写一个Win32小程序：</FONT></P>
<P><FONT size=2>int PASCAL WinMain( HINSTANCE hInstance,</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; HINSTANCE hPrevInstance,</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; LPSTR lpszCmdLine,</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; int nCmdShow )</FONT></P>
<P><FONT size=2>{</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; STARTUPINFO si;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; PROCESS_INFORMATION pi;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; ZeroMemory( &amp;si, sizeof(si) );</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; si.cb = sizeof(si);</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; ZeroMemory( &amp;pi, sizeof(pi) );</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; // Start the child process. </FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; if( !CreateProcess( "jre\\bin\\javaw.exe",//执行的程序名</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "jre\\bin\\javaw.exe -jar MyApp.jar", // 带参数的执行程序</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NULL,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Process handle not inheritable. </FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NULL,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Thread handle not inheritable. </FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FALSE,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Set handle inheritance to FALSE. </FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // No creation flags. </FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NULL,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Use parent’s environment block. </FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NULL,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Use parent’s starting directory. </FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;si,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Pointer to STARTUPINFO structure.</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;pi )&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Pointer to PROCESS_INFORMATION structure.</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; ) </FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; {</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ErrorExit( "CreateProcess failed." );</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp; // Wait until child process exits.</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; WaitForSingleObject( pi.hProcess, INFINITE );</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp; // Close process and thread handles. </FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; CloseHandle( pi.hProcess );</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; CloseHandle( pi.hThread );</FONT></P>
<P><FONT size=2>}</FONT></P>
<P><FONT size=2>基本上是按照MSDN文档中的例子照搬的。将它编译成一个EXE文件，我们的任务才全部完成。双击这个EXE文件，我们的程序启动了，看起来<BR>和传统的Win32程序没有两样，JRE完全被隐藏在底层。<BR><BR>转载地址&nbsp;</FONT><A href="http://www.matrix.org.cn/resource/article/44/44085_java.html"><FONT size=2>http://www.matrix.org.cn/resource/article/44/44085_java.html</FONT></A><BR></P><img src ="http://www.blogjava.net/terry-zj/aggbug/26023.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2005-12-30 11:23 <a href="http://www.blogjava.net/terry-zj/archive/2005/12/30/26023.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>介绍struts的新特性:Lazy ActionForm（转载）</title><link>http://www.blogjava.net/terry-zj/archive/2005/12/09/23090.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Fri, 09 Dec 2005 02:43:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2005/12/09/23090.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/23090.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2005/12/09/23090.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/23090.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/23090.html</trackback:ping><description><![CDATA[
		<span class="postbody">
				<font size="2">
						<span style="FONT-WEIGHT: bold">STRUTS的 ActionForm到现在为止,出现了最少三种方式</span>: 普通的,动态的和懒的. <br /><br />所以你在你自已的开发中,可以有很多选择,如果你安全第一,可以用普通的.如果你更喜欢XML,则用动态的. <br /><br />如果你很懒,那就用Lazy ActionForm.  available in Version 1.2.6 onwards<br /><br />STRUTS提供的这三种ActionForm方式,要实际应用中你只要选择一种就可以了. <br /><br /><span style="FONT-WEIGHT: bold">下面说说Lazy ActionForm: </span><br /><br />如果你喜欢STRUTS的强大的功能的特性(就比如这个ActionForm有多种选择),又喜欢快捷, Lazy ActionForm对你来说是一个好消息. 这个有点类似于WW2中值得称道的一个特性,可以减少编写ActionForm的麻烦.(STRUTS正在把WW2中好的东西都吸收进来了,难怪这两个东西以后会合并为STRUTS IT). <br /><br />示例代码如下: <br /><br />struts-config.xml配置</font>
		</span>
		<table cellspacing="1" cellpadding="3" width="90%" align="center" border="0">
				<tbody>
						<tr>
								<td>
										<span class="genmed">
												<b>
												</b>
										</span>
								</td>
						</tr>
						<tr>
								<td class="code">
										<div style="FONT-FAMILY: 'Courier New',Courier,monospace">
												<font size="2">&lt;struts-config&gt; <br /><br />  &lt;form-beans&gt; <br />     &lt;form-bean name="lazyForm" type="org.<span style="COLOR: rgb(0,0,0)">apache</span>.<span style="COLOR: rgb(0,0,0)">struts</span>.<span style="COLOR: rgb(0,0,0)">validator</span>.<span style="COLOR: rgb(0,0,0)">LazyValidatorForm</span>"/&gt; <br />  &lt;/form-beans&gt; <br /><br />  &lt;action-mappings&gt; <br />    &lt;action path="/myActionPath" type="myPackage.<span style="COLOR: rgb(0,0,0)">MyAction</span>" name="lazyForm" validate="<span style="FONT-WEIGHT: bold; COLOR: rgb(153,0,102)">true</span>"/&gt; <br />  &lt;/action-mappings&gt; <br /><br />&lt;/struts-config&gt; <br /></font>
										</div>
								</td>
						</tr>
				</tbody>
		</table>
		<span class="postbody">
				<font size="2">JSP网页 <br /></font>
		</span>
		<table cellspacing="1" cellpadding="3" width="90%" align="center" border="0">
				<tbody>
						<tr>
								<td>
										<span class="genmed">
												<b>
														<font size="2">
														</font>
												</b>
										</span>
								</td>
						</tr>
						<tr>
								<td class="code">
										<div style="FONT-FAMILY: 'Courier New',Courier,monospace">
												<font size="2">&lt;html:form action="/myActionPath"&gt; <br /><br />  &lt;h2&gt;Simple Property Example&lt;/h2&gt; <br />          <br />          Customer <span style="COLOR: rgb(170,170,221)">Number</span>: &lt;html:text property="custNo"/&gt; <br />          Customer <span style="COLOR: rgb(170,170,221)">Name</span>:   &lt;html:text property="custName"/&gt; <br /><br />  &lt;h2&gt;Mapped Property Example&lt;/h2&gt; <br />          <br />          Street:  &lt;html:text property="address<span style="COLOR: rgb(0,0,0)">(</span>street<span style="COLOR: rgb(0,0,0)">)</span>"/&gt; <br />          Town:    &lt;html:text property="address<span style="COLOR: rgb(0,0,0)">(</span>town<span style="COLOR: rgb(0,0,0)">)</span>"/&gt; <br />          State:   &lt;html:text property="address<span style="COLOR: rgb(0,0,0)">(</span>state<span style="COLOR: rgb(0,0,0)">)</span>"/&gt; <br />          Country: &lt;html:text property="address<span style="COLOR: rgb(0,0,0)">(</span>country<span style="COLOR: rgb(0,0,0)">)</span>"/&gt; <br /><br />  &lt;h2&gt;Indexed Property Example&lt;/h2&gt; <br />          <br />  &lt;logic:iterate id="products" property="products"&gt; <br />    Product Code:&lt;html:text name="products" property="code" indexed="<span style="FONT-WEIGHT: bold; COLOR: rgb(153,0,102)">true</span>"/&gt; <br />    Product Description:&lt;html:text name="products" property="description" indexed="<span style="FONT-WEIGHT: bold; COLOR: rgb(153,0,102)">true</span>"/&gt; <br />    Product Price:&lt;html:text name="products" property="price" indexed="<span style="FONT-WEIGHT: bold; COLOR: rgb(153,0,102)">true</span>"/&gt; <br />  &lt;/logic:iterate&gt; <br /><br />&lt;/html:form&gt; <br /></font>
										</div>
								</td>
						</tr>
				</tbody>
		</table>
		<span class="postbody">
				<font size="2">action调用 <br /></font>
		</span>
		<table cellspacing="1" cellpadding="3" width="90%" align="center" border="0">
				<tbody>
						<tr>
								<td>
										<span class="genmed">
												<b>
														<font size="2">java代码: </font>
												</b>
										</span>
								</td>
						</tr>
						<tr>
								<td class="code">
										<div style="FONT-FAMILY: 'Courier New',Courier,monospace">
												<font size="2">
														<span style="FONT-WEIGHT: bold; COLOR: rgb(153,0,102)">public</span> ActionForward execute<span style="COLOR: rgb(0,0,0)">(</span>ActionMapping mapping, <br />                                 ActionForm form, <br />                                 HttpServeletRequest request, <br />                                 HttpServletResponse response<span style="COLOR: rgb(0,0,0)">)</span><span style="FONT-WEIGHT: bold; COLOR: rgb(153,0,102)">throws</span><span style="COLOR: rgb(170,170,221)">Exception</span><span style="COLOR: rgb(0,0,0)">{</span> <br />    <span style="COLOR: rgb(102,102,255)">// Cast form to DynaBean</span> <br />    DynaBean dynaForm = <span style="COLOR: rgb(0,0,0)">(</span>DynaBean<span style="COLOR: rgb(0,0,0)">)</span>form; <br /><br />    <span style="COLOR: rgb(102,102,255)">// Use the DynaBean</span> <br />    <span style="COLOR: rgb(170,170,221)">String</span> custNo = <span style="COLOR: rgb(0,0,0)">(</span><span style="COLOR: rgb(170,170,221)">String</span><span style="COLOR: rgb(0,0,0)">)</span>dynaForm.<span style="COLOR: rgb(0,0,0)">get</span><span style="COLOR: rgb(0,0,0)">(</span>"custNo"<span style="COLOR: rgb(0,0,0)">)</span>;   <span style="COLOR: rgb(102,102,255)">// simple</span> <br />    <span style="COLOR: rgb(170,170,221)">Map</span> address   = <span style="COLOR: rgb(0,0,0)">(</span><span style="COLOR: rgb(170,170,221)">Map</span><span style="COLOR: rgb(0,0,0)">)</span>dynaForm.<span style="COLOR: rgb(0,0,0)">get</span><span style="COLOR: rgb(0,0,0)">(</span>"address"<span style="COLOR: rgb(0,0,0)">)</span>;     <span style="COLOR: rgb(102,102,255)">// mapped</span> <br />    <span style="COLOR: rgb(170,170,221)">List</span> products = <span style="COLOR: rgb(0,0,0)">(</span><span style="COLOR: rgb(170,170,221)">List</span><span style="COLOR: rgb(0,0,0)">)</span>dynaForm.<span style="COLOR: rgb(0,0,0)">get</span><span style="COLOR: rgb(0,0,0)">(</span>"products"<span style="COLOR: rgb(0,0,0)">)</span>;   <span style="COLOR: rgb(102,102,255)">// indexed  </span><br />    //... <span style="COLOR: rgb(0,0,0)">etc</span><br /><span style="COLOR: rgb(0,0,0)">}</span><br /></font>
										</div>
								</td>
						</tr>
				</tbody>
		</table>
		<span class="postbody">
				<font size="2">在ACTION中,你可以使用 BeanUtils 1.7.0的特性,把dynaForm一次性拷贝到HIBERNATE的POJO中去!<br /><br />转载地址：http://forum.javaeye.com/viewtopic.php?t=17441<br /></font>
		</span>
<img src ="http://www.blogjava.net/terry-zj/aggbug/23090.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2005-12-09 10:43 <a href="http://www.blogjava.net/terry-zj/archive/2005/12/09/23090.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java抽取word,pdf的四种武器(转载)</title><link>http://www.blogjava.net/terry-zj/archive/2005/12/07/22856.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Wed, 07 Dec 2005 06:40:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2005/12/07/22856.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/22856.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2005/12/07/22856.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/22856.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/22856.html</trackback:ping><description><![CDATA[<DIV id=articleview_summary>摘要：<BR><BR>转载：转载请保留本信息，本文来自<A href="http://www.matrix.org.cn/resource/article/0/120.html">http://www.matrix.org.cn/resource/article/0/120.html</A> </DIV>
<DIV id=divarticlecontent>很多人问到如何抽取word，excel，pdf阿。这里我总结一下抽取word,pdf的<BR>几种方法。<BR><SPAN style="COLOR: red">1。用jacob.</SPAN><BR>其实jacob是一个bridage，连接java和com或者win32函数的一个中间件，jacob并不能直接抽取word,excel等文件，需要自己写dll哦，不过已经有为你写好的了，就是jacob的作者一并提供了。<BR>jacob下载：http://www.matrix.org.cn/down_view.asp?id=13<BR>下载了jacob并放到指定的路径之后(dll放到path,jar文件放到classpath)，就可以写你自己的抽取程序了，下面是一个例子：<BR>import java.io.File;<BR>import com.jacob.com.*;<BR>import com.jacob.activeX.*;<BR><BR>public class FileExtracter{<BR><BR>public static void main(String[] args) {<BR><BR>ActiveXComponent app = new ActiveXComponent("Word.Application");<BR>String inFile = "c:\\test.doc";<BR>String tpFile = "c:\\temp.htm";<BR>String otFile = "c:\\temp.xml";<BR>boolean flag = false;<BR>try {<BR>app.setProperty("Visible", new Variant(false));<BR>Object docs = app.getProperty("Documents").toDispatch();<BR>Object doc = Dispatch.invoke(docs,"Open", Dispatch.Method, new Object[]{inFile,new Variant(false), new Variant(true)}, new int[1]).toDispatch();<BR>Dispatch.invoke(doc,"SaveAs", Dispatch.Method, new Object[]{tpFile,new Variant(8)}, new int[1]);<BR>Variant f = new Variant(false);<BR>Dispatch.call(doc, "Close", f);<BR>flag = true;<BR>} catch (Exception e) {<BR>e.printStackTrace();<BR>} finally {<BR>app.invoke("Quit", new Variant[] {});<BR>}<BR><BR>}<BR>}<BR><SPAN style="COLOR: red">2。用apache的poi来抽取word，excel。</SPAN><BR>poi是apache的一个项目，不过就算用poi你可能都觉得很烦，不过不要紧，这里提供了更加简单的一个接口给你：<BR>下载经过封装后的poi包：http://www.matrix.org.cn/down_view.asp?id=14<BR>下载之后，放到你的classpath就可以了，下面是如何使用它的一个例子：<BR>import java.io.*;<BR>import org.textmining.text.extraction.WordExtractor;<BR>/**<BR>* &lt;p&gt;Title: pdf extraction&lt;/p&gt;<BR>* &lt;p&gt;Description: email:chris@matrix.org.cn&lt;/p&gt;<BR>* &lt;p&gt;Copyright: Matrix Copyright (c) 2003&lt;/p&gt;<BR>* &lt;p&gt;Company: Matrix.org.cn&lt;/p&gt;<BR>* @author chris<BR>* @version 1.0,who use this example pls remain the declare<BR>*/<BR><BR>public class PdfExtractor {<BR>public PdfExtractor() {<BR>}<BR>public static void main(String args[]) throws Exception<BR>{<BR>FileInputStream in = new FileInputStream ("c:\\a.doc");<BR>WordExtractor extractor = new WordExtractor();<BR>String str = extractor.extractText(in);<BR>System.out.println("the result length is"+str.length());<BR>System.out.println("the result is"+str);<BR>}<BR>}<BR><BR><SPAN style="COLOR: red">3。pdfbox-用来抽取pdf文件</SPAN><BR>但是pdfbox对中文支持还不好，先下载pdfbox：http://www.matrix.org.cn/down_view.asp?id=12<BR>下面是一个如何使用pdfbox抽取pdf文件的例子：<BR>import org.pdfbox.pdmodel.PDDocument;<BR>import org.pdfbox.pdfparser.PDFParser;<BR>import java.io.*;<BR>import org.pdfbox.util.PDFTextStripper;<BR>import java.util.Date;<BR>/**<BR>* &lt;p&gt;Title: pdf extraction&lt;/p&gt;<BR>* &lt;p&gt;Description: email:chris@matrix.org.cn&lt;/p&gt;<BR>* &lt;p&gt;Copyright: Matrix Copyright (c) 2003&lt;/p&gt;<BR>* &lt;p&gt;Company: Matrix.org.cn&lt;/p&gt;<BR>* @author chris<BR>* @version 1.0,who use this example pls remain the declare<BR>*/<BR><BR>public class PdfExtracter{<BR><BR>public PdfExtracter(){<BR>}<BR>public String GetTextFromPdf(String filename) throws Exception<BR>{<BR>String temp=null;<BR>PDDocument pdfdocument=null;<BR>FileInputStream is=new FileInputStream(filename);<BR>PDFParser parser = new PDFParser( is );<BR>parser.parse();<BR>pdfdocument = parser.getPDDocument();<BR>ByteArrayOutputStream out = new ByteArrayOutputStream();<BR>OutputStreamWriter writer = new OutputStreamWriter( out );<BR>PDFTextStripper stripper = new PDFTextStripper();<BR>stripper.writeText(pdfdocument.getDocument(), writer );<BR>writer.close();<BR>byte[] contents = out.toByteArray();<BR><BR>String ts=new String(contents);<BR>System.out.println("the string length is"+contents.length+"\n");<BR>return ts;<BR>}<BR>public static void main(String args[])<BR>{<BR>PdfExtracter pf=new PdfExtracter();<BR>PDDocument pdfDocument = null;<BR><BR>try{<BR>String ts=pf.GetTextFromPdf("c:\\a.pdf");<BR>System.out.println(ts);<BR>}<BR>catch(Exception e)<BR>{<BR>e.printStackTrace();<BR>}<BR>}<BR><BR>}<BR><BR><SPAN style="COLOR: red">4.抽取支持中文的pdf文件－xpdf</SPAN><BR>xpdf是一个开源项目，我们可以调用他的本地方法来实现抽取中文pdf文件。<BR>下载xpdf函数包：http://www.matrix.org.cn/down_view.asp?id=15<BR>同时需要下载支持中文的补丁包：http://www.matrix.org.cn/down_view.asp?id=16<BR>按照readme放好中文的patch，就可以开始写调用本地方法的java程序了<BR>下面是一个如何调用的例子：<BR>import java.io.*;<BR>/**<BR>* &lt;p&gt;Title: pdf extraction&lt;/p&gt;<BR>* &lt;p&gt;Description: email:chris@matrix.org.cn&lt;/p&gt;<BR>* &lt;p&gt;Copyright: Matrix Copyright (c) 2003&lt;/p&gt;<BR>* &lt;p&gt;Company: Matrix.org.cn&lt;/p&gt;<BR>* @author chris<BR>* @version 1.0,who use this example pls remain the declare<BR>*/<BR><BR><BR>public class PdfWin {<BR>public PdfWin() {<BR>}<BR>public static void main(String args[]) throws Exception<BR>{<BR>String PATH_TO_XPDF="C:\\Program Files\\xpdf\\pdftotext.exe";<BR>String filename="c:\\a.pdf";<BR>String[] cmd = new String[] { PATH_TO_XPDF, "-enc", "UTF-8", "-q", filename, "-"};<BR>Process p = Runtime.getRuntime().exec(cmd);<BR>BufferedInputStream bis = new BufferedInputStream(p.getInputStream());<BR>InputStreamReader reader = new InputStreamReader(bis, "UTF-8");<BR>StringWriter out = new StringWriter();<BR>char [] buf = new char[10000];<BR>int len;<BR>while((len = reader.read(buf))&gt;= 0) {<BR>//out.write(buf, 0, len);<BR>System.out.println("the length is"+len);<BR>}<BR>reader.close();<BR>String ts=new String(buf);<BR>System.out.println("the str is"+ts);<BR>}<BR>}<BR></DIV><img src ="http://www.blogjava.net/terry-zj/aggbug/22856.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2005-12-07 14:40 <a href="http://www.blogjava.net/terry-zj/archive/2005/12/07/22856.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>解决Tomcat 5.0.19 中文参数传递问题(转载)</title><link>http://www.blogjava.net/terry-zj/archive/2005/12/07/22845.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Wed, 07 Dec 2005 05:33:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2005/12/07/22845.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/22845.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2005/12/07/22845.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/22845.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/22845.html</trackback:ping><description><![CDATA[<SPAN class=javascript id=text44042>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT size=2>實際運用 Tomcat 5.0.19，我們了解在不修改 Tomcat 原始碼的狀況下，使用者透過 Form submit 的資料將一律以 ISO8859-1 處理，程式設計師必須自行將字串將轉換為 Big5(繁體中文) or GB2312/GBK(簡體中文)，我們在應用程式中，對所有的 request.getParameter("xx"); 作了 toBig5String() 的處理，理論上，所有的中文問題應該不會出現才對，結果，還是發現某些狀況下，中文還是變成亂碼！ <BR><BR>經過分析整理，我們發現問題出在 QueryString 的解析，以前在 Tomcat 4.x 時代，無論 SUBMIT 時採用 GET or POST，Tomcat server 對 parameters 的處理都採用相同的編碼，但在 Tomcat 5.x 版，不知何故，卻將 QueryString 的解析獨立出來，目前確認，Form 的 Method 採用 GET 及直接將參數寫在 URL 上的中文，上傳到 Tomcat 時，無論如何轉碼，都會變成亂碼，那怕你事先作過 URLEncode 也一樣。 <BR><BR>網站上，有人針對這個問題，建議將所有中文改採用 base64 編碼，到了 server 上，程式將自行土 base64 decode 回來，確保中文不會發生問題。這樣作法當然可以解決這個問題，但是所有網頁變成限定要採用 POST，且程式設計師要隨時分清楚，那個參數是採用 GET 上傳，那個參數是採用 POST 上傳，然後再針對不同的方式採用不同的解析，這樣的程式一點兒移植性都沒有，更別提跨平台、跨國際語言了。 <BR><BR>研究 Tomcat 的文件及原始碼，我們找到了問題所在及解決的方法，只有按著以下的作法，才能使 Form submit 的資料完全按著 ISO8859-1 的編碼，當然，若是全照著 Tomcat 的文件說明去作，肯定還是不行，你還是得加上這個參數到 server.xml 中才行。 <BR><BR>解決方案 <BR><BR>請先研究 $TOMCAT_HOME/webapps/tomcat-docs/config/http.html 這個說明檔，擷錄重點如下： <BR><B>URIEncoding</B>：This specifies the character encoding used to decode the URI bytes, after %xx decoding the URL. If not specified, ISO-8859-1 will be used. <BR><BR><B>useBodyEncodingForURI</B>：This specifies if the encoding specified in contentType should be used for URI query parameters, instead of using the URIEncoding. This setting is present for compatibility with Tomcat 4.1.x, where the encoding specified in the contentType, or explicitely set using Request.setCharacterEncoding method was also used for the parameters from the URL. The default value is false. <BR><BR>上述二個 Tomcat 參數，是設定在 server.xml 中的 http &lt;Connector /&gt; 區塊，要解決 QueryString 中文變成亂碼的問題，你必須至少設定這二個參數其中之一。 <BR>URIEncoding 請設定為 URIEncoding="ISO-8859-1" 指定為 "ISO-8859-1" 編碼，讓 QueryString 的字元編碼與 post body 相同。 <BR>useBodyEncodingForURI 這是用來相容 Tomcat 4.x 版的，設定的值是 "true" or "false"，意思是指 "要不要讓 QueryString 與 POST BODY 採用相同的字元編碼 ?"，若是設成 true，那也可達到 "ISO-8859-1" 編碼的需求。 <BR>建議，採用 URIEncoding 的設定，畢竟 useBodyEncodingForURI 的作法是為了相容 Tomcat 4.X。不過若照原文的說明，理論上這二個參數都不設，Tomcat 也該採用 "ISO-8859-1" 的編碼，那為什麼還是會有問題呢 ? 我們由 Tomcat Source Code 來看就清楚了。</FONT> <BR>
<TABLE class=java cellSpacing=1 cellPadding=3 bgColor=#999999 border=0>
<TBODY>
<TR>
<TD vAlign=top align=left width=1 bgColor=#dddddd><PRE><FONT color=#555555>1<BR>2<BR>3<BR>4<BR>5<BR>6<BR>7<BR>8<BR>9<BR>10<BR>11<BR>12<BR>13<BR>14<BR>15<BR>16<BR>17<BR>18<BR>19<BR>20<BR>21<BR>22<BR>23<BR>24<BR>25<BR>26<BR>27<BR>28<BR>29<BR></FONT></PRE></TD>
<TD vAlign=top align=left bgColor=#ffffff><PRE><FONT class=java-comment>// 這一段碼是 Tomcat 用來解 QueryString 的程式，</FONT>
<FONT class=java-comment>// 在 org.apache.tomcat.util.http.Parameters 這個 class 裡。</FONT>
<FONT class=java-reserved_word><B>private</B></FONT> String urlDecode(ByteChunk bc, String enc)
  <FONT class=java-reserved_word><B>throws</B></FONT> IOException <FONT class=java-bracket>{</FONT>
  <FONT class=java-reserved_word><B>if</B></FONT>( urlDec==<FONT class=java-reserved_word><B>null</B></FONT> ) <FONT class=java-bracket>{</FONT>
     urlDec=<FONT class=java-reserved_word><B>new</B></FONT> UDecoder(); 
  <FONT class=java-bracket>}</FONT>
  urlDec.convert(bc);
  String result = <FONT class=java-reserved_word><B>null</B></FONT>;
  <FONT class=java-reserved_word><B>if</B></FONT> (enc != <FONT class=java-reserved_word><B>null</B></FONT>) <FONT class=java-bracket>{</FONT>
    bc.setEncoding(enc);
    result = bc.toString();
  <FONT class=java-bracket>}</FONT> 
  <FONT class=java-reserved_word><B>else</B></FONT> <FONT class=java-bracket>{</FONT>
    CharChunk cc = tmpNameC;
    cc.allocate(bc.getLength(), -1);
    <FONT class=java-comment>// Default encoding: fast conversion</FONT>
    <FONT class=java-reserved_word><B>byte</B></FONT>[] bbuf = bc.getBuffer();
    <FONT class=java-reserved_word><B>char</B></FONT>[] cbuf = cc.getBuffer();
    <FONT class=java-reserved_word><B>int</B></FONT> start = bc.getStart();
    <FONT class=java-reserved_word><B>for</B></FONT> (<FONT class=java-reserved_word><B>int</B></FONT> i = 0; i &lt; bc.getLength(); i++) <FONT class=java-bracket>{</FONT>
      cbuf[i] = (<FONT class=java-reserved_word><B>char</B></FONT>) (bbuf[i + start] &amp; 0xff);
    <FONT class=java-bracket>}</FONT>
    cc.setChars(cbuf, 0, bc.getLength());
    result = cc.toString();
    cc.recycle();
  <FONT class=java-bracket>}</FONT>
  <FONT class=java-reserved_word><B>return</B></FONT> result;
<FONT class=java-bracket>}</FONT>
</PRE></TD></TR></TBODY></TABLE><BR><FONT size=2>請特別注意紅色區塊，當 Tomcat 發現 QueryString 並沒有設定 encode 時，並非像文件中所說預設採用 ISO-8859-1 的編碼，而是用一段 fast conversion 來處理，才會造成中文問題，所以，還是必須在 Server.xml 中，加上 URLEncoding 的參數設定才行哦。 <BR><BR>Connector 的設定範例：</FONT> <BR>
<TABLE class=java cellSpacing=1 cellPadding=3 bgColor=#999999 border=0>
<TBODY>
<TR>
<TD vAlign=top align=left width=1 bgColor=#dddddd><PRE><FONT color=#555555>1<BR>2<BR>3<BR>4<BR>5<BR>6<BR>7<BR>8<BR>9<BR>10<BR>11<BR>12<BR>13<BR>14<BR>15<BR></FONT></PRE></TD>
<TD vAlign=top align=left bgColor=#ffffff><PRE>&lt;Connector
debug=<FONT class=java-string>"0"</FONT>
acceptCount=<FONT class=java-string>"100"</FONT>
connectionTimeout=<FONT class=java-string>"20000"</FONT>
disableUploadTimeout=<FONT class=java-string>"true"</FONT>
port=<FONT class=java-string>"80"</FONT>
redirectPort=<FONT class=java-string>"8443"</FONT>
enableLookups=<FONT class=java-string>"false"</FONT>
minSpareThreads=<FONT class=java-string>"25"</FONT>
maxSpareThreads=<FONT class=java-string>"75"</FONT>
maxThreads=<FONT class=java-string>"150"</FONT>
maxPostSize=<FONT class=java-string>"0"</FONT>
URIEncoding=<FONT class=java-string>"ISO-8859-1"</FONT>
&gt;
&lt;/Connector&gt;
</PRE></TD></TR></TBODY></TABLE></SPAN><BR>转载地址：<BR><A href="http://www.javaworld.com.tw/jute/post/view?bid=9&amp;id=44042&amp;sty=1&amp;tpg=1&amp;age=0">http://www.javaworld.com.tw/jute/post/view?bid=9&amp;id=44042&amp;sty=1&amp;tpg=1&amp;age=0</A><img src ="http://www.blogjava.net/terry-zj/aggbug/22845.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2005-12-07 13:33 <a href="http://www.blogjava.net/terry-zj/archive/2005/12/07/22845.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>提交一个查询有必要用事务吗?(转载) </title><link>http://www.blogjava.net/terry-zj/archive/2005/12/06/22792.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Tue, 06 Dec 2005 14:25:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2005/12/06/22792.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/22792.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2005/12/06/22792.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/22792.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/22792.html</trackback:ping><description><![CDATA[<H2><FONT size=2>如果只提交一个查询，有必要用事务吗？这个问题之前已经讨论过 </FONT></H2>
<P><A href="http://forum.javaeye.com/viewtopic.php?t=1603"><FONT color=#003366 size=2>http://forum.javaeye.com/viewtopic.php?t=1603</FONT></A><FONT size=2> </FONT></P>
<P><FONT size=2>但是并没有得出明确的结论。先让我们看看事务的定义： </FONT></P>
<P><FONT size=2>引用: </FONT></P>
<P><FONT size=2>Transactions are described in terms of ACID properties, which are as follows: <BR>n Atomic: all changes to the database made in a transaction are rolled back if any <BR>change fails. <BR>n Consistent: the effects of a transaction take the database from one consistent <BR>state to another consistent state. <BR>n Isolated: the intermediate steps in a transaction are not visible to other users of <BR>the database. <BR>n Durable: when a transaction is completed (committed or rolled back), its effects <BR>persist in the database. <BR>&nbsp;</FONT></P>
<P><BR><FONT size=2>即ACID的定义，从上面看来，似乎除了isolated之外，和只读查询都没有关系。那么是否只读查询不需要事务呢？ </FONT></P>
<P><FONT size=2>再看看Oracle对于只读事务的定义： </FONT></P>
<P><FONT size=2>引用: <BR>Read-Only Transactions <BR>By default, Oracle guarantees statement-level read consistency. The set of data returned by a single query is consistent with respect to a single point in time. However, in some situations, you might also require transaction-level read consistency. This is the ability to run multiple queries within a single transaction, all of which are read-consistent with respect to the same point in time, so that queries in this transaction do not see the effects of intervening committed transactions. </FONT></P>
<P><FONT size=2>If you want to run a number of queries against multiple tables and if you are not doing any updating, you prefer a read-only transaction. After indicating that your transaction is read-only, you can run as many queries as you like against any table, knowing that the results of each query are consistent with respect to the same point in time. </FONT></P>
<P><BR><FONT size=2>Oracle默认情况下保证了SQL语句级别的读一致性，即在该条SQL语句执行期间，它只会看到执行前点的数据状态，而不会看到执行期间数据被其他SQL改变的状态。 </FONT></P>
<P><FONT size=2>而Oracle的只读查询(read-only transaction)则保证了事务级别的读一致性，即在该事务范围内执行的多条SQL都只会看到执行前点的数据状态，而不会看到事务期间的任何被其他SQL改变的状态。 </FONT></P>
<P><FONT size=2>因此我们可以得出结论： </FONT></P>
<P><FONT size=2>如果你一次执行单条查询语句，则没有必要启用事务支持，数据库默认支持SQL执行期间的读一致性； <BR>如果你一次执行多条查询语句，例如统计查询，报表查询，在这种场景下，多条查询SQL必须保证整体的读一致性，否则，在前条SQL查询之后，后条SQL查询之前，数据被其他用户改变，则该次整体的统计查询将会出现读数据不一致的状态，此时，应该启用事务支持。 </FONT></P>
<P><BR><FONT size=2>只读事务与读写事务区别 </FONT></P>
<P><FONT size=2>对于只读查询，可以指定事务类型为readonly，即只读事务。由于只读事务不存在数据的修改，因此数据库将会为只读事务提供一些优化手段，例如Oracle对于只读事务，不启动回滚段，不记录回滚log。 </FONT></P>
<P><FONT size=2>在JDBC中，指定只读事务的办法为： <BR>connection.setReadOnly(true); </FONT></P>
<P><FONT size=2>在Hibernate中，指定只读事务的办法为： <BR>session.setFlushMode(FlushMode.NEVER); <BR>此时，Hibernate也会为只读事务提供Session方面的一些优化手段 </FONT></P>
<P><FONT size=2>在Spring的Hibernate封装中，指定只读事务的办法为： <BR>bean配置文件中，prop属性增加“readOnly”</FONT></P>
<P><FONT size=2></FONT>&nbsp;</P>
<P><FONT size=2>我在MySQL4.1试验了一下，过程和结果如下： </FONT></P>
<P><FONT size=2>数据库：MySQL4.1 <BR>表类型：InnoDB <BR>Spring：1.1.2 <BR>Hibernate：2.1.7 </FONT></P>
<P><FONT size=2>使用Spring的声明式事务管理 </FONT></P>
<P><FONT size=2>试验过程如下： </FONT></P>
<P><FONT size=2>不设置查询方法的事务类型(即不需要事务)：访问查询页面，后台执行Spring的Bean方法，让Hibernate发送select语句，然后手工在MySQL里面修改该记录某字段值，再访问查询页面，发现被修改过的字段值并没有变化，Hibernate输出的log显示，数据库还是把老的字段值返回，而没有返回新的字段值。 </FONT></P>
<P><FONT size=2>设置查询方法的事务类型(只读事务)：访问查询页面，后台执行Spring的Bean方法，让Hibernate发送select语句，然后手工在MySQL里面修改该记录某字段值，再访问查询页面，发现被修改过的字段值已经变化，Hibernate输出的log显示，数据库返回新的字段值。 </FONT></P>
<P><FONT size=2>这个试验说明，至少在MySQL4.1的InnoDB情况下，不使用只读事务的查询将无法读取到数据更新值，必须使用只读事务来保证读记录的数据一致性。这个结果非常令我诧异，和我预期完全两样。 </FONT></P>
<P><FONT size=2>我将在Oracle平台上试试看会有什么样的结果。 </FONT></P>
<P><FONT size=2>BTW: 如果MySQL的表类型改为MyISAM，那么即使不设置事务，也不会出现读数据不一致的现象。</FONT></P>
<P><BR><FONT size=2>oracle有两种方法保证在事务级读数据一致性(Transaction-Level Read Consistency) </FONT></P>
<P><FONT size=2>一是用SET TRANSACTION ISOLATION LEVEL SERIALIZABLE , <BR>当执行这条命令后读数据时会产生一些重复copy, 你也可以做数据修改, 但在大量数据修改的情况下容易造成deadlock或异常, 用commit或rollback将把ISOLATION LEVEL设回为缺省模式read committed, </FONT></P>
<P><BR><FONT size=2>二是用SET TRANSCATION READ ONLY <BR>当执行这条命令时数据库会生成一个快照的latch, 这个latch会耗费一些resource, 如果你想进行数据修改会导致异常. 用commit或rollback会把latch释放掉, 也将把ISOLATION LEVEL设回为缺省模式read committed,</FONT></P><img src ="http://www.blogjava.net/terry-zj/aggbug/22792.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2005-12-06 22:25 <a href="http://www.blogjava.net/terry-zj/archive/2005/12/06/22792.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Oracle SQL依然无可替代--《Mastering Oracle SQL》(转载)</title><link>http://www.blogjava.net/terry-zj/archive/2005/12/06/22786.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Tue, 06 Dec 2005 14:04:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2005/12/06/22786.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/22786.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2005/12/06/22786.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/22786.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/22786.html</trackback:ping><description><![CDATA[<SPAN id=BlogViewId><TR><TD class=ellipse><SPAN class=bvTitle id=subjcns!1pnXmtZJZoGE64AUuta1hh1Q!144><FONT size=2>转载 Oracle SQL依然无可替代--《Mastering Oracle SQL》</FONT></SPAN></TD></TR><TR><TD class=bvh8></TD></TR><TR><TD id=msgcns!1pnXmtZJZoGE64AUuta1hh1Q!144>
<P><FONT size=2>选择自 </FONT><A id=ArticleTitle1_ArticleTitle1_AuthorLink href="http://dev.csdn.net/user/calvinxiu"><FONT size=2>calvinxiu</FONT></A><FONT size=2> 的 Blog&nbsp; </FONT><A href="http://dev.csdn.net/user/calvinxiu"><FONT size=2>http://dev.csdn.net/user/calvinxiu</FONT></A></P>
<P><FONT size=2>天寒地冻，呆在家里又读完了《Mastering Oracle SQL》2nd，发现Oracle的功能还是很强悍，光函数就有两百个，HSQL是很难比拟的。接下来的硬骨头，看来要么冒险用Hibernate3.0 的SQL Mapping功能，要么就自己跑JDBC组装VO了。 </FONT></P>
<DIV><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </FONT><FONT size=2><STRONG>1.报表合计专用的Rollup函数<BR></STRONG>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 销售报表<BR>&nbsp; 广州&nbsp;&nbsp;&nbsp;&nbsp; 1月&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2000元<BR>&nbsp; 广州&nbsp;&nbsp;&nbsp;&nbsp; 2月&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2500元<BR>&nbsp; 广州&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4500元<BR>&nbsp; 深圳&nbsp;&nbsp;&nbsp;&nbsp; 1月&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1000元<BR>&nbsp; 深圳&nbsp;&nbsp;&nbsp;&nbsp; 2月&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2000元<BR>&nbsp; 深圳&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3000元<BR>&nbsp; 所有地区&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;7500元<BR></FONT></DIV>
<DIV><BR><FONT size=2>以往的查询SQL:<BR>Select&nbsp; area,month,sum(money) from SaleOrder group by area,month<BR>然后广州，深圳的合计和所有地区合计都需要在程序里自行累计</FONT></DIV>
<DIV><BR><FONT size=2>1.其实可以使用如下SQL:&nbsp;&nbsp; Select area,month,sum(total_sale) from SaleOrder group by <STRONG>rollup</STRONG>(area,month)就能产生和报表一模一样的纪录</FONT></DIV>
<DIV><FONT size=2></FONT>&nbsp;</DIV>
<DIV><FONT size=2>2.如果year不想累加，可以写成&nbsp;&nbsp; Select year,month,area,sum(total_sale) from SaleOrder group by <STRONG>year</STRONG>, <STRONG>rollup</STRONG>(month,area)&nbsp;&nbsp;&nbsp;另外Oracle 9i还支持如下语法:&nbsp;&nbsp; Select year,month,area,sum(total_sale) from SaleOrder group by rollup(<STRONG>(year,month),</STRONG>area)</FONT></DIV>
<DIV><FONT size=2></FONT>&nbsp;</DIV>
<DIV><FONT size=2>3.如果使用Cube(area,month)而不是RollUp(area,month)，除了获得每个地区的合计之外，还将获得每个月份的合计，在报表最后显示。</FONT></DIV>
<DIV><FONT size=2></FONT>&nbsp;</DIV>
<DIV><FONT size=2>4.Grouping让合计列更好读<BR>&nbsp; RollUp在显示广州合计时，月份列为NULL，但更好的做法应该是显示为"所有月份"<BR>&nbsp; Grouping就是用来判断当前Column是否是一个合计列，1为yes，然后用Decode把它转为"所有月份"&nbsp; Select&nbsp; <STRONG>Decode(Grouping(area),1,'所有地区',area)</STRONG> area,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Decode(Grouping(month),1,'所有月份',month),<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sum(money)<BR>&nbsp;&nbsp;From SaleOrder&nbsp;<BR>&nbsp;&nbsp;Group by RollUp(area,month);</FONT></DIV>
<DIV><FONT size=2></FONT>&nbsp;</DIV>
<DIV><FONT size=2><STRONG>2.对多级层次查询的start with.....connect by</STRONG><BR>&nbsp;&nbsp; 比如人员组织,产品类别,Oracle提供了很经典的方法</FONT></DIV>
<DIV><FONT size=2>SELECT <STRONG>LEVE</STRONG>L, name, emp_id,manager_emp_id<BR>FROM employee<BR><STRONG>START WITH </STRONG>manager_emp_id is null<BR><STRONG>CONNECT BY PRIOR </STRONG>emp_id = manager_emp_id;</FONT></DIV>
<DIV><FONT size=2>上面的语句demo了全部的应用,start with指明从哪里开始遍历树,如果从根开始,那么它的manager应该是Null,如果从某个职员开始,可以写成emp_id='11'<BR>CONNECT BY 就是指明父子关系,注意PRIOR位置<BR>另外还有一个LEVEL列,显示节点的层次</FONT></DIV>
<DIV><FONT size=2></FONT>&nbsp;</DIV>
<DIV><FONT size=2><STRONG>3.更多报表/分析决策功能</STRONG><BR>3.1 分析功能的基本结构<BR>&nbsp;&nbsp;&nbsp;&nbsp; 分析功能() over( partion子句,order by子句,窗口子句)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;概念上很难讲清楚,还是用例子说话比较好.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </FONT></DIV>
<DIV><FONT size=2></FONT>&nbsp;</DIV>
<DIV><FONT size=2>3.2 Row_Number 和 Rank, DENSE_Rank<BR>&nbsp;&nbsp;&nbsp; 用于选出Top 3 sales这样的报表<BR>&nbsp;&nbsp;&nbsp; 当两个业务员可能有相同业绩时,就要使用Rank和Dense_Rank<BR>&nbsp;&nbsp;&nbsp; 比如<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 金额&nbsp;&nbsp;&nbsp; RowNum&nbsp; Rank&nbsp; Dense_Rank<BR>&nbsp;&nbsp;&nbsp; 张三 4000元&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1<BR>&nbsp;&nbsp;&nbsp; 李四 3000元&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2<BR>&nbsp;&nbsp;&nbsp; 钱五 2000元&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3<BR>&nbsp;&nbsp;&nbsp; 孙六 2000元&nbsp;&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3<BR>&nbsp;&nbsp;&nbsp; 丁七 1000元&nbsp;&nbsp;&nbsp; 5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4</FONT></DIV>
<DIV><FONT size=2>&nbsp;&nbsp;&nbsp; 这时,应该把并列第三的钱五和孙六都选进去,所以用Ranking功能比RowNumber保险.至于Desnse还是Ranking就看具体情况了。</FONT></DIV>
<DIV><FONT size=2>&nbsp;&nbsp;&nbsp; SELECT salesperson_id, SUM(tot_sales) sp_sales,<BR>&nbsp;&nbsp;&nbsp; <STRONG>RANK( ) OVER </STRONG>(ORDER BY SUM(tot_sales) DESC) sales_rank<BR>&nbsp;&nbsp;&nbsp; FROM orders<BR>&nbsp;&nbsp;&nbsp; GROUP BY salesperson_id</FONT></DIV>
<DIV><FONT size=2>3.3 NTILE 把纪录平分成甲乙丙丁四等 <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 比如我想取得前25%的纪录,或者把25%的纪录当作同一个level平等对待,把另25%当作另一个Level平等对待</FONT></DIV>
<DIV><FONT size=2>&nbsp;&nbsp;&nbsp; SELECT cust_nbr, SUM(tot_sales) cust_sales,<BR>&nbsp;&nbsp;&nbsp; <STRONG>NTILE(4) OVER </STRONG>(ORDER BY SUM(tot_sales) DESC) sales_quartile<BR>&nbsp;&nbsp;&nbsp; FROM orders<BR>&nbsp;&nbsp;&nbsp; GROUP BY cust_nbr<BR>&nbsp;&nbsp;&nbsp; ORDER BY 3,2 DESC;NTITLE(4)把纪录以 SUM(tot_sales)排序分成4份.</FONT></DIV>
<DIV><FONT size=2></FONT>&nbsp;</DIV>
<DIV><FONT size=2>3.4 辅助分析列和Windows Function<BR>&nbsp;&nbsp;&nbsp;&nbsp; 报表除了基本事实数据外,总希望旁边多些全年总销量,到目前为止的累计销量,前后三个月的平均销量这样的列来参考.<BR>&nbsp;&nbsp;&nbsp; 这种前后三个月的平均和到目前为止的累计销量就叫windows function, 见下例&nbsp;&nbsp;&nbsp; SELECT month, SUM(tot_sales) monthly_sales,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SUM(SUM(tot_sales)) OVER (ORDER BY month<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <STRONG>ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW</STRONG>) max_preceeding<BR>&nbsp;&nbsp;&nbsp; FROM orders<BR>&nbsp;&nbsp;&nbsp; GROUP BY month<BR>&nbsp;&nbsp;&nbsp; ORDER BY month;<BR><BR><BR><BR>&nbsp;&nbsp;&nbsp; SELECT month, SUM(tot_sales) monthly_sales,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AVG(SUM(tot_sales)) OVER (ORDER BY month <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <STRONG>ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING</STRONG>) rolling_avg&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; FROM orders<BR>&nbsp;&nbsp;&nbsp; GROUP BY month<BR>&nbsp;&nbsp;&nbsp; ORDER BY month;</FONT></DIV>
<DIV><FONT size=2>&nbsp;&nbsp;&nbsp; Windows Function的关键就是Windows子句的几个取值<BR>&nbsp;&nbsp;&nbsp; 1 PRECEDING 之前的一条记录<BR>&nbsp;&nbsp;&nbsp; 1 FOLLOWING 之后的一条记录<BR>&nbsp;&nbsp;&nbsp; UNBOUNDED PRECEDING 之前的所有记录<BR>&nbsp;&nbsp;&nbsp; CURRENT ROW 当前纪录</FONT></DIV>
<DIV><FONT size=2></FONT>&nbsp;</DIV>
<DIV><FONT size=2><STRONG>4.SubQuery总结</STRONG><BR>&nbsp; SubQuery天天用了,理论上总结一下.SubQuery 分三种<BR>&nbsp; 1.Noncorrelated 子查询&nbsp;&nbsp; 最普通的样式.<BR>&nbsp; 2.Correlated Subqueries&nbsp; 把父查询的列拉到子查询里面去,头一回cyt教我的时候理解了半天.<BR>&nbsp; 3.Inline View&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 也被当成最普通的样式用了.</FONT></DIV>
<DIV><FONT size=2></FONT>&nbsp;</DIV>
<DIV><FONT size=2>&nbsp; 然后Noncorrelated 子查询又有三种情况<BR>&nbsp; 1.返回一行一列&nbsp;&nbsp;&nbsp; where price &lt; (select max(price) from goods )<BR>&nbsp;&nbsp;2.返回多行一列&nbsp;&nbsp;&nbsp; where price&gt;= ALL (select price from goods where type=2)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;or where NOT price&lt; ANY(select price from goods where type=2)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;最常用的IN其实就是=ANY()<BR>&nbsp; 3.返回多行多列&nbsp;&nbsp;&nbsp; 一次返回多列当然就节省了查询时间 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UPDATE monthly_orders&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SET (tot_orders, max_order_amt) =<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;(SELECT COUNT(*), MAX(sale_price)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FROM cust_order)<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>DELETE FROM line_item<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WHERE (order_nbr, part_nbr) IN<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (SELECT order_nbr, part_nbr FROM cust_order c)</FONT></DIV></TD></TR></SPAN><img src ="http://www.blogjava.net/terry-zj/aggbug/22786.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2005-12-06 22:04 <a href="http://www.blogjava.net/terry-zj/archive/2005/12/06/22786.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于数据库名(db_name)、实例名(instance_name)、ORACLE_SID (转载)</title><link>http://www.blogjava.net/terry-zj/archive/2005/12/06/22784.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Tue, 06 Dec 2005 13:57:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2005/12/06/22784.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/22784.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2005/12/06/22784.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/22784.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/22784.html</trackback:ping><description><![CDATA[<P><FONT size=2>数据库名(DB_NAME)、实例名(Instance_name)、以及操作系统环境变量(ORACLE_SID) </FONT></P>
<P><FONT size=2>在ORACLE7、8数据库中只有数据库名(db_name)和数据库实例名(instance_name)。在ORACLE8i、9i中出现了新的参数，即数据库域名(db_domain)、服务名(service_name)、以及操作系统环境变量(ORACLE_SID)。这些都存在于同一个数据库中的标识，用于区分不同数据库的参数。 </FONT></P>
<P><FONT size=2>一、什么是数据库名(db_name)? 数据库名是用于区分数据的内部标识，是以二进制方式存储于数据库控制文件中的参数，在数据安装或创建之后将不得修改。数据库安装完成后，该参数被写入数据库参数文件pfile中，格式如下： </FONT></P>
<P><FONT size=2>db_name="orcl" <BR>db_domain=dbcenter.toys.com <BR>instance_name=orcl <BR>service_names=orcl.dbcenter.toys.com <BR>control_file=...............<BR><BR>在每一个运行的ORACLE8i数据库中都有一个数据库名(db_name),如果一个服务器程序中创建了两个数据库，则有两个数据库名。其控制参数据分属在不同的pfile中控制着相关的数据库。 </FONT></P>
<P><FONT size=2>二、什么是数据库实例名(instance_name) 数据库实例名则用于和操作系统之间的联系，用于对外部连接时使用。在操作系统中要取得与数据库之间的交互，必须使用数据库实例名。例如，要和某一个数据库server连接，就必须知道其数据库实例名，只知道数据库名是没有用的，与数据库名不同，在数据安装或创建数据库之后，实例名可以被修改。数据库安装完成后，该实例名被写入数据库参数文件pfile中，格式如下： <BR>db_name="orcl" #(不允许修改) <BR>db_domain=dbcenter.toys.com <BR>instance_name=orcl #(可以修改,可以与db_name相同也可不同) <BR>service_names=orcl.dbcenter.toys.com <BR>control_file=...............<BR>数据库名与实例名之间的关系。 数据库名与实例名之间的关系一般是一一对应关系，有一个数据库名就有一个实例名，如果在一个服务器中创建两个数据库，则有两个数据库名，两个数据库实例名，用两个标识确定一个数据库，用户和实例相连接。 但在8i、9i的并行服务器结构中，数据库与实例之间不存在一一对应关系，而是一对多关系，(一个数据库对应多个实例，同一时间内用户只一个实例相联系，当某一实例出现故障，其它实例自动服务，以保证数据库安全运行。) </FONT></P>
<P><FONT size=2>三、操作系统环境变量(ORACLE_SID) 在实际中，对于数据库实例名的描述有时使用实例名(instance_name)参数，有时使用ORACLE_SID参数。这两个都是数据库实例名，它们有什么区别呢？(经常弄混) </FONT></P>
<P><FONT size=2>(ORACLE_SID) OS&lt;----------------&gt; ORACLE 数据库 &lt;--------(Instance_name(实例名)) </FONT></P>
<P><FONT size=2>上图表示实例名instance_name、ORACLE_SID与数据库及操作系统之间的关系，虽然这里列出的两个参数都是数据库实例名，但instance_name参数是ORACLE数据库的参数，此参数可以在参数文件中查询到，而ORACLE_SID参数则是操作系统环境变量。 操作系统环境变量ORACLE_SID用于和操作系统交互。也就是说，在操作系统中要想得到实例名，就必须使用ORACLE_SID。此参数与ORACLE_BASE、ORACLE_HOME等用法相同。在数据库安装之后，ORACLE_SID被用于定义数据库参数文件的名称。如： $ORACLE_BASE/admin/DB_NAME/pfile/init$ORACLE_SID.ora。 定义方法:&nbsp; export ORACLE_SID=orcl </FONT></P>
<P><FONT size=2>如果在同一服务器中创建了多个数据库，则必然同时存在多个数据库实例,这时可以重复上述定义过程，以选择不同实例。 </FONT></P>
<P><FONT size=2>还可以用 [oracle@Datacent]$ . oraenv 来切换不同的ORACLE_SID来通过操作系统来启动不同的实例(instance)</FONT></P><img src ="http://www.blogjava.net/terry-zj/aggbug/22784.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2005-12-06 21:57 <a href="http://www.blogjava.net/terry-zj/archive/2005/12/06/22784.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Tomcat 5.5 配置(转载)</title><link>http://www.blogjava.net/terry-zj/archive/2005/12/06/22646.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Mon, 05 Dec 2005 16:13:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2005/12/06/22646.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/22646.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2005/12/06/22646.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/22646.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/22646.html</trackback:ping><description><![CDATA[<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US><FONT face=Century>Tomcat 5.5 配置</FONT></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US><FONT face=Century>&nbsp;<?xml:namespace prefix = o /><o:p></o:p></FONT></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US><FONT face=Century>1.</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">下</SPAN><SPAN style="FONT-FAMILY: SimSun">载</SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">：</SPAN></FONT></P><FONT size=2>Release Notes: http://tomcat.apache.org/tomcat-5.5-doc/RELEASE-NOTES<BR>Change Log: http://tomcat.apache.org/tomcat-5.5-doc/changelog.html<BR>Downloads: http://tomcat.apache.org/download-55.cgi</FONT>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">把</SPAN><U><SPAN lang=EN-US style="COLOR: blue"><FONT face=Century>jakarta-tomcat-5.5.x.zip</FONT></SPAN></U></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">和</SPAN><U><SPAN lang=EN-US style="COLOR: blue"><FONT face=Century>jakarta-tomcat-5.5.x-compat.zip</FONT></SPAN></U></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">和</SPAN><U><SPAN lang=EN-US style="COLOR: purple"><FONT face=Century>jakarta-tomcat-5.5.x-admin.zip</FONT></SPAN></U><SPAN lang=EN-US><BR><FONT face=Century>(Tomcat </FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">默</SPAN><SPAN style="FONT-FAMILY: SimSun">认</SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">是没有内置</SPAN><SPAN lang=EN-US><FONT face=Century>admin</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">模</SPAN><SPAN style="FONT-FAMILY: SimSun">块</SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">了</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US><FONT face=Century>Tomcat's administration web application is no longer installed by default. Download and install the "admin" package to use it. )</FONT></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">都解</SPAN><SPAN style="FONT-FAMILY: SimSun">压</SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">到同一个目</SPAN><SPAN style="FONT-FAMILY: SimSun">录</SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">下面。比如：</SPAN><SPAN lang=EN-US><FONT face=Century>D:\jakarta-tomcat-5.5.x\</FONT></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US><FONT face=Century>(</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">如果使用</SPAN><SPAN lang=EN-US><FONT face=Century>jdk1.4</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">，才需要</SPAN><U><SPAN lang=EN-US style="COLOR: blue"><FONT face=Century>compat.zip</FONT></SPAN></U><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">用</SPAN><SPAN lang=EN-US><FONT face=Century>jdk1.5</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">就可以免了</SPAN><SPAN style="FONT-FAMILY: SimSun">这</SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">个。</SPAN><SPAN lang=EN-US><FONT face=Century>) </FONT></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US></SPAN></FONT>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US><FONT face=Century>2.</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">修改</SPAN><SPAN lang=EN-US><FONT face=Century>jakarta-tomcat-5.5.x\conf\tomcat-users.xml.<BR></FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">添加管理</SPAN><SPAN style="FONT-FAMILY: SimSun">员账</SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">号</SPAN><SPAN lang=EN-US><FONT face=Century>lizongbo</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">，密</SPAN><SPAN style="FONT-FAMILY: SimSun">码为</SPAN><SPAN lang=EN-US><FONT face=Century>lizongbopass.<BR></FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">新</SPAN><SPAN lang=EN-US><FONT face=Century>xml</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">如下：</SPAN><SPAN lang=EN-US><BR><FONT face=Century>&lt;?xml version='1.0' encoding='utf-8'?&gt;<BR>&lt;tomcat-users&gt;<BR>&nbsp; &lt;role rolename="tomcat"/&gt;<BR>&nbsp; &lt;role rolename="role1"/&gt;<BR>&nbsp; &lt;role rolename="manager"/&gt;<BR>&nbsp; &lt;role rolename="admin"/&gt;<BR>&nbsp; &lt;user username="tomcat" password="tomcat" roles="tomcat"/&gt;<BR>&nbsp; &lt;user username="role1" password="tomcat" roles="role1"/&gt;<BR>&nbsp; &lt;user username="both" password="tomcat" roles="tomcat,role1"/&gt;<BR>&nbsp; &lt;user username="lizongbo" password="lizongbopass" roles="admin,manager"/&gt;<BR>&lt;/tomcat-users&gt;</FONT></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US></SPAN></FONT>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US><FONT face=Century>3.</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">修改</SPAN><SPAN lang=EN-US><FONT face=Century>jakarta-tomcat-5.5.x\conf\server.xml</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">来解决</SPAN><SPAN style="FONT-FAMILY: SimSun">编码问题</SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">。<SPAN lang=EN-US><o:p></o:p></SPAN></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US><FONT face=Century>(</FONT></SPAN><SPAN style="FONT-FAMILY: SimSun">给</SPAN><SPAN lang=EN-US><FONT face=Century>Connector </FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">添加</SPAN><SPAN lang=EN-US><FONT face=Century>URIEncoding</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">参数</SPAN><SPAN lang=EN-US><BR></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">参考</SPAN></FONT><FONT face=Century size=2> <SPAN lang=EN-US><A href="http://blog.csdn.net/darkxie/archive/2004/10/25/TOMCATAPP.aspx"><FONT color=#0066cc>http://blog.csdn.net/darkxie/archive/2004/10/25/TOMCATAPP.aspx</FONT></A>)</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US><FONT face=Century>(</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">可以</SPAN><SPAN style="FONT-FAMILY: SimSun">设</SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">置成</SPAN><SPAN lang=EN-US><FONT face=Century>GB18030)<BR>&nbsp;&nbsp;&nbsp; &lt;Connector port="8080"<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; maxThreads="150" minSpareThreads="25" maxSpareThreads="75"<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enableLookups="false" redirectPort="8443" acceptCount="200"<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; connectionTimeout="20000" disableUploadTimeout="true" URIEncoding="GBK"<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; compression="on" compressionMinSize="2048" <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; noCompressionUserAgents="gozilla, traviata" <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; compressableMimeType="text/html,text/xml"/&gt;</FONT></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US></SPAN></FONT>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US><FONT face=Century>&nbsp;&nbsp;&nbsp; &lt;Connector port="8009" <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enableLookups="false" redirectPort="8443" protocol="AJP/1.3" URIEncoding="GBK"/&gt;</FONT></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US></SPAN></FONT>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US><FONT face=Century>4.</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">启用支持</SPAN><SPAN lang=EN-US><FONT face=Century>gzip</FONT></SPAN><SPAN style="FONT-FAMILY: SimSun">压缩</SPAN><SPAN lang=EN-US><FONT face=Century>.<BR>(</FONT><A href="http://www.linuxaid.com.cn/forum/showdoc.jsp?l=1&amp;i=81169"><FONT face=Century color=#0066cc>http://www.linuxaid.com.cn/forum/showdoc.jsp?l=1&amp;i=81169</FONT></A><FONT face=Century>)<BR></FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">添加下列属性</SPAN><SPAN lang=EN-US><BR><FONT face=Century>&nbsp;compression="on" <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; compressionMinSize="2048" <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; noCompressionUserAgents="gozilla, traviata" <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; compressableMimeType="text/html,text/xml"</FONT></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US></SPAN></FONT>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US><FONT face=Century>5.</FONT></SPAN><SPAN style="FONT-FAMILY: SimSun">设</SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">置虚</SPAN><SPAN style="FONT-FAMILY: SimSun">拟</SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">主机。</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">在</SPAN><SPAN lang=EN-US><FONT face=Century>jakarta-tomcat-5.5.x\</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">下建立文件</SPAN><SPAN style="FONT-FAMILY: SimSun">夹</SPAN><SPAN lang=EN-US><FONT face=Century>vhost\www.mydomain.com</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">。</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">然后修改</SPAN><SPAN lang=EN-US><FONT face=Century>jakarta-tomcat-5.5.x\conf\server.xml</FONT></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US></SPAN></FONT>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US><FONT face=Century>&lt;Engine defaultHost="localhost" name="Catalina"&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Host appBase="vhost/www.mydomain.com" name="</FONT><A href="http://www.mydomain.com/"><FONT face=Century color=#0066cc>www.mydomain.com</FONT></A><FONT face=Century>"&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/Host&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Host appBase="webapps" name="localhost"&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/Host&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Realm className="org.apache.catalina.realm.UserDatabaseRealm"/&gt;<BR>&nbsp;&nbsp;&nbsp; &lt;/Engine&gt;</FONT></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US></SPAN></FONT>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US><FONT face=Century>6.</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">添加数据</SPAN><SPAN style="FONT-FAMILY: SimSun">库驱动</SPAN><SPAN lang=EN-US><FONT face=Century>,</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">更新</SPAN><SPAN lang=EN-US><FONT face=Century>mail.jar</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">和</SPAN><SPAN lang=EN-US><FONT face=Century>actiovation.jar</FONT></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN style="FONT-FAMILY: SimSun">复</SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">制</SPAN><SPAN lang=EN-US><FONT face=Century>mysql-connector-java-3.0.16-ga-bin.jar,pg74.215.jdbc3.jar</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">到</SPAN><SPAN lang=EN-US><FONT face=Century> jakarta-tomcat-5.5.x\common\lib\</FONT></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN style="FONT-FAMILY: SimSun">还</SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">有</SPAN><SPAN lang=EN-US><FONT face=Century>javamail 1.3.2</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">的</SPAN><SPAN lang=EN-US><FONT face=Century>mail.jar</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">，</SPAN><SPAN lang=EN-US><FONT face=Century>jaf-1_0_2</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">的</SPAN><SPAN lang=EN-US><FONT face=Century> activation.jar</FONT></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US><FONT face=Century>msSQl 2000 JDBC sp3</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">，</SPAN><SPAN lang=EN-US><FONT face=Century>msbase.jar,msutil,jar,mssqlserver.jar</FONT></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US></SPAN></FONT>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US></SPAN></FONT>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US><FONT face=Century>7.</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">配置</SPAN><SPAN lang=EN-US><FONT face=Century>SSL</FONT></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">参考</SPAN></FONT><FONT face=Century size=2> <SPAN lang=EN-US><A href="http://jakarta.apache.org/tomcat/tomcat-5.5-doc/ssl-howto.html"><FONT color=#0066cc>http://jakarta.apache.org/tomcat/tomcat-5.5-doc/ssl-howto.html</FONT></A></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US><FONT face=Century>D:\j2sdk1.4.2_06\bin&gt;%JAVA_HOME%\bin\keytool -genkey -alias tomcat -keyalg RSA<BR></FONT></SPAN><SPAN style="FONT-FAMILY: SimSun">输</SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">入</SPAN><SPAN lang=EN-US><FONT face=Century>keystore</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">密</SPAN><SPAN style="FONT-FAMILY: SimSun">码</SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">：</SPAN><SPAN lang=EN-US><FONT face=Century>&nbsp; lizongbossl<BR></FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">您的名字与姓氏是什</SPAN><SPAN style="FONT-FAMILY: SimSun">么</SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">？</SPAN><SPAN lang=EN-US><BR><FONT face=Century>&nbsp; </FONT></SPAN><SPAN lang=EN-US><FONT face=Century>[tomcat5.5.x]</FONT></SPAN><SPAN lang=ZH-CN style="FONT-FAMILY: 'ＭＳ 明朝'">：</SPAN><SPAN lang=EN-US><FONT face=Century>&nbsp; tomcat5.5.x<BR></FONT></SPAN><SPAN lang=ZH-CN style="FONT-FAMILY: 'ＭＳ 明朝'">您的</SPAN><SPAN lang=ZH-CN style="FONT-FAMILY: SimSun">组织单</SPAN><SPAN lang=ZH-CN style="FONT-FAMILY: 'ＭＳ 明朝'">位名称是什</SPAN><SPAN lang=ZH-CN style="FONT-FAMILY: SimSun">么</SPAN><SPAN lang=ZH-CN style="FONT-FAMILY: 'ＭＳ 明朝'">？</SPAN><SPAN lang=EN-US><BR><FONT face=Century>&nbsp; </FONT></SPAN><SPAN lang=EN-US><FONT face=Century>[jakarta]</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">：</SPAN><SPAN lang=EN-US><FONT face=Century>&nbsp; jakarta<BR></FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">您的</SPAN><SPAN style="FONT-FAMILY: SimSun">组织</SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">名称是什</SPAN><SPAN style="FONT-FAMILY: SimSun">么</SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">？</SPAN><SPAN lang=EN-US><BR><FONT face=Century>&nbsp; [apache]</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">：</SPAN><SPAN lang=EN-US><FONT face=Century>&nbsp; apache<BR></FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">您所在的城市或区域名称是什</SPAN><SPAN style="FONT-FAMILY: SimSun">么</SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">？</SPAN><SPAN lang=EN-US><BR><FONT face=Century>&nbsp; [hzcity]</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">：</SPAN><SPAN lang=EN-US><FONT face=Century>&nbsp; hzcity<BR></FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">您所在的州或省份名称是什</SPAN><SPAN style="FONT-FAMILY: SimSun">么</SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">？</SPAN><SPAN lang=EN-US><BR><FONT face=Century>&nbsp; [gdp]</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">：</SPAN><SPAN lang=EN-US><FONT face=Century>&nbsp; gdp<BR></FONT></SPAN><SPAN style="FONT-FAMILY: SimSun">该单</SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">位的两字母国家代</SPAN><SPAN style="FONT-FAMILY: SimSun">码</SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">是什</SPAN><SPAN style="FONT-FAMILY: SimSun">么</SPAN><SPAN lang=EN-US><BR><FONT face=Century>&nbsp; [CN]</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">：</SPAN><SPAN lang=EN-US><FONT face=Century>&nbsp; CN<BR>CN=tomcat5.5.x, OU=jakarta, O=apache, L=hzcity, ST=gdp, C=CN </FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">正确</SPAN><SPAN style="FONT-FAMILY: SimSun">吗</SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">？</SPAN><SPAN lang=EN-US><BR><FONT face=Century>&nbsp; </FONT></SPAN><SPAN lang=EN-US><FONT face=Century>[</FONT></SPAN><SPAN lang=ZH-CN style="FONT-FAMILY: 'ＭＳ 明朝'">否</SPAN><SPAN lang=EN-US><FONT face=Century>]</FONT></SPAN><SPAN lang=ZH-CN style="FONT-FAMILY: 'ＭＳ 明朝'">：</SPAN><SPAN lang=EN-US><FONT face=Century>&nbsp; y<o:p></o:p></FONT></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US><FONT face=Century>&nbsp;<o:p></o:p></FONT></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=ZH-CN style="FONT-FAMILY: SimSun">输</SPAN><SPAN lang=ZH-CN style="FONT-FAMILY: 'ＭＳ 明朝'">入</SPAN><SPAN lang=EN-US><FONT face=Century>&lt;tomcat&gt;</FONT></SPAN><SPAN lang=ZH-CN style="FONT-FAMILY: 'ＭＳ 明朝'">的主密</SPAN><SPAN lang=ZH-CN style="FONT-FAMILY: SimSun">码</SPAN><SPAN lang=EN-US><BR><FONT face=Century>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </FONT></SPAN><SPAN lang=ZH-CN style="FONT-FAMILY: 'ＭＳ 明朝'">（如果和</SPAN><SPAN lang=EN-US><FONT face=Century> keystore </FONT></SPAN><SPAN lang=ZH-CN style="FONT-FAMILY: 'ＭＳ 明朝'">密</SPAN><SPAN lang=ZH-CN style="FONT-FAMILY: SimSun">码</SPAN><SPAN lang=ZH-CN style="FONT-FAMILY: 'ＭＳ 明朝'">相同，按回</SPAN><SPAN lang=ZH-CN style="FONT-FAMILY: SimSun">车</SPAN><SPAN lang=ZH-CN style="FONT-FAMILY: 'ＭＳ 明朝'">）：</SPAN><SPAN lang=EN-US><o:p></o:p></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US><FONT face=Century>(</FONT></SPAN><SPAN lang=ZH-CN style="FONT-FAMILY: 'ＭＳ 明朝'">必</SPAN><SPAN lang=ZH-CN style="FONT-FAMILY: SimSun">须</SPAN><SPAN lang=ZH-CN style="FONT-FAMILY: 'ＭＳ 明朝'">密</SPAN><SPAN lang=ZH-CN style="FONT-FAMILY: SimSun">码</SPAN><SPAN lang=ZH-CN style="FONT-FAMILY: 'ＭＳ 明朝'">一致，因此直接回</SPAN><SPAN lang=ZH-CN style="FONT-FAMILY: SimSun">车</SPAN><SPAN lang=EN-US><FONT face=Century>)<o:p></o:p></FONT></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">然后再把</SPAN><SPAN lang=EN-US><FONT face=Century>userhome(</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">例如：</SPAN><SPAN lang=EN-US><FONT face=Century>C:\Documents and Settings\lizongbo\)</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">下的</SPAN><SPAN lang=EN-US><FONT face=Century>.keystore</FONT></SPAN><SPAN style="FONT-FAMILY: SimSun">复</SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">制到</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US><FONT face=Century>tomcat</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">的</SPAN><SPAN lang=EN-US><FONT face=Century>conf\</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">目</SPAN><SPAN style="FONT-FAMILY: SimSun">录</SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">下。</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US><FONT face=Century>&nbsp;(</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">例如：</SPAN><SPAN lang=EN-US><FONT face=Century>D:\jakarta-tomcat-5.5.x\conf\.keystore )</FONT></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">配置</SPAN><SPAN lang=EN-US><FONT face=Century>jakarta-tomcat-5.5.x\conf\server.xml</FONT></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">加上</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US><FONT face=Century>&nbsp;&nbsp;&nbsp; &lt;Connector port="8443" <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; maxThreads="150" minSpareThreads="25" maxSpareThreads="75"<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enableLookups="false" disableUploadTimeout="true"<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; acceptCount="100" scheme="https" secure="true"<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; clientAuth="false" sslProtocol="TLS" <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; keystoreFile="conf/.keystore" <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; keystorePass="lizongbossl"&gt; &lt;!--</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">与先前</SPAN><SPAN style="FONT-FAMILY: SimSun">设</SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">置的密</SPAN><SPAN style="FONT-FAMILY: SimSun">码</SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">一致</SPAN><SPAN lang=EN-US><FONT face=Century>--&gt;<BR>&nbsp;&nbsp;&nbsp; &lt;/Connector&gt;</FONT></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US><FONT face=Century>8.</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">禁止文件目</SPAN><SPAN style="FONT-FAMILY: SimSun">录</SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">列表，</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">修改</SPAN><SPAN lang=EN-US><FONT face=Century>jakarta-tomcat-5.5.x\conf\web.xml</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">，把</SPAN><SPAN lang=EN-US><FONT face=Century>listing</FONT></SPAN><SPAN style="FONT-FAMILY: SimSun">设</SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">置</SPAN><SPAN style="FONT-FAMILY: SimSun">为</SPAN><SPAN lang=EN-US><FONT face=Century>false</FONT></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US></SPAN></FONT>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US><FONT face=Century>&nbsp;&nbsp;&nbsp; &lt;servlet&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;servlet-name&gt;default&lt;/servlet-name&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;servlet-class&gt;org.apache.catalina.servlets.DefaultServlet&lt;/servlet-class&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;init-param&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param-name&gt;debug&lt;/param-name&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param-value&gt;0&lt;/param-value&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/init-param&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;init-param&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param-name&gt;listings&lt;/param-name&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param-value&gt;true&lt;/param-value&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/init-param&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;<BR>&nbsp;&nbsp;&nbsp; &lt;/servlet&gt;</FONT></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US></SPAN></FONT>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US><FONT face=Century>&nbsp;9.</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">指定了自己的</SPAN><SPAN lang=EN-US><FONT face=Century>javaEncoding</FONT></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US><FONT face=Century>(</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">参考</SPAN></FONT><FONT face=Century size=2> <SPAN lang=EN-US><A href="http://gceclub.sun.com.cn/staticcontent/html/sunone/app7/app7-dg-webapp/ch6/ch6-4.html"><FONT color=#0066cc>http://gceclub.sun.com.cn/staticcontent/html/sunone/app7/app7-dg-webapp/ch6/ch6-4.html</FONT></A>&nbsp;)</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US><BR><FONT face=Century>&nbsp;&nbsp;&nbsp; &lt;servlet&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;servlet-name&gt;jsp&lt;/servlet-name&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;servlet-class&gt;org.apache.jasper.servlet.JspServlet&lt;/servlet-class&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;init-param&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param-name&gt;fork&lt;/param-name&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param-value&gt;false&lt;/param-value&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/init-param&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;init-param&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param-name&gt;javaEncoding&lt;/param-name&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param-value&gt;GB18030&lt;/param-value&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/init-param&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;init-param&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param-name&gt;xpoweredBy&lt;/param-name&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param-value&gt;true&lt;/param-value&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/init-param&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;load-on-startup&gt;3&lt;/load-on-startup&gt;<BR>&nbsp;&nbsp;&nbsp; &lt;/servlet&gt;</FONT></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US><FONT face=Century>&nbsp;10.</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">添加</SPAN><SPAN lang=EN-US><FONT face=Century>rar,iso</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">等的</SPAN><SPAN lang=EN-US><FONT face=Century>mime-type</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">映射</SPAN><SPAN lang=EN-US><FONT face=Century> </FONT></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=ZH-CN style="FONT-FAMILY: 'ＭＳ 明朝'">避免在</SPAN><SPAN lang=ZH-CN style="FONT-FAMILY: SimSun">浏览</SPAN><SPAN lang=ZH-CN style="FONT-FAMILY: 'ＭＳ 明朝'">器里直接打</SPAN><SPAN lang=ZH-CN style="FONT-FAMILY: SimSun">开</SPAN><SPAN lang=ZH-CN style="FONT-FAMILY: 'ＭＳ 明朝'">。</SPAN><SPAN lang=EN-US><o:p></o:p></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US><FONT face=Century>&lt;mime-mapping&gt;<BR>&lt;extension&gt;mht&lt;/extension&gt;<BR>&lt;mime-type&gt;text/x-mht&lt;/mime-type&gt;<BR>&lt;/mime-mapping&gt;</FONT></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US><FONT face=Century>&lt;mime-mapping&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;extension&gt;rar&lt;/extension&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;mime-type&gt;application/octet-stream&lt;/mime-type&gt;<BR>&nbsp;&nbsp;&nbsp; &lt;/mime-mapping&gt;<BR>&nbsp;&nbsp;&nbsp; &lt;mime-mapping&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;extension&gt;iso&lt;/extension&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;mime-type&gt;application/octet-stream&lt;/mime-type&gt;<BR>&nbsp;&nbsp;&nbsp; &lt;/mime-mapping&gt;<BR>&nbsp;&nbsp;&nbsp; &lt;mime-mapping&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;extension&gt;ape&lt;/extension&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;mime-type&gt;application/octet-stream&lt;/mime-type&gt;<BR>&nbsp;&nbsp;&nbsp; &lt;/mime-mapping&gt;<BR>&nbsp;&nbsp;&nbsp; &lt;mime-mapping&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;extension&gt;rmvb&lt;/extension&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;mime-type&gt;application/octet-stream&lt;/mime-type&gt;<BR>&nbsp;&nbsp;&nbsp; &lt;/mime-mapping&gt;</FONT></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US><FONT face=Century>&nbsp;&nbsp;&nbsp; &lt;mime-mapping&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;extension&gt;ico&lt;/extension&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;mime-type&gt;image/x-icon&lt;/mime-type&gt;<BR>&nbsp;&nbsp;&nbsp; &lt;/mime-mapping&gt;</FONT></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US><FONT face=Century>10.1对html静态页面设置编码<BR>&nbsp;&nbsp;&nbsp; &lt;!--&nbsp; 修改下面两行以支持静态超文本的自动编码 --&gt; <BR>&nbsp;&nbsp;&nbsp; &lt;mime-mapping&gt;<BR>&nbsp;&nbsp;&nbsp; &lt;extension&gt;htm&lt;/extension&gt; <BR>&nbsp;&nbsp;&nbsp; &lt;mime-type&gt;text/html;charset=gb2312&lt;/mime-type&gt; <BR>&nbsp;&nbsp;&nbsp; &lt;/mime-mapping&gt;<BR>&nbsp;&nbsp;&nbsp; &lt;mime-mapping&gt;<BR>&nbsp;&nbsp;&nbsp; &lt;extension&gt;html&lt;/extension&gt; <BR>&nbsp;&nbsp;&nbsp; &lt;mime-type&gt;text/html;charset=gb2312&lt;/mime-type&gt; <BR>&nbsp;&nbsp;&nbsp; &lt;/mime-mapping&gt;<BR>&nbsp; &lt;/web-app&gt;<BR></FONT></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US><FONT face=Century><SPAN style="COLOR: blue"></SPAN></FONT></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US></SPAN></FONT>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US><FONT face=Century>11.</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">添加</SPAN><SPAN lang=EN-US><FONT face=Century>welcome-file-list</FONT></SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">，并</SPAN><SPAN style="FONT-FAMILY: SimSun">调</SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">整</SPAN><SPAN style="FONT-FAMILY: SimSun">顺</SPAN><SPAN style="FONT-FAMILY: 'ＭＳ 明朝'">序。</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US><FONT face=Century>&nbsp;&lt;welcome-file-list&gt;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;welcome-file&gt;index.jsp&lt;/welcome-file&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;welcome-file&gt;index.html&lt;/welcome-file&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;welcome-file&gt;index.htm&lt;/welcome-file&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;welcome-file&gt;default.html&lt;/welcome-file&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;welcome-file&gt;default.htm&lt;/welcome-file&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;welcome-file&gt;default.jsp&lt;/welcome-file&gt;<BR>&nbsp;&nbsp;&nbsp; &lt;/welcome-file-list&gt;</FONT></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0mm 0mm 0pt"><FONT size=2><SPAN lang=EN-US><o:p><FONT face=Century>&nbsp;</FONT></o:p></SPAN></FONT></P><img src ="http://www.blogjava.net/terry-zj/aggbug/22646.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2005-12-06 00:13 <a href="http://www.blogjava.net/terry-zj/archive/2005/12/06/22646.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>字符串中的正则表达式特殊符号(转载)</title><link>http://www.blogjava.net/terry-zj/archive/2005/12/05/22509.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Mon, 05 Dec 2005 02:31:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2005/12/05/22509.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/22509.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2005/12/05/22509.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/22509.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/22509.html</trackback:ping><description><![CDATA[<font size="2">字符串中的正则表达式特殊符号 <br><br>问题：<br>String s1="111+222+333";<br>System.out.println(s1.split("+").length);<br>//输出时提示错误：<br>java.util.regex.PatternSyntaxException: Dangling meta character '+' near index<br>问题出现在加号附近，查询相关的资料显示，+、*、|、\等符号在正则表达示中有相应的不同意义。<br><br>正则表达式的基本用法 zt &nbsp;&nbsp; &nbsp;<br>1、“.”为通配符，表示任何一个字符，例如：“a.c”可以匹配“anc”、“abc”、“acc”；<br>2、“[]”，在[]内可以指定要求匹配的字符，例如：“a[nbc]c”可以匹配“anc”、“abc”、“acc；<br>但不可以匹配“ancc”,a到z可以写成[a-z],0到9可以写成[0-9];<br><br>3、数量限定符号，表示匹配次数（或者叫做长度）的符号：<br><br>包括：“*”——0次或者多次<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; “+”——1次或者多次<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; “?”——0次或者1次<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; “{n}”——匹配n次，n为整数<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; “{n,m}”——匹配从n到m之间的某个数的次数；n和m都是整数；<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; “{n,}”——匹配n到无穷次之间任意次数；<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; “{,m}”——匹配0到m之间任意次数；<br>他们放到匹配格式的后面：<br>例如：<br>电话号码：024－84820482，02484820482(假设前面3或者4位，后面7或者8位，并且中间的减号可有可无)<br><br>都是符合规定的，那么可以用如下格式来匹配：[0-9]{3,4} \-? [0-9]{7,8}；<br>注意：“\”为转义字符，因为“-”在正则表达式用有代表一个范围的意义，例如：前面所说的[0-9]，<br>所以它需要转义字符“\”进行转义才可使用；<br><br>4、“^”为否符号，表示不想匹配的符号，例如：[^z][a-z]+可以匹配所有除“z”开头的以外的所有字<br><br>符串（长度大于2，因为“+”表示大于等于1的次数，从第二位开始都是小写英文字符）；<br>如果^放到[]的外边则表示以[]开头的字符串；^[az][a-z]+表示a或者z开头的长度大于等于2的英文字符串；<br><br>5、“|”或运算符，例如：a[n|bc|cb]c可以匹配“abcc”,“anc”,“acbc”；<br>6、“$”以它前面的字符结尾的；例如：ab+$就可以被“abb”，“ab”匹配；<br><br>7、一些简单表示方法：<br>\d表示[0-9];\D表示[^0-9];\w表示[A-Z0-9];\W表示[^A-Z0-9];\s表示[\t\n\r\f],就是空格字符包括tab，空格等等;\S表示[^\t\n\r\f]，就是非空格字符;<br><br><br>明白了这些以后，我们再返回头看看它们如何被运用呢？一般来讲只需要加[]、或是\\即可。<br><br>举例来讲：<br>String s1="111+222+333";<br>System.out.println(s1.split("[+]").length);<br>或是<br>String s1="111+222+333";<br>System.out.println(s1.split("\\+").length);<br><br>其他用法类同。</font><img src ="http://www.blogjava.net/terry-zj/aggbug/22509.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2005-12-05 10:31 <a href="http://www.blogjava.net/terry-zj/archive/2005/12/05/22509.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Calendar使用方法（转载）</title><link>http://www.blogjava.net/terry-zj/archive/2005/12/05/22506.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Mon, 05 Dec 2005 02:15:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2005/12/05/22506.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/22506.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2005/12/05/22506.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/22506.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/22506.html</trackback:ping><description><![CDATA[<font size="2">明海棠文集之日期时间1.0<br><br>--------它不是原创，是一种思念<br><br>Java 语言的Calendar，GregorianCalendar (日历),Date(日期), 和DateFormat(日期格式)组成了Java标准的一个基本但是非常重要的部分. 日期是商业逻辑计算一个关键的部分. 所有的开发者都应该能够计算未来的日期, 定制日期的显示格式, 并将文本数据解析成日期对象。学习日期, 日期格式, 日期的解析和日期的计算。 <br><br>我们将讨论下面的类: <br><br>1、&nbsp; 具体类(和抽象类相对)java.util.Date <br><br>2、&nbsp; 抽象类java.text.DateFormat 和它的一个具体子类,java.text.SimpleDateFormat <br><br>3、&nbsp; 抽象类java.util.Calendar 和它的一个具体子类,java.util.GregorianCalendar <br><br>具体类可以被实例化, 但是抽象类却不能. 你首先必须实现抽象类的一个具体子类.<br><br>1.&nbsp;&nbsp; java.util.Date及其格式化<br>Date 类从Java 开发包(JDK) 1.0 就开始进化, 当时它只包含了几个取得或者设置一个日期数据的各个部分的方法, 比如说月, 日, 和年. 这些方法现在遭到了批评并且已经被转移到了Calendar类里去了, 我们将在本文中进一步讨论它. 这种改进旨在更好的处理日期数据的国际化格式. 就象在JDK 1.1中一样, Date 类实际上只是一个包裹类, 它包含的是一个长整型数据, 表示的是从GMT(格林尼治标准时间)1970年, 1 月 1日00:00:00这一刻之前或者是之后经历的毫秒数. <br><br>1.1. 创建java.util.Date<br>Java统计从1970年1月1日起的毫秒的数量表示日期。也就是说，例如，1970年1月2日，是在1月1日后的86，400，000毫秒。同样的，1969年12月31日是在1970年1月1日前86，400，000毫秒。Java的Date类使用long类型纪录这些毫秒值.因为long是有符号整数，所以日期可以在1970年1月1日之前，也可以在这之后。Long类型表示的最大正值和最大负值可以轻松的表示290，000，000年的时间，这适合大多数人的时间要求。<br><br>让我们看一个使用系统的当前日期和时间创建一个日期对象并返回一个长整数的简单例子. 这个时间通常被称为Java 虚拟机(JVM)主机环境的系统时间. <br>import java.util.Date; <br><br>public class DateExample1 { <br><br>public static void main(String[] args) { <br><br>// Get the system date/time <br><br>Date date = new Date(); <br><br>// 打印出具体的年，月，日，小时，分钟，秒钟以及时区<br><br>System.out.println(date.getTime()); <br><br>}&nbsp;&nbsp; <br><br>} <br><br>在星期六, 2001年9月29日, 下午大约是6:50的样子, 上面的例子在系统输出设备上显示的结果是 1001803809710. 在这个例子中,值得注意的是我们使用了Date 构造函数创建一个日期对象, 这个构造函数没有接受任何参数. 而这个构造函数在内部使用了System.currentTimeMillis() 方法来从系统获取日期. <br><br>//1年前日期<br><br>&nbsp;&nbsp; java.util.Date myDate=new java.util.Date();&nbsp; <br><br>&nbsp;&nbsp; long myTime=(myDate.getTime()/1000)-60*60*24*365;<br><br>&nbsp;&nbsp; myDate.setTime(myTime*1000);<br><br>&nbsp;&nbsp; String mDate=formatter.format(myDate);<br><br>//明天日期<br><br>&nbsp;&nbsp; myDate=new java.util.Date(); <br><br>&nbsp;&nbsp; myTime=(myDate.getTime()/1000)+60*60*24;<br><br>&nbsp;&nbsp; myDate.setTime(myTime*1000);<br><br>&nbsp;&nbsp; mDate=formatter.format(myDate);<br><br>//两个时间之间的天数<br><br>&nbsp;&nbsp; SimpleDateFormat myFormatter = new SimpleDateFormat("yyyy-MM-dd");<br><br>&nbsp;&nbsp; java.util.Date date= myFormatter.parse("2003-05-1"); <br><br>&nbsp;&nbsp; java.util.Date mydate= myFormatter.parse("1899-12-30");<br><br>&nbsp;&nbsp; long&nbsp; day=(date.getTime()-mydate.getTime())/(24*60*60*1000);<br><br>//加半小时<br><br>SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");<br><br>java.util.Date date1 = format.parse("2002-02-28 23:16:00");<br><br>long Time=(date1.getTime()/1000)+60*30;<br><br>date1.setTime(Time*1000);<br><br>String mydate1=formatter.format(date1);<br><br>//年月周求日期<br><br>SimpleDateFormat formatter2 = new SimpleDateFormat("yyyy-MM F E");<br><br>java.util.Date date2= formatter2.parse("2003-05 5 星期五"); <br><br>SimpleDateFormat formatter3 = new SimpleDateFormat("yyyy-MM-dd");<br><br>String mydate2=formatter3.format(date2);<br><br>//求是星期几<br><br>mydate= myFormatter.parse("2001-1-1");<br><br>SimpleDateFormat formatter4 = new SimpleDateFormat("E");<br><br>String mydate3=formatter4.format(mydate);<br><br>&nbsp;<br>&nbsp;<br><br>&nbsp;<br><br>1.2. Date格式化<br>能以一种用户明白的格式来显示这个日期呢? 在这里类java.text.SimpleDateFormat 和它的抽象基类 java.text.DateFormat。那么, 现在我们已经知道了如何获取从1970年1月1日开始经历的毫秒数了. 我们如何才format 就派得上用场了. <br><br>// 我们能不能用下面的代码构件出 2001/8/8 8:8<br>&nbsp;&nbsp;&nbsp; import java.io.*;<br>&nbsp;&nbsp;&nbsp; import java.util.*;<br>&nbsp;<br>&nbsp;&nbsp;&nbsp; public class WhatIsDate<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static void main(String[] args) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Date date = new Date(2001, 8, 8, 8, 8, 8);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(date);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;<br><br>Java 的编译器竟然报如下信息 (Sun JDK1.3, Windows 2000 中文下)<br><br>注意：<br>WhatIsDate.java 使用或覆盖一个不鼓励使用的API。<br>注意：<br>使用-deprecation重新编译，以得到详细信息。！<br>&nbsp;<br><br>那么 Date 对象究竟是为了满足哪个需求呢？看来它不是用来实现基于年/月/日小时:分钟 的时间表述。我们查看 Java 的文档，我们看到有 getTime() 方法，它返回的竟然是一个 long 值。<br><br>文档进一步又告诉我们这个值代表了当前系统的时间离1970/1/1 0:0 的毫秒差，而且是在 GMT 时区下(也被称为 EPOC)。如果我们指定的时间是在此之前的，那它将返回一个负数值。<br><br>这个发现让我们对 Date 对象有了一个全新的认识-Date 存放的是与 EPOC 的偏差值。换而言之我们也可通过 long 类型来表示时间？对了，这个猜想是得到了 Java 的支持：<br><br>&nbsp;&nbsp; // 第二种获得当前时间的方法<br>&nbsp;&nbsp;&nbsp; long dateInMilliSeconds = System.currentTimeMillis();<br>&nbsp;&nbsp;&nbsp; // 这时候打印出的只是一串数字而已<br>&nbsp;&nbsp;&nbsp; System.out.println(dateInMilliSeconds);<br>&nbsp;<br><br>对程序执行效率敏感的程序员可以发现这个方法只是生成一个 Java 的原始类型 (primitive type) long, 不需要实例化一个对象。因此如果我们对时间的处理只是在内部进行时，可以用 long 来代替 Date 对象。<br><br>最典型的应用就是在一段代码开始和结束时,分别获得系统当前的时间,然后计算出代码执行所需的时间(微秒级)。<br><br>&nbsp;&nbsp; long start = System.currentTimeMillis();<br>&nbsp;&nbsp;&nbsp; // 代码段<br>&nbsp;&nbsp;&nbsp; System.out.println("需要 "+(System.currentTimeMillis()-start)+" 微秒");<br>&nbsp;<br><br>那么当我们要把这个 long 值已更为友好的表现形式显示处理的时候，我们可以用它来构造 Date 对象：<br><br>Date date = new Date(dateInMilliSeconds);<br><br>System.out.println(date);<br>&nbsp;<br><br>我们看到了在 Java 中对时间最为基本的表示，有通过对EPOC 的偏差值进行处理。Date 对象是对它的一个对象的封装。我们同时也看到了，在现时世界中我们对时间的描述通常是通过"某年某月某日某时某分"来定义的。Date 的显示(实际上是 toString() 方法)描述了这些信息，但 Java 并不建议我们用这种方式直接来构件 Date 对象。因此我们需要找出哪个对象可以实现这个需求。这就是我们下面就要讲述的 Calendar 对象的功能。<br><br>在我们进一步研究 Calendar 之前，请记住 Date 只是一个对 long 值(基于 GMT 时区)的对象封装。它所表现出来的年/月/日小时:分钟时区的时间表述，只是它的 toString() 方法所提供的。千万不要为这个假象所迷惑。<br><br>假如我们希望定制日期数据的格式, 比方星期六-9月-29日-2001年. 下面的例子展示了如何完成这个工作: <br><br>import java.text.SimpleDateFormat; <br><br>import java.util.Date; <br><br>public class DateExample2 { <br><br>public static void main(String[] args) { <br><br>SimpleDateFormat bartDateFormat = new SimpleDateFormat("EEEE-MMMM-dd-yyyy"); Date date = new Date(); <br><br>System.out.println(bartDateFormat.format(date)); <br><br>}<br><br>}<br>&nbsp;<br><br>只要通过向SimpleDateFormat 的构造函数传递格式字符串"EEE-MMMM-dd-yyyy", 我们就能够指明自己想要的格式. 你应该可以看见, 格式字符串中的ASCII 字符告诉格式化函数下面显示日期数据的哪一个部分. EEEE是星期, MMMM是月, dd是日, yyyy是年. 字符的个数决定了日期是如何格式化的.传递"EE-MM-dd-yy"会显示 Sat-09-29-01. 请察看Sun 公司的Web 站点获取日期格式化选项的完整的指示. <br><br>1.3. 文本数据解析成日期对象 <br>假设我们有一个文本字符串包含了一个格式化了的日期对象, 而我们希望解析这个字符串并从文本日期数据创建一个日期对象. 我们将再次以格式化字符串"MM-dd-yyyy" 调用SimpleDateFormat类, 但是这一次, 我们使用格式化解析而不是生成一个文本日期数据. 我们的例子, 显示在下面, 将解析文本字符串"9-29-2001"并创建一个值为001736000000 的日期对象. <br><br>通过parse()方法，DateFormat能够以一个字符串创立一个Date对象。这个方法能抛出ParseException异常，所以你必须使用适当的异常处理技术。<br><br>例子程序: <br><br>import java.text.SimpleDateFormat; <br><br>import java.util.Date; <br><br>public class DateExample3 { <br><br>public static void main(String[] args) { <br><br>// Create a date formatter that can parse dates of <br><br>// the form MM-dd-yyyy. <br><br>SimpleDateFormat bartDateFormat = new SimpleDateFormat("MM-dd-yyyy"); <br><br>// Create a string containing a text date to be parsed. <br><br>String dateStringToParse = "9-29-2001"; <br><br>try { <br><br>// Parse the text version of the date. <br><br>// We have to perform the parse method in a <br><br>// try-catch construct in case dateStringToParse <br><br>// does not contain a date in the format we are expecting. <br><br>Date date = bartDateFormat.parse(dateStringToParse); <br><br>// Now send the parsed date as a long value <br><br>// to the system output. <br><br>System.out.println(date.getTime()); <br><br>}catch (Exception ex) { <br><br>System.out.println(ex.getMessage()); <br><br>}<br><br>} <br><br>} <br>&nbsp;<br><br>1.4. 使用标准的日期格式化过程 <br>既然我们已经可以生成和解析定制的日期格式了, 让我们来看一看如何使用内建的格式化过程. 方法 DateFormat.getDateTimeInstance() 让我们得以用几种不同的方法获得标准的日期格式化过程. 在下面的例子中, 我们获取了四个内建的日期格式化过程. 它们包括一个短的, 中等的, 长的, 和完整的日期格式. <br><br>import java.text.DateFormat; <br><br>import java.util.Date; <br><br>public class DateExample4 { <br><br>public static void main(String[] args) { <br><br>Date date = new Date(); <br><br>DateFormat shortDateFormat = DateFormat.getDateTimeInstance( <br><br>DateFormat.SHORT, DateFormat.SHORT); <br><br>DateFormat mediumDateFormat = DateFormat.getDateTimeInstance( <br><br>DateFormat.MEDIUM, DateFormat.MEDIUM); <br><br>DateFormat longDateFormat = DateFormat.getDateTimeInstance( <br><br>DateFormat.LONG, DateFormat.LONG); <br><br>DateFormat fullDateFormat = DateFormat.getDateTimeInstance( <br><br>DateFormat.FULL, DateFormat.FULL); <br><br>System.out.println(shortDateFormat.format(date)); System.out.println(mediumDateFormat.format(date)); System.out.println(longDateFormat.format(date)); System.out.println(fullDateFormat.format(date)); <br><br>} <br><br>} <br><br>注意我们在对 getDateTimeInstance的每次调用中都传递了两个值. 第一个参数是日期风格, 而第二个参数是时间风格. 它们都是基本数据类型int(整型). 考虑到可读性, 我们使用了DateFormat 类提供的常量: SHORT, MEDIUM, LONG, 和 FULL. 要知道获取时间和日期格式化过程的更多的方法和选项, 请看Sun 公司Web 站点上的解释. <br><br>运行我们的例子程序的时候, 它将向标准输出设备输出下面的内容: <br>9/29/01 8:44 PM <br>Sep 29, 2001 8:44:45 PM <br>September 29, 2001 8:44:45 PM EDT <br>Saturday, September 29, 2001 8:44:45 PM EDT <br><br>2.&nbsp;&nbsp; Calendar 日历类 <br>首先请记住 Calendar 只是一个抽象类, 也就是说你无法直接获得它的一个实例，换而言之你可以提供一个自己开发的 Calendar 对象。<br><br>那究竟什么是一个 Calendar 呢？中文的翻译就是日历，那我们立刻可以想到我们生活中有阳(公)历、阴(农)历之分。它们的区别在哪呢？<br><br>比如有：<br><br>月份的定义 - 阳`(公)历 一年12 个月，每个月的天数各不同；阴(农)历，每个月固定28天,每周的第一天 - 阳(公)历星期日是第一天；阴(农)历，星期一是第一天<br><br>实际上，在历史上有着许多种纪元的方法。它们的差异实在太大了，比如说一个人的生日是"八月八日" 那么一种可能是阳(公)历的八月八日，但也可以是阴(农)历的日期。所以为了计时的统一，必需指定一个日历的选择。那现在最为普及和通用的日历就是 "Gregorian Calendar"。也就是我们在讲述年份时常用 "公元几几年"。Calendar 抽象类定义了足够的方法，让我们能够表述日历的规则。Java 本身提供了对 "Gregorian Calendar" 规则的实现。我们从 Calendar.getInstance() 中所获得的实例就是一个 "GreogrianCalendar" 对象(与您通过 new GregorianCalendar() 获得的结果一致)。<br><br>下面的代码可以证明这一点：<br><br>&nbsp;&nbsp; import java.io.*;<br>&nbsp;&nbsp;&nbsp; import java.util.*;<br>&nbsp;<br>&nbsp;&nbsp;&nbsp; public class WhatIsCalendar<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static void main(String[] args) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Calendar calendar = Calendar.getInstance();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (calendar instanceof GregorianCalendar)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("It is an instance of GregorianCalendar");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;<br><br>&nbsp;<br><br>Calendar 在 Java 中是一个抽象类(Abstract Class)，GregorianCalendar 是它的一个具体实现。<br><br>Calendar 与 Date 的转换非常简单：<br><br>&nbsp;&nbsp; Calendar calendar = Calendar.getInstance();<br>&nbsp;&nbsp;&nbsp; // 从一个 Calendar 对象中获取 Date 对象<br>&nbsp;&nbsp;&nbsp; Date date = calendar.getTime();<br>&nbsp;&nbsp;&nbsp; // 将 Date 对象反应到一个 Calendar 对象中，<br>&nbsp;&nbsp;&nbsp; // Calendar/GregorianCalendar 没有构造函数可以接受 Date 对象<br>&nbsp;&nbsp;&nbsp; // 所以我们必需先获得一个实例，然后设置 Date 对象<br>&nbsp;&nbsp;&nbsp; calendar.setTime(date);<br>&nbsp;<br>&nbsp;<br><br>&nbsp;<br><br>Calendar 对象在使用时，有一些值得注意的事项：<br><br>1. Calendar 的 set() 方法<br><br>set(int field, int value) - 是用来设置"年/月/日/小时/分钟/秒/微秒"等值<br><br>field 的定义在 Calendar 中<br><br>set(int year, int month, int day, int hour, int minute, int second) 但没有set(int year, int month, int day, int hour, int minute, int second, int millisecond) 前面 set(int,int,int,int,int,int) 方法不会自动将 MilliSecond 清为 0。<br><br>另外，月份的起始值为０而不是１，所以要设置八月时，我们用７而不是8。<br><br>calendar.set(Calendar.MONTH, 7);<br><br>我们通常需要在程序逻辑中将它清为 0，否则可能会出现下面的情况：<br><br>&nbsp;&nbsp; import java.io.*;<br>&nbsp;&nbsp;&nbsp; import java.util.*;<br>&nbsp;<br>&nbsp;&nbsp;&nbsp; public class WhatIsCalendarWrite<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static void main(String[] args) throws Exception{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ObjectOutputStream out =<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new ObjectOutputStream(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new FileOutputStream("calendar.out"));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Calendar cal1 = Calendar.getInstance();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cal1.set(2000, 7, 1, 0, 0, 0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.writeObject(cal1);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Calendar cal2 = Calendar.getInstance();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cal2.set(2000, 7, 1, 0, 0, 0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cal2.set(Calendar.MILLISECOND, 0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.writeObject(cal2);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.close();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;<br><br>我们将 Calendar 保存到文件中<br><br>&nbsp;&nbsp; import java.io.*;<br>&nbsp;&nbsp;&nbsp; import java.util.*;<br>&nbsp;<br>&nbsp;&nbsp;&nbsp; public class WhatIsCalendarRead<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static void main(String[] args) throws Exception{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ObjectInputStream in =<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new ObjectInputStream(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new FileInputStream("calendar.out"));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Calendar cal2 = (Calendar)in.readObject();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Calendar cal1 = Calendar.getInstance();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cal1.set(2000, 7, 1, 0, 0, 0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (cal1.equals(cal2))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("Equals");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("NotEqual");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("Old calendar "+cal2.getTime().getTime());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("New calendar "+cal1.getTime().getTime());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cal1.set(Calendar.MILLISECOND, 0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cal2 = (Calendar)in.readObject();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (cal1.equals(cal2))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("Equals");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("NotEqual");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("Processed Old calendar "+cal2.getTime().getTime());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("Processed New calendar "+cal1.getTime().getTime());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;<br><br>然后再另外一个程序中取回来（模拟对数据库的存储），但是执行的结果是：<br><br>NotEqual<br>Old calendar 965113200422 &lt;------------ 最后三位的MilliSecond与当前时间有关<br>New calendar 965113200059 &lt;-----------/<br>Equals<br>Processed Old calendar 965113200000<br>Processed New calendar 965113200000<br>&nbsp;<br>&nbsp;<br><br>另外我们要注意的一点是，Calendar 为了性能原因对 set() 方法采取延缓计算的方法。在 JavaDoc 中有下面的例子来说明这个问题：<br><br>Calendar cal1 = Calendar.getInstance();<br>&nbsp;&nbsp;&nbsp; cal1.set(2000, 7, 31, 0, 0 , 0); //2000-8-31<br>&nbsp;&nbsp;&nbsp; cal1.set(Calendar.MONTH, Calendar.SEPTEMBER); //应该是 2000-9-31，也就是 2000-10-1<br>&nbsp;&nbsp;&nbsp; cal1.set(Calendar.DAY_OF_MONTH, 30); //如果 Calendar 转化到 2000-10-1，那么现在的结果就该是 2000-10-30<br>&nbsp;&nbsp;&nbsp; System.out.println(cal1.getTime()); //输出的是2000-9-30，说明 Calendar 不是马上就刷新其内部的记录<br>&nbsp;<br><br>在 Calendar 的方法中，get() 和 add() 会让 Calendar 立刻刷新。Set() 的这个特性会给我们的开发带来一些意想不到的结果。我们后面会看到这个问题。<br><br>2. Calendar 对象的容错性，Lenient 设置<br><br>我们知道特定的月份有不同的日期，当一个用户给出错误的日期时，Calendar 如何处理的呢？<br><br>&nbsp;&nbsp; import java.io.*;<br>&nbsp;&nbsp;&nbsp; import java.util.*;<br>&nbsp;<br>&nbsp;&nbsp;&nbsp; public class WhatIsCalendar<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static void main(String[] args) throws Exception{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Calendar cal1 = Calendar.getInstance();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cal1.set(2000, 1, 32, 0, 0, 0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(cal1.getTime());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cal1.setLenient(false);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cal1.set(2000, 1, 32, 0, 0, 0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(cal1.getTime());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;<br><br>它的执行结果是：<br><br>&nbsp;&nbsp; Tue Feb 01 00:00:00 PST 2000<br>&nbsp;&nbsp;&nbsp; Exception in thread "main" java.lang.IllegalArgumentException<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at java.util.GregorianCalendar.computeTime(GregorianCalendar.java:1368)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at java.util.Calendar.updateTime(Calendar.java:1508)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at java.util.Calendar.getTimeInMillis(Calendar.java:890)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at java.util.Calendar.getTime(Calendar.java:871)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at WhatIsCalendar.main(WhatIsCalendar.java:12)<br>&nbsp;<br><br>当我们设置该 Calendar 为 Lenient false 时，它会依据特定的月份检查出错误的赋值。<br><br>3. 不稳定的 Calendar<br><br>我们知道 Calendar 是可以被 serialize 的，但是我们要注意下面的问题<br><br>&nbsp;&nbsp; import java.io.*;<br>&nbsp;&nbsp;&nbsp; import java.util.*;<br>&nbsp;<br>&nbsp;&nbsp;&nbsp; public class UnstableCalendar implements Serializable<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static void main(String[] args) throws Exception{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Calendar cal1 = Calendar.getInstance();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cal1.set(2000, 7, 1, 0, 0 , 0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cal1.set(Calendar.MILLISECOND, 0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ObjectOutputStream out =<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new ObjectOutputStream(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new FileOutputStream("newCalendar.out"));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.writeObject(cal1);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.close();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ObjectInputStream in =<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new ObjectInputStream(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new FileInputStream("newCalendar.out"));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Calendar cal2 = (Calendar)in.readObject();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cal2.set(Calendar.MILLISECOND, 0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(cal2.getTime());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;<br><br>&nbsp;<br><br>运行的结果竟然是: Thu Jan 01 00:00:00 PST 1970<br><br>它被复原到 EPOC 的起始点，我们称该 Calendar 是处于不稳定状态。这个问题的根本原因是 Java 在 serialize GregorianCalendar 时没有保存所有的信息，所以当它被恢复到内存中，又缺少足够的信息时，Calendar 会被恢复到 EPOCH 的起始值。Calendar 对象由两部分构成：字段和相对于 EPOC 的微秒时间差。字段信息是由微秒时间差计算出的，而 set() 方法不会强制 Calendar 重新计算字段。这样字段值就不对了。<br><br>下面的代码可以解决这个问题：<br><br>&nbsp;&nbsp; import java.io.*;<br>&nbsp;&nbsp;&nbsp; import java.util.*;<br>&nbsp;<br>&nbsp;&nbsp;&nbsp; public class StableCalendar implements Serializable<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static void main(String[] args) throws Exception{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Calendar cal1 = Calendar.getInstance();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cal1.set(2000, 7, 1, 0, 0 , 0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cal1.set(Calendar.MILLISECOND, 0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ObjectOutputStream out =<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new ObjectOutputStream(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new FileOutputStream("newCalendar.out"));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.writeObject(cal1);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.close();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ObjectInputStream in =<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new ObjectInputStream(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new FileInputStream("newCalendar.out"));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Calendar cal2 = (Calendar)in.readObject();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cal2.get(Calendar.MILLISECOND); //先调用 get()，强制 Calendar 刷新<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cal2.set(Calendar.MILLISECOND, 0);&nbsp; //再设值<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(cal2.getTime());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;<br><br>运行的结果是: Tue Aug 01 00:00:00 PDT 2000,这个问题主要会影响到在 EJB 编程中，参数对象中包含 Calendar 时。经过 Serialize/Deserialize 后，直接操作 Calendar 会产生不稳定的情况。<br><br>4. add() 与 roll() 的区别<br><br>add() 的功能非常强大，add 可以对 Calendar 的字段进行计算。如果需要减去值，那么使用负数值就可以了，如 add(field, -value)。<br><br>add() 有两条规则：<br><br>当被修改的字段超出它可以的范围时，那么比它大的字段会自动修正。如：<br><br>Calendar cal1 = Calendar.getInstance();<br><br>cal1.set(2000, 7, 31, 0, 0 , 0); //2000-8-31<br><br>cal1.add(Calendar.MONTH, 1); //2000-9-31 =&gt; 2000-10-1，对吗？System.out.println(cal1.getTime()); //结果是 2000-9-30<br>&nbsp;<br><br>另一个规则是，如果比它小的字段是不可变的（由 Calendar 的实现类决定），那么该小字段会修正到变化最小的值。<br><br>以上面的例子，9-31 就会变成 9-30，因为变化最小。<br><br>Roll() 的规则只有一条：当被修改的字段超出它可以的范围时，那么比它大的字段不会被修正。如：<br><br>Calendar cal1 = Calendar.getInstance();<br>cal1.set(1999, 5, 6, 0, 0, 0); //1999-6-6, 周日<br>cal1.roll(Calendar.WEEK_OF_MONTH, -1); //1999-6-1, 周二<br>cal1.set(1999, 5, 6, 0, 0, 0); //1999-6-6, 周日<br>cal1.add(Calendar.WEEK_OF_MONTH, -1); //1999-5-30, 周日<br>WEEK_OF_MONTH 比 MONTH 字段小，所以 roll 不能修正 MONTH 字段。<br>&nbsp;<br><br>我们现在已经能够格式化并创建一个日期对象了, 但是我们如何才能设置和获取日期数据的特定部分呢, 比如说小时, 日, 或者分钟? 我们又如何在日期的这些部分加上或者减去值呢? 答案是使用Calendar 类. 就如我们前面提到的那样, Calendar 类中的方法替代了Date 类中被人唾骂的方法. <br><br>假设你想要设置, 获取, 和操纵一个日期对象的各个部分, 比方一个月的一天或者是一个星期的一天. 为了演示这个过程, 我们将使用具体的子类 java.util.GregorianCalendar. 考虑下面的例子, 它计算得到下面的第十个星期五是13号. <br><br>import java.util.GregorianCalendar; <br><br>import java.util.Date; <br><br>import java.text.DateFormat; <br><br>public class DateExample5 { <br><br>public static void main(String[] args) { <br><br>DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.FULL); <br><br>// Create our Gregorian Calendar. <br><br>GregorianCalendar cal = new GregorianCalendar(); <br><br>// Set the date and time of our calendar <br><br>// to the system&amp;s date and time <br><br>cal.setTime(new Date()); <br><br>System.out.println("System Date: " + dateFormat.format(cal.getTime())); // Set the day of week to FRIDAY <br><br>cal.set(GregorianCalendar.DAY_OF_WEEK, GregorianCalendar.FRIDAY); System.out.println("After Setting Day of Week to Friday: " + dateFormat.format(cal.getTime())); <br><br>int friday13Counter = 0; <br><br>while (friday13Counter &lt;= 10) { <br><br>// Go to the next Friday by adding 7 days. cal.add(GregorianCalendar.DAY_OF_MONTH, 7); <br><br>// If the day of month is 13 we have <br><br>// another Friday the 13th. <br><br>if (cal.get(GregorianCalendar.DAY_OF_MONTH) == 13) { <br><br>friday13Counter++; System.out.println(dateFormat.format(cal.getTime())); <br><br>} <br><br>} <br><br>} <br><br>} <br><br>在这个例子中我们作了有趣的函数调用: <br><br>cal.set(GregorianCalendar.DAY_OF_WEEK, GregorianCalendar.FRIDAY); <br><br>和:cal.add(GregorianCalendar.DAY_OF_MONTH, 7); <br><br>set 方法能够让我们通过简单的设置星期中的哪一天这个域来将我们的时间调整为星期五. 注意到这里我们使用了常量 DAY_OF_WEEK 和 FRIDAY来增强代码的可读性. add 方法让我们能够在日期上加上数值. 润年的所有复杂的计算都由这个方法自动处理. <br><br>我们这个例子的输出结果是: <br><br>System Date: Saturday, September 29, 2001 <br><br>当我们将它设置成星期五以后就成了: Friday, September 28, 2001 <br><br>Friday, September 13, 2002 <br><br>Friday, December 13, 2002 <br><br>Friday, June 13, 2003 <br><br>Friday, February 13, 2004 <br><br>Friday, August 13, 2004 <br><br>Friday, May 13, 2005 <br><br>Friday, January 13, 2006 <br><br>Friday, October 13, 2006 <br><br>Friday, April 13, 2007 <br><br>Friday, July 13, 2007 <br><br>Friday, June 13, 2008 <br><br>Calendar类的基础即有变量域的观念。每个类元素都是域，并且这些域在Calendar类中表现为静态变量。这些变量域，可以通过get/set类方法来获得或者设置域值。<br><br>// 获得默认的Calendar实例，给它设置时间<br>Calendarcal = Calendar.getInstance();<br>intyear = cal.get(Calendar.YEAR);<br>cal.set(Calendar.MONTH,Calendar.NOVEMBER); <br>Calendar类的add和roll方法提供在日期之间转换的能力。每个方法都由一个参数变量和一个参数值来修改，通过这个可为正数或负数的参数值来修改它。仅仅不同的是，add方法可以向高阶的变量域溢出。例如，如果从九月三号向后倒退三天，将得到：<br><br>Calendar cal = Calendar.getInstance();<br><br>cal.add(Calendar.DATE,-3);<br><br>// 值为: 星期六八月 31 23:43:19 EDT 2002 <br><br>然而使用roll方法向后回滚三天得出：<br><br>Calendar cal = Calendar.getInstance();<br><br>cal.roll(Calendar.DATE,-3);<br><br>// 值为: 星期一九月 30 23:43:47 EDT 2002 <br>这就是为什么通常主要使用add方法的原因。<br><br>还有一个隐藏在最通用的Calendar的子类中的功能性方法--isLeapYear（判断是否为闰年）方法。<br><br>Calendar cal = Calendar.getInstance();<br><br>booleanleapYear = ( (GregorianCalendar)cal ).isLeapYear(2002);<br><br>// 这个值是false <br><br>尽管它是一个实例方法，isLeapYear方法的行为表现像静态方法，需要提供年份的参数传值给日历。<br><br>其实求几天几月几年前/后的方法，应该用Calendar类比较好的（比Date）。<br><br>Calendar cal = Calendar.getInstance();<br><br>cal.setTime(date);<br><br>cal.add(Calendar.MONTH,1);<br><br>cal.add(Calendar.YEAR,2000);<br><br>date = cal.getTime();<br><br>通过接管日期修改的功能，java.util.Calendar类看上去更像是Data类的复杂版本。但是它还提供额外的功能，更不用说它的国际化支持，使得它值得拥有学习的难度曲线。<br><br>3.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 使用GregorianCalendar类<br>创建一个代表任意日期的一个途径使用GregorianCalendar类的构造函数，它包含在java.util包中：<br><br>GregorianCalendar(int year, int month, int date) <br>注意月份的表示，一月是0，二月是1，以此类推，是12月是11。因为大多数人习惯于使用单词而不是使用数字来表示月份，这样程序也许更易读，父类Calendar使用常量来表示月份：JANUARY, FEBRUARY,等等。所以，创建Wilbur 和 Orville制造第一架动力飞机的日期（December 17, 1903），你可以使用：<br><br>GregorianCalendar firstFlight = new GregorianCalendar(1903, Calendar.DECEMBER, 17); <br><br>出于清楚的考虑，你应该使用前面的形式。但是，你也应该学习怎样阅读下面的短格式。下面的例子同样表示December 17,1903（记住，在短格式中，11表示December）<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GregorianCalendar firstFlight = new GregorianCalendar(1903, 11, 17);&nbsp;&nbsp; 在上一节中，你学习了转换Date对象到字符串。这里，你可以做同样的事情；但是首先，你需要将GregorianCalendar对象转换到Date。要做到这一点，你可以使用getTime()方法，从它得父类Calendar继承而来。GetTime()方法返回GregorianCalendar相应的Date对象。你能够创建GregorianCalendar对象，转换到Date对象，得到和输出相应的字符串这样一个过程。下面是例子： <br><br>import java.util.*;<br><br>import java.text.*;<br><br>public class Flight {<br><br>&nbsp;&nbsp; public static void main(String[] args) {<br><br>GregorianCalendar firstFlight = new GregorianCalendar(1903, Calendar.DECEMBER, 17);&nbsp;&nbsp;&nbsp; <br><br>Date d = firstFlight.getTime();<br><br>DateFormat df = DateFormat.getDateInstance();<br><br>String s = df.format(d);<br><br>System.out.println("First flight was " + s);<br><br>}<br><br>有时候创建一个代表当前时刻的GregorianCalendar类的实例是很有用的。你可以简单的使用没有参数的GregorianCalendar构造函数，象这样：<br><br>GregorianCalendar thisday = new GregorianCalendar();<br>一个输出今天日期的例子程序，使用GregorianCalendar对象：<br><br>import java.util.*;<br>import java.text.*;<br>class Today {<br>&nbsp;&nbsp; public static void main(String[] args) {<br>GregorianCalendar thisday = new GregorianCalendar(); <br>Date d = thisday.getTime();<br>DateFormat df = DateFormat.getDateInstance();<br>String s = df.format(d);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("Today is " + s);<br>&nbsp;&nbsp; }<br>}<br>注意到，Date()构造函数和GregorianCalendar()构造函数很类似：都创建一个对象，条件简单，代表今天。<br>GregorianCalendar类提供处理日期的方法。一个有用的方法是add().使用add()方法，你能够增加象年，月数，天数到日期对象中。要使用add()方法，你必须提供要增加的字段，要增加的数量。一些有用的字段是DATE, MONTH, YEAR, 和 WEEK_OF_YEAR。下面的程序使用add()方法计算未来80天的一个日期。在Jules的&lt;环球80天&gt;是一个重要的数字，使用这个程序可以计算Phileas Fogg从出发的那一天1872年10月2日后80天的日期：<br><br>import java.util.*;<br>import java.text.*;<br>public class World {<br>&nbsp;&nbsp; public static void main(String[] args) {<br>GregorianCalendar worldTour = new GregorianCalendar(1872, Calendar.OCTOBER, 2);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; worldTour.add(GregorianCalendar.DATE, 80);<br>Date d = worldTour.getTime();<br>DateFormat df = DateFormat.getDateInstance();<br>String s = df.format(d);<br>System.out.println("80 day trip will end " + s);<br>&nbsp;&nbsp; }<br>}<br>add()一个重要的副作用是它改变了原来的日期。有时候，拥有原始日期和修改后的日期很重要。不幸的是，你不能简单的创建一个GregorianCalendar对象，设置它和原来的相等（equal）。原因是两个变量指向同一个Date()对象地址。如果Date对象改变，两个变量就指向改变后的日期对象。代替这种做法，应该创建一个新对象。下面的程序示范了这种做法：import java.util.*;<br><br>import java.text.*;<br><br>public class ThreeDates {<br><br>&nbsp;&nbsp; public static void main(String[] args) {<br><br>GregorianCalendar gc1 = new GregorianCalendar(2000, Calendar.JANUARY, 1);<br><br>GregorianCalendar gc2 = gc1;<br><br>GregorianCalendar gc3 = new GregorianCalendar(2000, Calendar.JANUARY, 1);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //Three dates all equal to January 1, 2000<br><br>gc1.add(Calendar.YEAR, 1);<br><br>//gc1 and gc2 are changed&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br><br>DateFormat df = DateFormat.getDateInstance();<br><br>Date d1 = gc1.getTime();<br><br>Date d2 = gc2.getTime();<br><br>Date d3 = gc3.getTime();<br><br>String s1 = df.format(d1);<br><br>String s2 = df.format(d2);<br><br>String s3 = df.format(d3);<br><br>System.out.println("gc1 is " + s1);<br><br>System.out.println("gc2 is " + s2);<br><br>System.out.println("gc3 is " + s3);<br><br>&nbsp;&nbsp; }<br><br>}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 程序运行后，gc1和gc2被变成2001年（因为两个对象指向同一个Date，而Date已经被改变了）。对象gc3指向一个单独的Date，它没有被改变。<br>&nbsp;package com.minght.sys.util;<br><br>/**<br>&nbsp;* &lt;p&gt;Title: 开源,开放&lt;/p&gt;<br>&nbsp;* &lt;p&gt;Description: opeansource&lt;/p&gt;<br>&nbsp;* &lt;p&gt;Copyright: Copyright (c) 2004&lt;/p&gt;<br>&nbsp;* &lt;p&gt;Company: ?海棠&lt;/p&gt;<br>&nbsp;* @author HaiTang Ming<br>&nbsp;* @version 1.0<br>&nbsp;*/<br><br>import java.util.*;<br>import java.math.BigDecimal;<br>import java.math.BigInteger;<br>import java.sql.Timestamp;<br>import java.text.*;<br><br><br>public class timeUtil {<br><br>&nbsp; /**<br>&nbsp;&nbsp; * 将Date类型日期转化成String类型"任意"格式<br>&nbsp;&nbsp; * java.sql.Date,java.sql.Timestamp类型是java.util.Date类型的子类<br>&nbsp;&nbsp; * @param date Date<br>&nbsp;&nbsp; * @param format String<br>&nbsp;&nbsp; *&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "2003-01-01"格式<br>&nbsp;&nbsp; *&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "yyyy年M月d日"<br>&nbsp;&nbsp; *&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "yyyy-MM-dd HH:mm:ss"格式<br>&nbsp;&nbsp; * @return String<br>&nbsp;&nbsp; */<br>&nbsp; public static String dateToString(java.util.Date date,String format) {<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (date==null || format==null) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return null;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SimpleDateFormat sdf = new&nbsp; SimpleDateFormat(format);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String str = sdf.format(date);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return str;<br>&nbsp; }<br><br>&nbsp; /**<br>&nbsp;&nbsp; * 将String类型日期转化成java.utl.Date类型"2003-01-01"格式<br>&nbsp;&nbsp; * @param str String&nbsp; 要格式化的字符串<br>&nbsp;&nbsp; * @param format String<br>&nbsp;&nbsp; * @return Date<br>&nbsp;&nbsp; */<br>&nbsp; public static java.util.Date stringToUtilDate(String str,String format) {<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (str==null||format==null) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return null;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SimpleDateFormat sdf = new&nbsp; SimpleDateFormat(format);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; java.util.Date date = null;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; date = sdf.parse(str);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch(Exception e)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return date;<br>&nbsp; }<br><br><br>&nbsp; /**<br>&nbsp;&nbsp; * 将String类型日期转化成java.sql.Date类型"2003-01-01"格式<br>&nbsp;&nbsp; * @param str String<br>&nbsp;&nbsp; * @param format String<br>&nbsp;&nbsp; * @return Date<br>&nbsp;&nbsp; */<br>&nbsp; public static java.sql.Date stringToSqlDate(String str,String format) {<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (str==null||format==null) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return null;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SimpleDateFormat sdf = new&nbsp; SimpleDateFormat(format);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; java.util.Date date = null;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; date = sdf.parse(str);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch(Exception e)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return null;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return new java.sql.Date(date.getTime());<br>&nbsp; }<br><br>&nbsp; /**<br>&nbsp;&nbsp; * 将String类型日期转化成java.sql.Date类型"2003-01-01"格式<br>&nbsp;&nbsp; * @param str String<br>&nbsp;&nbsp; * @param format String<br>&nbsp;&nbsp; * @return Timestamp<br>&nbsp;&nbsp; */<br>&nbsp; public static java.sql.Timestamp stringToTimestamp(String str,String format) {<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (str==null||format==null) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return null;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SimpleDateFormat sdf = new&nbsp; SimpleDateFormat(format);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; java.util.Date date = null;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; date = sdf.parse(str);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch(Exception e)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return null;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return new java.sql.Timestamp(date.getTime());<br>&nbsp; }<br><br><br>&nbsp; /**<br>&nbsp;&nbsp; * 将java.util.Date日期转化成java.sql.Date类型<br>&nbsp;&nbsp; * @param Date<br>&nbsp;&nbsp; * @return 格式化后的java.sql.Date<br>&nbsp;&nbsp; */<br>&nbsp; public static java.sql.Date toSqlDate(Date date) {<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (date==null) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return null;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp; return new java.sql.Date(date.getTime());<br>&nbsp; }<br>&nbsp; /**<br>&nbsp;&nbsp; * 将字符串转化为时间格式 string to string<br>&nbsp;&nbsp; * @param str String<br>&nbsp;&nbsp; * @param format String<br>&nbsp;&nbsp; * @return String<br>&nbsp;&nbsp; */<br>&nbsp; public static String toDateString(String str,String oldformat,String newformat){<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return dateToString(stringToUtilDate(str,oldformat),newformat);<br><br>&nbsp; }<br><br>&nbsp; /**<br>&nbsp;&nbsp; * 将日历转化为日期<br>&nbsp;&nbsp; * @param calendar Calendar<br>&nbsp;&nbsp; * @return Date<br>&nbsp;&nbsp; */<br>&nbsp; public static java.util.Date converToDate(java.util.Calendar calendar){<br>&nbsp;&nbsp;&nbsp; return Calendar.getInstance().getTime();<br>&nbsp; }<br><br>&nbsp; /**<br>&nbsp;&nbsp; * 将日期转化为日历<br>&nbsp;&nbsp; * @param date Date<br>&nbsp;&nbsp; * @return Calendar<br>&nbsp;&nbsp; */<br>&nbsp; public static java.util.Calendar converToCalendar(java.util.Date date){<br>&nbsp;&nbsp;&nbsp;&nbsp; Calendar calendar = Calendar.getInstance();<br>&nbsp;&nbsp;&nbsp;&nbsp; calendar.setTime(date);<br>&nbsp;&nbsp;&nbsp;&nbsp; return calendar;<br>&nbsp; }<br><br>&nbsp; /**<br>&nbsp;&nbsp; * 求得从某天开始，过了几年几月几日几时几分几秒后，日期是多少<br>&nbsp;&nbsp; * 几年几月几日几时几分几秒可以为负数<br>&nbsp;&nbsp; * @param date Date<br>&nbsp;&nbsp; * @param year int<br>&nbsp;&nbsp; * @param month int<br>&nbsp;&nbsp; * @param day int<br>&nbsp;&nbsp; * @param hour int<br>&nbsp;&nbsp; * @param min int<br>&nbsp;&nbsp; * @param sec int<br>&nbsp;&nbsp; * @return Date<br>&nbsp;&nbsp; */<br>&nbsp; public static java.util.Date modifyDate(java.util.Date date,int year ,int month,int day,int hour,int min,int sec){<br>&nbsp;&nbsp;&nbsp; Calendar cal = Calendar.getInstance();<br>&nbsp;&nbsp;&nbsp; cal.setTime(date);<br>&nbsp;&nbsp;&nbsp; cal.add(Calendar.YEAR,year);<br>&nbsp;&nbsp;&nbsp; cal.add(Calendar.MONTH,month);<br>&nbsp;&nbsp;&nbsp; cal.add(Calendar.DATE,day);<br>&nbsp;&nbsp;&nbsp; cal.add(Calendar.HOUR,hour);<br>&nbsp;&nbsp;&nbsp; cal.add(Calendar.MINUTE,min);<br>&nbsp;&nbsp;&nbsp; cal.add(Calendar.SECOND,sec);<br><br>&nbsp;&nbsp;&nbsp; return cal.getTime();<br><br>&nbsp; }<br><br><br>&nbsp; /**<br>&nbsp;&nbsp; * 取得当前日期时间<br>&nbsp;&nbsp; * 1:year<br>&nbsp;&nbsp; * 2:month<br>&nbsp;&nbsp; * 3:day<br>&nbsp;&nbsp; */<br>&nbsp; public static int getCurTime(int i) {<br>&nbsp;&nbsp;&nbsp; if (i == 1) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return java.util.Calendar.getInstance().get(Calendar.YEAR);<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; else if (i == 2) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return java.util.Calendar.getInstance().get(Calendar.MONTH) + 1;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; else if (i == 3) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return java.util.Calendar.getInstance().get(Calendar.DATE);<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; return 0;<br><br>&nbsp; }<br><br>&nbsp; public static void main(String[] args){<br>&nbsp;&nbsp;&nbsp; System.out.println(dateToString(modifyDate(Calendar.getInstance().getTime(),-1,-1,-1,-1,-1,-1),"yyyy-MM-dd HH:mm:ss"));<br>&nbsp; }<br><br>}<br></font><img src ="http://www.blogjava.net/terry-zj/aggbug/22506.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2005-12-05 10:15 <a href="http://www.blogjava.net/terry-zj/archive/2005/12/05/22506.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>我的最小项目管理工具集（转载）</title><link>http://www.blogjava.net/terry-zj/archive/2005/11/25/21444.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Fri, 25 Nov 2005 09:28:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2005/11/25/21444.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/21444.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2005/11/25/21444.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/21444.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/21444.html</trackback:ping><description><![CDATA[<FONT size=2>工具从来就乱花迷眼，但花哨的工具未必适合自己的团队。<BR>洗净铅华的总结出一些最必要的，能提供最大辅力加持的工具。<BR>参见《死亡中旅》2nd 第x章--最小工具集. <BR></FONT>
<P><FONT size=2><STRONG>1.版本管理工具和文本比较/合并工具<BR></STRONG>&nbsp;&nbsp; 用的是</FONT><STRONG><FONT size=2>CVS: </FONT><A href="http://www.tortoisecvs.org/"><FONT color=#366900 size=2>绿毛小海龟</FONT></A><FONT size=2>加 </FONT><A href="http://winmerge.sourceforge.net/"><FONT color=#366900 size=2>WinMerge</FONT></A><FONT size=2>.&nbsp;&nbsp;<BR></FONT></STRONG><FONT size=2>&nbsp;&nbsp;&nbsp;这年头，还有谁敢不用版本管理工具就跟人合作开发么？ 有的。<BR>&nbsp;&nbsp; 一个好的Programmer，除了要有好的udpate/commit习惯外，会不会善用文本差异比较/合并工具是另一层次的观察标准。<BR>&nbsp;&nbsp; 另外，因为重构时有用，版本管理工具要能和IDE结合。</FONT></P>
<P><FONT size=2>2</FONT><FONT size=2><STRONG>.项目计划，任务分配，需求变更管理，Bug管理工具<BR></STRONG>&nbsp;&nbsp;&nbsp; 偶然的，</FONT><STRONG><FONT size=2>我发现自己把这些都交给了</FONT><A href="http://www.atlassian.com/software/jira/"><FONT color=#366900 size=2>JIRA</FONT></A><FONT size=2>完成。<BR></FONT></STRONG><BR><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;项目计划，任务分配，进度跟踪，需求变更管理，Bug管理几乎就是PM的全部工作了。<BR>&nbsp;&nbsp;&nbsp; 以前总有很多软件分开来管理这些问题，同一问题经常要Copy Paste好几个软件。<BR>&nbsp;&nbsp;&nbsp;&nbsp;但如果你的团队的项目计划是XP plan风格 而不是MS Project<BR>&nbsp;&nbsp;&nbsp;&nbsp;那恭喜了，<EM>一</EM>个JIRA就可以完成所有任务。 </FONT></P>
<P><STRONG><FONT size=2>3.支持重构，Flying Error提示，TDD和Debug 的IDE</FONT></STRONG></P>
<P><FONT size=2>&nbsp;Java: <STRONG><A href="http://www.jetbrains.com/"><FONT color=#366900>IDEA 5.0</FONT></A>能满足下面的全部要求</STRONG>。&nbsp;<BR>&nbsp;C++: <STRONG>VC7.1+</STRONG></FONT><A href="http://www.wholetomato.com/"><STRONG><FONT color=#366900 size=2>VA</FONT></STRONG></A><FONT size=2>，就差好多了。<BR>&nbsp;Ruby: Eclipse的</FONT><A href="http://rubyeclipse.sourceforge.net/"><STRONG><FONT color=#366900 size=2>RDT</FONT></STRONG></A><FONT size=2>插件，就弱得一塌糊涂。<BR>&nbsp;Groovy:IDEA的插件</FONT><A href="http://groovy.codehaus.org/IntelliJ+IDEA+Plugin"><STRONG><FONT color=#366900 size=2>Groovyj<BR></FONT></STRONG></A><FONT size=2>&nbsp;Php:&nbsp;</FONT><A href="http://www.zend.com/"><STRONG><FONT color=#366900 size=2>Zend Stuido</FONT></STRONG></A><BR><BR><FONT size=2>&nbsp;a.重构：即使团队用的最多的只是Rename，Move，Extract Method等有限几个最基本的功能，但J2EE结构里牵一发动全身的事情太多了，重构会帮你把事情擦干净，现在已形成依赖。</FONT></P>
<P><FONT size=2>&nbsp;b.Flying Error提示：<BR>&nbsp;&nbsp;&nbsp; Java IDE的标准配置了，有错马上提示，不要等编译时。可惜其他语言的IDE里这还不是标配。</FONT></P>
<P><FONT size=2>&nbsp; c.Debug J2EE应用：<BR>&nbsp;&nbsp;&nbsp;&nbsp; Web开发者一般用System.out或者log4j来显示调试信息，但对于曾经桌面编程的程序员来说，直接进入调试模式，单步跟踪程序执行路径，想看哪个变量就看哪个变量，才是天经地义的事情，只是之前的IDE不能支持而已。<BR>&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp; d.TDD：TDD不等于Unit Test。TDD是让你不用依赖表现层，不用手工输入数据，清除数据，不用重起Tomcat的开发。<BR>&nbsp;&nbsp;&nbsp; 我们团队暂时还追求不起测试覆盖率，So，UntTest只是一种开发的手段，而不是测试的手段。</FONT></P>
<P><FONT size=2><STRONG>4.团队IM工具和共享文件夹<BR>&nbsp;&nbsp;&nbsp; </STRONG>前代是言必称Email的，现在配合</FONT><A href="http://groups.google.com/"><STRONG><FONT color=#366900 size=2>Google Group</FONT></STRONG></A><FONT size=2>也很好用，但我们更喜欢QQ 群的即时性。<BR>&nbsp;&nbsp;&nbsp; 同时QQ 2005版的"来消息时只显示消息条数"的免打扰功能很重要。<BR>&nbsp;&nbsp;&nbsp; 对于坐在一起的团队，在文件服务器上建个共享文件夹就够了。<BR></FONT></P>
<P><FONT size=2><STRONG>5.知识库Wiki<BR></STRONG>&nbsp;&nbsp; Java里</FONT><A href="http://www.jspwiki.org/"><STRONG><FONT color=#366900 size=2>JspWiki</FONT></STRONG></A><FONT size=2>是最简单易装入门级wiki，但php世界里显然有更好的选择如</FONT><A href="http://www.splitbrain.org/Programming/PHP/DokuWiki/index.php"><STRONG><FONT color=#366900 size=2>Dokuwiki</FONT></STRONG></A><FONT size=2>。<BR>&nbsp;&nbsp; 我一直希望wiki语法有所见所得的编辑器。<BR><BR><BR>其他工具包括纸，笔，足够大的白板，随时可用的会议室。<BR><BR>还缺了什么？<BR>一、代码自动生成工具中也没有最趁手的。<BR>二、因为没有足够的UnitTest用例，配好的持续集成工具没有实际运作。<BR><BR></FONT><A href="/calvin/archive/2005/10/13/15422.html"><FONT size=2>http://www.blogjava.net/calvin/archive/2005/10/13/15422.html</FONT></A><BR></P><img src ="http://www.blogjava.net/terry-zj/aggbug/21444.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2005-11-25 17:28 <a href="http://www.blogjava.net/terry-zj/archive/2005/11/25/21444.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>始终会用上的Common BeanUtils （转载）</title><link>http://www.blogjava.net/terry-zj/archive/2005/11/25/21443.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Fri, 25 Nov 2005 09:22:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2005/11/25/21443.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/21443.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2005/11/25/21443.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/21443.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/21443.html</trackback:ping><description><![CDATA[<DIV class=postText>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Beanutils用了魔术般的反射技术，实现了很多夸张有用的功能，都是C/C++时代不敢想的。无论谁的项目，始终一天都会用得上它。我算是后知后觉了，第一回看到它的时候居然错过。<BR></FONT><FONT size=2><STRONG><BR>1.属性的动态getter、setter <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </STRONG></FONT><FONT size=2>在这框架满天飞的年代，不能事事都保证执行getter,setter函数了，有时候属性是要根据名字动态取得的，就像这样：　　<BR></FONT><FONT size=2>BeanUtils.getProperty(myBean,"code");<BR></FONT><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 而Common BeanUtils的更强功能在于可以直接访问内嵌对象的属性，只要使用点号分隔。<BR></FONT><FONT size=2>BeanUtils.getProperty(orderBean, "address.city");<BR></FONT><FONT size=2>相比之下其他类库的BeanUtils通常都很简单，不能访问内嵌的对象，所以有时要用Commons BeanUtils来替换它们。<BR><BR>BeanUtils还支持List和Map类型的属性，如下面的语法即可取得Order的顾客列表中第一个顾客的名字<BR></FONT><FONT size=2>BeanUtils.getProperty(orderBean, "customers[1].name");<BR></FONT><FONT size=2>其中BeanUtils会使用ConvertUtils类把字符串转为Bean属性的真正类型，方便从HttpServletRequest等对象中提取bean，或者把bean输出到页面。<BR></FONT><FONT size=2>而PropertyUtils就会原色的保留Bean原来的类型。</FONT></P>
<P><FONT size=2><STRONG>2.BeanCompartor 动态排序 <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </STRONG></FONT><FONT size=2>还是通过反射，动态设定Bean按照哪个属性来排序，而不再需要在实现bean的Compare接口进行复杂的条件判断。 <BR></FONT><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; List peoples = ...; // Person对象的列表<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Collections.sort(peoples, new BeanComparator("age"));<BR></FONT><FONT size=2>如果要支持多个属性的复合排序，如"Order By lastName,firstName" </FONT></P><PRE><FONT size=2>ArrayList sortFields = new ArrayList();<BR>sortFields.add(new BeanComparator("lastName"));<BR>sortFields.add(new BeanComparator("firstName"));<BR>ComparatorChain multiSort = new ComparatorChain(sortFields);<BR>Collections.sort(rows,multiSort);<BR></FONT></PRE>
<P><FONT size=2>其中ComparatorChain属于jakata commons-collections包。<BR>如果age属性不是普通类型，构造函数需要再传入一个comparator对象为age变量排序。<BR>另外, BeanCompartor本身的ComparebleComparator, 遇到属性为null就会抛出异常, 也不能设定升序还是降序。这个时候又要借助commons-collections包的ComparatorUtils.</FONT></P><PRE><FONT size=2>&nbsp;&nbsp; Comparator mycmp = ComparableComparator.getInstance();<BR>&nbsp;&nbsp;&nbsp;mycmp = ComparatorUtils.nullLowComparator(mycmp);&nbsp; //允许null<BR>&nbsp;&nbsp; mycmp = ComparatorUtils.reversedComparator(mycmp); //逆序<BR>&nbsp;&nbsp; Comparator cmp = new BeanComparator(sortColumn, mycmp);</FONT></PRE><FONT size=2><STRONG>3.Converter 把Request或ResultSet中的字符串绑定到对象的属性 <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </STRONG></FONT><FONT size=2>经常要从request,resultSet等对象取出值来赋入bean中，如果不用MVC框架的绑定功能的话，下面的代码谁都写腻了。<BR>&nbsp; <BR></FONT><FONT size=2>&nbsp;&nbsp; String a = request.getParameter("a");<BR>&nbsp;&nbsp; bean.setA(a);<BR>&nbsp;&nbsp; String b = ....<BR>&nbsp;&nbsp; bean.setB(b);<BR>&nbsp;&nbsp; ......<BR></FONT><FONT size=2>不妨写一个Binder自动绑定所有属性:</FONT><PRE><FONT size=2>    MyBean bean = ...;<BR>    HashMap map = new HashMap();<BR>    Enumeration names = request.getParameterNames();<BR>    while (names.hasMoreElements())<BR>    {<BR>      String name = (String) names.nextElement();<BR>      map.put(name, request.getParameterValues(name));<BR>    }<BR>    BeanUtils.populate(bean, map);</FONT></PRE>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; 其中BeanUtils的populate方法或者getProperty,setProperty方法其实都会调用convert进行转换。<BR>&nbsp;&nbsp;&nbsp;&nbsp;但Converter只支持一些基本的类型，甚至连java.util.Date类型也不支持。而且它比较笨的一个地方是当遇到不认识的类型时，居然会抛出异常来。&nbsp;对于Date类型，我参考它的sqldate类型实现了一个Converter，而且添加了一个设置日期格式的函数。<BR>要把这个Converter注册，需要如下语句：</FONT></P><PRE><FONT size=2>   ConvertUtilsBean convertUtils = new ConvertUtilsBean();<BR>&nbsp;&nbsp; DateConverter dateConverter = new DateConverter();<BR>&nbsp;&nbsp; convertUtils.register(dateConverter,Date.class);<BR> <BR><BR><BR>   //因为要注册converter,所以不能再使用BeanUtils的静态方法了，必须创建BeanUtilsBean实例<BR>   BeanUtilsBean beanUtils = new BeanUtilsBean(convertUtils,new PropertyUtilsBean());<BR>   beanUtils.setProperty(bean, name, value);</FONT></PRE><FONT size=2><STRONG>4 其他功能</STRONG></FONT> 
<DIV><FONT size=2><STRONG>4.1 ConstructorUtils，动态创建对象<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </STRONG></FONT><FONT size=2>public static Object invokeConstructor(Class klass, Object arg)<BR></FONT><FONT size=2><STRONG>4.2 MethodUtils，动态调用方法</STRONG></FONT>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT size=2>MethodUtils.invokeMethod(bean, methodName, parameter);</FONT></DIV><FONT size=2><STRONG>4.3 PropertyUtils，当属性为Collection,Map时的动态读取：<BR></STRONG>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Collection: 提供index<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </FONT><FONT size=2>BeanUtils.getIndexedProperty(orderBean,"items",1);</FONT> 
<DIV><FONT size=2>或者<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </FONT><FONT size=2>BeanUtils.getIndexedProperty(orderBean,"items[1]");</FONT><FONT size=2>Map: 提供Key Value<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </FONT><FONT size=2>BeanUtils.getMappedProperty(orderBean, "items","111");//key-value goods_no=111 </FONT><FONT size=2>或者<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </FONT><FONT size=2>BeanUtils.getMappedProperty(orderBean, "items(111)") </FONT></DIV>
<DIV><FONT size=2><STRONG>4.4 PropertyUtils，直接获取属性的Class类型<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </STRONG></FONT><FONT size=2>public static Class getPropertyType(Object bean, String name)</FONT></DIV>
<DIV><FONT size=2><STRONG>4.5 动态Bean </STRONG>见<A href="http://anonymouse.org/cgi-bin/anon-www.cgi/http://blog.csdn.net/calvinxiu/archive/2005/02/02/277765.aspx" target=__blank><FONT color=#000080>用DynaBean减除不必要的VO和FormBean&nbsp;</FONT></A><BR></FONT></DIV><FONT size=2><BR></FONT>
<P id=TBPingURL><FONT size=2>Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=277748</FONT></P></DIV><img src ="http://www.blogjava.net/terry-zj/aggbug/21443.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2005-11-25 17:22 <a href="http://www.blogjava.net/terry-zj/archive/2005/11/25/21443.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate 2 升级为Hibernate 3 的注意事项(转载)</title><link>http://www.blogjava.net/terry-zj/archive/2005/11/24/21250.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Thu, 24 Nov 2005 03:22:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2005/11/24/21250.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/21250.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2005/11/24/21250.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/21250.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/21250.html</trackback:ping><description><![CDATA[<DIV class=postbody><FONT size=2>目的，主要是那当前的项目练手，熟悉一下hibernate2和hibernate3的差别，给当前项目一点扩展的空间。<BR><BR>1.首先将hibernate2.jar替换为hibernate3.jar(hibernate-3.0.5)<BR>&nbsp;&nbsp;hibernate-tools.jar也替换成新的(从hibernate-tools-3.0.0.alpha4a找出来的)<BR><BR>2.将所有程序中的net.sf.hibernate替换为org.hibernate.<BR>&nbsp;<BR>3.但是有例外<BR>&nbsp;&nbsp;net.sf.hibernate.expression.Expression换为org.hibernate.criterion.Expression<BR>&nbsp;&nbsp;如果用eclipse,用ctrl+shift+o快捷键可以加快速度<IMG onclick="window.open('http://Anonymouse.org/cgi-bin/anon-www.cgi/http://blog.donews.com/images/smile.gif','_blank');" alt="" hspace=2 src="http://anonymouse.org/cgi-bin/anon-www.cgi/http://www.blogcn.com/images/smile.gif" onload="javascript:if(this.width>screen.width/2)this.width=screen.width/2" vspace=2 border=0><BR>&nbsp;<BR>4.在使用hql查询时将<BR>&nbsp;&nbsp;createSQLQuery(hql,"c",EZCampaignDTO.class);改为createSQLQuery(hql).addEntity("c",EZCampaignDTO.class);<BR>&nbsp;<BR>5.在批量插入时<BR>&nbsp;&nbsp;将原来的int&nbsp;size&nbsp;=&nbsp;((SessionFactoryImpl)(session.getSessionFactory())).getJdbcBatchSize()<BR>&nbsp;&nbsp;改为int&nbsp;size&nbsp;=&nbsp;((SessionFactoryImpl)(session.getSessionFactory())).getSettings().getJdbcBatchSize();<BR>&nbsp;<BR>6.在计算count时<BR>&nbsp;&nbsp;将原来的int&nbsp;size&nbsp;=&nbsp;((Integer)&nbsp;session.iterate(hql).next()).intValue();<BR>&nbsp;&nbsp;改为int&nbsp;size&nbsp;=&nbsp;((Integer)&nbsp;session.createQuery(hql).iterate().next()).intValue();<BR>其中hql="select&nbsp;count(*)&nbsp;from&nbsp;"&nbsp;+&nbsp;DAOVar.contactClass;<BR>&nbsp;<BR>7.还有就是把.hbm中的hibernate-mapping-2.0.dtd替换为hibernate-mapping-3.0.dtd<BR>&nbsp;&nbsp;Hibernate&nbsp;Mapping&nbsp;DTD&nbsp;2.0替换为Hibernate&nbsp;Mapping&nbsp;DTD&nbsp;3.0<BR>&nbsp;<BR>8.hibernate.cfg.xml中<BR>&nbsp;&nbsp;Hibernate&nbsp;Mapping&nbsp;DTD&nbsp;2.0替换为Hibernate&nbsp;Mapping&nbsp;DTD&nbsp;3.0<BR>&nbsp;&nbsp;&lt;property&nbsp;name="hibernate.dialect"&gt;org.hibernate.dialect.SQLServerDialect&lt;/property&gt;<BR>&nbsp;<BR>9.hibernate.properties中类似<BR>&nbsp;<BR>10.cache-config.xml中<BR>&nbsp;&nbsp;&nbsp;&lt;provider&nbsp;className="net.sf.hibernate.cache.OSCacheProvider"/&gt;替换为<BR>&nbsp;&nbsp;&nbsp;&lt;provider&nbsp;className="org.hibernate.cache.OSCacheProvider"/&gt;<BR>&nbsp;<BR>11.classeshibernate.properties中<BR>&nbsp;&nbsp;&nbsp;hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider<BR>&nbsp;&nbsp;&nbsp;hibernate.dialect=org.hibernate.dialect.SQLServerDialect<BR>&nbsp;<BR>12.在自动外部模块部分有一个功能是根据模版自动生成.hbm文件在load,结果出来的.hbm中有问题:<BR>&nbsp;&nbsp;&nbsp;生成的&nbsp;&lt;composite-id&nbsp;unsaved-value="any"&nbsp;mapped="false"&gt;其中mapped="false"&nbsp;出错。找了半天才发现在网上的hibernate-mapping-3.0.dtd文件有支持mapped="false"这个属性。而本地的hebernate3.0.5中的hibernate-mapping-3.0.dtd文件没有这个属性。晕，hibernate也太不负责了吧。解决办法把hibernate-mapping-3.0.dtd&nbsp;copy到jboss\bin目录下然后，在template文件中&lt;!DOCTYPE&nbsp;hibernate-mapping&nbsp;PUBLIC&nbsp;"-//Hibernate/Hibernate&nbsp;Mapping&nbsp;DTD//EN"&nbsp;"hibernate-mapping-3.0.dtd"&gt;，然后他会在jboss\bin目录下读取该文件。<BR>&nbsp;<BR>13.重新测试,还是咣铛，发现子类读父类数据时抛出异常：<BR>&nbsp;&nbsp;&nbsp;"org.hibernate.LazyInitializationException:&nbsp;could&nbsp;not&nbsp;initialize&nbsp;proxy"<BR>&nbsp;&nbsp;&nbsp;延迟抓取出的错，hb3对many-to-one的默认处理是lazy&nbsp;=&nbsp;"proxy"，没有搞懂到底怎么回事，把所有many-to-one,one-to-one都加上lazy="false"，再测试终于大功告成。<BR><BR>文章原作者Blog：</FONT><A href="http://anonymouse.org/cgi-bin/anon-www.cgi/http://blog.csdn.net/chinaewolf/" target=_blank><FONT size=2><IMG alt=::URL:: hspace=2 src="http://anonymouse.org/cgi-bin/anon-www.cgi/http://www.blogcn.com/images/aurl.gif" align=absBottom border=0></FONT></A><A href="http://anonymouse.org/cgi-bin/anon-www.cgi/http://blog.csdn.net/chinaewolf/" target=_blank><FONT color=#000080 size=2>http://blog.csdn.net/chinaewolf/</FONT></A></DIV><img src ="http://www.blogjava.net/terry-zj/aggbug/21250.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2005-11-24 11:22 <a href="http://www.blogjava.net/terry-zj/archive/2005/11/24/21250.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate的未来发展之路（转载）</title><link>http://www.blogjava.net/terry-zj/archive/2005/11/24/21248.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Thu, 24 Nov 2005 03:14:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2005/11/24/21248.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/21248.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2005/11/24/21248.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/21248.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/21248.html</trackback:ping><description><![CDATA[<font size="2"><span class="postbody">Hibernate的未来发展之路 <br><br>最近半年多来，在Java世界，Hibernate是最引人关注的一个话题。从Gavin King加入EJB3.0 EG，负责制订EJB3.0的持久层规范；到Gavin King非正式退出JDO EG，并且充满个人情绪的攻击JDO2.0规范；到《Hibernate in Action》的发行；再到Hibernate3 Alpha的发布；最后再到最近JBoss 3.0 PR的发布(使用Hibernate3实现Entity Bean)。可以说这其中的每一步都引起业界的侧目。 <br><br>Hibernate在不到3年的时间里，从一个不起眼的开源软件发展到今天令业界瞩目的主流O/R Mapping框架，Gavin King从一个开源软件的作者成为业界举足轻重的人物，这多少有些传奇的色彩。毕竟，单纯从技术成就而言，Hibernate不算是最有成就的Java开源框架软件，到目前为止也不是一个完美无缺的软件；从个人技术水平而言，Gavin King也不算绝顶高手。 <br><br>在当前的Java持久层框架中，最流行的O/R Mapping产品分别是Hibernate，JDO和TopLink。 <br><br>自从去年Gavin King加入JBoss之后，Hibernate已经由一个民间的开源软件走上了兼容EJB EntityBean的道路。然而更加令人侧目的是，Gavin King在EJB3.0 EG中充当了一个非常重要的角色，只要对比一下EJB3.0的EntityBean和Hibernate3，真相就会大白，虽然API接口不同，但是EntityBean的设计理念完全来自于Hibernate。 <br><br>虽然EJB3.0的EntityBean在相当程度上来源于Hibernate，但是毕竟是不同的API接口，因此Hibernate和EJB3.0 EntityBean究竟是怎样的一种关系，是很多人心中的疑问。 <br><br>今年四月份JBoss的Ben Wang访华期间，我曾经向Ben请教Hibernate的未来发展，他回答说，Hibernate未来将仍旧以独立的软件产品存在和发展，既可以outside EJB container使用；同时Hibernate也将做为JBoss EntityBean Implementation，又可以inside EJB container使用。然而如何既inside，又outside，终究缺乏一个感性的认识。 <br><br>10月8日JBoss发布的EJB3.0 PR揭开了答案。从Sourceforge的CVS服务器上面checkout出来源代码看一下，我们可以发现，Gavin King对Hibernate3进行了简单的封装，将EJB 3.0 EntityBean API调用转换为内部Hibernate3自己的API，从而实现EJB3.0 EntityBean的兼容。 <br><br>EJB3.0不承诺脱离容器调用，如果你想享用EJB3.0，则必须运行在某个EJB Vendor提供的容器内，例如你使用JBoss提供的容器，那么你调用的是EntityBean API，这些调用请求会被转换为Hibernate API的调用请求。这意味着Hibernate实际上提供了两套API：一套是Hibernate原生API；另一套是兼容EJB3.0 EntityBean API。对于那些需要分布式调用支持，需要EJB容器的开发人员来说，他们选择后一套API；对于不需要EJB容器的开发人员来说，他们选择前一套API。这就是Hibernate既定的发展策略。 <br><br>今年夏天投票通过的JDO2.0标准从某种程度而言，并不逊色于Hibernate当前的版本，有些功能甚至比Hibernate还要好，例如JDO支持对类属性的lazy loading，而Hibernate要到3才支持，当前Hibernate仅仅支持类的lazy loading。实际上在去年，就已经有很多用户不断提出对类属性的lazy loading的需求，然而Gavin King当时一直不认为这个需求有添加的必要性。再例如被Gavin King形容为“可憎的”JDOQL，实际上是类SQL查询语言和对象条件查询的混合体。从功能上来说，不如HQL强大，但是远比Hibernate自己的条件查询强很多。 <br><br>不知道究竟出于什么原因，Gavin King对JDO似乎一直怀有由衷的厌恶，今年5月，他在Hibernate的blog上面对JDO进行了毫不留情的批判，列举了JDO的种种缺点来解释为什么EJB3持久层规范没有把JDO考虑进去。然而事实上他的批判充满了对JDO的误解和偏见，例如Gavin King憎恨JDOQL丝毫没有什么特别的理由，只因为JDOQL不是一个纯粹的查询语言，而是一个混合体，这多少让人对Gavin King的风度感到遗憾。在被SolarMetric的Abe White反驳之后，同样没有风度的说，“我可没有时间做这种无谓的争论，事实上每个人都认为他自己的技术是最好的……我是错了，JDO那伙人也错了，每个人都会犯错误……”。（所以说人无完人阿！） <br><br>JDO2规范的出台事实上构成了对Hibernate，乃至基于Hibernate理念的EJB3.0 EntityBean的严重威胁。JDO1.0规范在功能上的严重缺失导致了JDO无力面对Hibernate和TopLink的竞争，然而功能基本完备的JDO2挟众多JDO Vendor商业支持的合力，同时JDO规范可以避免产品锁定在某个Vendor的优势，已经将竞争的天平拉直。 <br><br>然而JDO2和EJB3两大商业主流标准的分裂，是大部分人，甚至包括厂商所不希望看到的。 于是最终EJB3的Lead Linda DeMichiel和JDO2的Lead Craig Russell联名发表公开信，宣布了一个合并EJB3和JDO2持久层规范的计划，新的持久层规范将以JSR-220(EJB3.0)的持久层规范为基础，融合JDO2的部分特性。新的持久层规范将进入J2EE1.5之中，独立于EJB存在，既可以inside J2EE容器来使用，也可以脱离J2EE容器，独立的运行。 <br><br>这个新的持久层框架可以说完全是一个政治的产物。EJB Vendors出于自身利益反对JDO，使得JDO没有办法成为J2EE的一部分，然而标准的分裂也是大部分人更加不希望看到的，于是最终JDO成了政治斗争的牺牲品。从表面上来看，JDO和EJB3.0 EntityBean都将被新的持久层框架取代，似乎JDO并没有吃亏，但实际上JDO2标准已经成熟，部分JDO领导厂商的产品已经蓄始待发，而EJB3.0 EntityBean还处于Early Draft，等待产品诞生至少也是一年之后的事情了；另外值得耐人寻味的是，新的持久层框架将基于当前EJB3.0 EntityBean，再结合JDO2的规范，并且将处于EJB3.0 EG的控制之下，再加入一些JDO2 EG的成员。因此可以看出来新的持久层框架无疑还是以EJB3.0 EG为主导进行制定的。 <br><br>从长远来看，EJB3和JDO2的政治斗争对双方都有好处，长期分裂带来的后果对双方的发展都不利，然而从短期来看，JDO2确实是在这场政治斗争中败下阵来。最直接的体现就是，已经有一些JDO的用户对JDO的前景产生了动摇和迷茫，不少的JDO爱好者更是直言JDO将死。 <br><br>不过对JDO来说，事情未必如此悲观。因为新的持久层框架的最终发布最快也要在2005年夏天，这还是乐观的估计，比较广泛的使用则是2006年的事情了。并且如果新的持久层框架还是像EJB3 EntityBean那样严重依赖J2SE5.0的annotation的话，无疑将无法在很多当前运行的系统和遗留系统上使用。这些都是JDO2的市场生存空间。有了这段时间的缓冲，JDO Vendor将可以平缓的转变为一个J2EE1.5持久层框架的供应商，面临更加广阔的企业客户群体。 <br><br>TopLink是一个老牌的O/R Mapping软件了，自从被Oracle收购之后，又增加了对Oracle数据库的良好支持，和对Oracle AS EntityBean的支持。Oracle提供了TopLink的图形设计环境，可以使得设计好的TopLink域模型既可以被单独用在TopLink中，也可以被用在EJB CMP中。因此看来TopLink也走了一条和Hibernate同样策略的路。 <br><br>TopLink的问题在于相比Hibernate的开源和免费的优势来说，TopLink既不开源，售价又不菲上。本来商业软件TopLink应该在技术支持和商业宣传策略上拥有足够的优势，然而Oracle公司毕竟是一个以数据库为核心产品的公司，其他的一切产品都是为了数据库销售业绩而服务的。在Oracle产品线中处于一个从属地位的TopLink，由于先天不足，只能眼睁睁看着Hibernate的日益壮大而无所作为，因此TopLink更多的被局限在购买了Oracle数据库，并且绑定Oracle数据库的用户群体中。 <br><br>J2EE1.5的新持久层规范将毫无悬念的成为未来持久层框架的主流API，无论是Hibernate，JDO，还是TopLink终将兼容这个主流商业API。在当前的这三种持久层API当中，Hibernate无疑是最有前途的。这是因为： <br><br>1、新的持久层规范将基于EJB3.0 EntityBean规范，这意味着仍将以Hibernate的设计理念为基础 <br>2、JBoss对EJB3.0规范跟随的步伐非常紧密，在规范制定过程中就不断的发布参考实现产品，因此可以对对EJB3.0规范产生比较大的影响力。 <br>3、根据内部泄漏出来的小道消息，BEA公司的WebLogic9产品线的项目经理已经在用Hibernate2来实现EJB3.0的持久层框架。WebLogic9 beta1预计年底发布，beta2预计明年3月发布，正式产品将紧随EJB3.0规范正式版发布之后的明年秋季发布。 <br><br>综上所述，我们有理由对Hibernate的前途抱有强烈的信心。 <br><br>最后的一个疑问是，既然J2EE1.5的新持久层框架可以脱离J2EE容器运行，那么大家不全部都去用Hibernate的后一套兼容API，而完全放弃Hibernate的原生API了吗？那么是否意味着Hibernate做为一个独立产品的使命彻底终结呢？ <br><br>对于这个问题我的看法是：J2EE1.5的持久层规范要综合各个EJB Vendor，JDO Vendor的意见，要平衡他们之间的利益得失，那么这样一个瞻前顾后的规范必然无法覆盖所有应用场合的全面需要，这不像Hibernate的原生API可以随时根据开发人员的要求增加功能那么灵活。因此我预计Hibernate的原生API以其更加强大的功能仍然会吸引一大批人直接使用原生API，而不是兼容J2EE规范的API。 <br><br>总而言之，对于我们当前的持久层开发来说，最好的办法莫过于坚定的使用DAO层来隔离持久层和业务层逻辑，那么不管未来持久层风云如何变换，但凡基于POJO的持久层框架都可以被我们拿来任意替换。</span><br><br>转载来源：<a href="http://www.hibernate.org.cn/viewtopic.php?t=8146&amp;postdays=0&amp;postorder=asc&amp;start=0"><br>http://www.hibernate.org.cn/viewtopic.php?t=8146&amp;postdays=0&amp;postorder=asc&amp;start=0</a></font><img src ="http://www.blogjava.net/terry-zj/aggbug/21248.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2005-11-24 11:14 <a href="http://www.blogjava.net/terry-zj/archive/2005/11/24/21248.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate的三种查询方式（转载）</title><link>http://www.blogjava.net/terry-zj/archive/2005/11/24/21233.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Thu, 24 Nov 2005 02:27:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2005/11/24/21233.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/21233.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2005/11/24/21233.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/21233.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/21233.html</trackback:ping><description><![CDATA[<SPAN class=postdetails><FONT size=2><SPAN style="COLOR: red">（一）HQL</SPAN> <BR>HQL：Hibernate Qusery Language，如果你已经熟悉它，就会发现它跟SQL非常相像。不过 你不要被表面的假象迷惑，HQL是面向对象的（OO，用生命的眼光看待每一个对象，他们是如此 鲜活）。如果你对JAVA和SQL语句有一定了解的话，那么HQL对你简直易如反掌，你完全可以利用在公车上的时间掌握它。 <BR><BR>以下从几个方面进行慢慢深入： <BR><BR>1。大小些敏感 <BR>大家知道SQL-92 Query是对大小写不敏感的，但是在HQL（前面提到它是OO的）中对对象类的名称和属性确实大小写敏感的（符合java编程语法）。 <BR>HQL 子句本身大小写无关，但是其中出现的类名和属性名必须注意大小写区分 <BR>如：sElect cat.name from Cat as cat和select cat.name from Cat as cat是一样的 <BR>但是： <BR>sElect cat.name from CAT as cat和select cat.name from Cat as cat确实不一样的。 <BR><BR>2。from语句 <BR>最简单的： <BR>from eg.Cat <BR>它只是简单的返回所有eg.Cat的实例,通常我们此时会为eg.Cat其个别名，因为在query的其余部分可能会用到(参看上边关于大小写敏感时的例子情形)，如： <BR>from eg.Cat as cat 这里as可以省略。 <BR><BR>上边只是单表查询，多表的情况如下写法： <BR>from eg.Cat, eg.Dog <BR>from eg.Cat as cat, eg.Dog as dog <BR><BR>3。join相关 <BR>(inner) join <BR>left (outer) join <BR>right (outer) join <BR>full join <BR>HQL同样对SQL中的这些特性支持 <BR>下面插播一个小话题，关于上边的那些特性，我一直都没怎么用，今天既然说到这里，就想把上边的几个特性的用法说一下，也算对自己的一个补充： <BR><BR>假设有两个表：部门、员工，下面列举一些数据： <BR>员工(Employee)： <BR>ID Name DepNo <BR>001 Jplateau 01 <BR>002 Jony 01 <BR>003 Camel 02 <BR>部门(Department)： <BR>ID Name <BR>01 研发部 <BR>02 营销部 <BR><BR>在Hibernate中我们操纵的都是对象，所以我们操纵的是部门类和员工类 <BR><BR><BR><BR><BR><BR>1).(inner) join <BR>select employee.ID as id1,employee.Name as name1, <BR>department.ID as id2,department.Name as name2 from Employee as employee <BR>join Department as department on employee.DepNo=department.ID (注意到条件语句我用on 没有用where) <BR>那么执行结果是什么呢？ <BR>id1 name1 id2 name2 <BR>++++++++++++++++++++++++++++++++++++++ <BR>001 Jplateau 01 研发部 <BR>002 Jony 01 研发部 <BR><BR>2).left (outer) join <BR>select employee.ID as id1,employee.Name as name1,department.ID as id2,department.Name <BR>as name2 from Employee as employee left join Department as department on employee.DepNo= <BR>department.ID <BR>那么执行结果又该是什么呢？ <BR>id1 name1 id2 name2 <BR>++++++++++++++++++++++++++++++++++++++ <BR>001 Jplateau 01 研发部 <BR>002 Jony 01 研发部 <BR>003 Camel null null <BR>{就是说此时我要已第一个表的记录多少为准，第二个表中没有相应纪录的时候填充null} <BR>3). right (outer) join <BR>select employee.ID as id1,employee.Name as name1,department.ID as id2,department.Name <BR>as name2 from Employee as employee right join Department as department on employee.DepNo= <BR>department.ID <BR>那么执行结果又该是什么呢？ <BR>id1 name1 id2 name2 <BR>++++++++++++++++++++++++++++++++++++++ <BR>001 Jplateau 01 研发部 <BR>002 Jony 01 研发部 <BR>null null 02 营销部 <BR>{就是说此时我要已第二个表的记录多少为准，第一个表中没有相应纪录的时候填充null} <BR><BR>4。select语句 <BR>就是要确定你要从查询中返回哪些对象或者哪些对象的属性。写几个例子吧： <BR>select employee form Employee as employee <BR>select employee form Employee as employee where employee.Name like 'J%' <BR>select employee.Name form Employee as employee where employee.Name like 'J%' <BR>select employee.ID as id1,employee.Name as name1,department.ID as id2,department.Name <BR>as name2 from Employee as employee right join Department as department on employee.DepNo= <BR>department.ID <BR><BR>select elements(employee.Name) from Employee as employee <BR>（不明白elements到底是做什么用的？望给于说明） <BR>等等 <BR><BR>5。数学函数 <BR>JDO目前好像还不支持此类特性。 <BR>avg(...), sum(...), min(...), max(...) <BR><BR>count(*) <BR><BR>count(...), count(distinct ...), count(all...) <BR><BR>其用法和SQL基本相同 <BR><BR>select distinct employee.name from Employee as employee <BR>select count(distinct employee.name),count(employee) from Employee as employee <BR><BR>6。polymorphism (暂时不知道如何解释？) <BR>from com.test.Animal as animal <BR>不光得到所有Animal得实例，而且可以得到所有Animal的子类（如果我们定义了一个子类Cat） <BR>一个比较极端的例子 <BR>from java.lang.Object as o <BR>可以得到所有持久类的实例 <BR><BR>7。where语句 <BR>定义查询语句的条件，举几个例子吧： <BR>from Employee as employee where employee.Name='Jplateau' <BR>from Employee as employee where employee.Name like 'J%' <BR>from Employee as employee where employee.Name like '%u' <BR>在where语句中“=”不光可以比较对象的属性，也可以比较对象，如： <BR>select animal from com.test.Animal as animal where animal.name=dog <BR><BR>8。表达式 <BR><BR>在SQL语句中大部分的表达式在HQL中都可以使用： <BR>mathematical operators +, -, *, / <BR><BR>binary comparison operators =, &gt;=, &lt;=, &lt;&gt;, !=, like <BR><BR>logical operations and, or, not <BR><BR>string concatenation || <BR><BR>SQL scalar functions like upper() and lower() <BR><BR>Parentheses ( ) indicate grouping <BR><BR>in, between, is null <BR><BR>JDBC IN parameters ? <BR><BR>named parameters :name, :start_date, <IMG alt=Mad src="http://www.fankai.com/images/smiles/icon_mad.gif" border=0>1 （这种应该是另一种"?"的变通解决方法） <BR><BR>SQL literals 'foo', 69, '1970-01-01 10:00:01.0' <BR><BR>Java public static final constants eg.Color.TABBY <BR><BR>其他不必解释了，在这里我只想对查询中的参数问题说明一下： <BR>大家知道在SQL中进行传递参数进行查询的时候，我们通常用PreparedStatement，在语句中写一大堆的“？”， <BR>在hql中也可以用这种方法，如： <BR>List mates = sess.find( <BR>"select employee.name from Employee as employee " + <BR>"where employee.Name=? ", <BR>name, <BR>Hibernate.STRING <BR>); <BR>(说明：上面利用Session里的find方法，在hibernate的api Session中重载了很多find方法，它可以满足你多种形式的查询) <BR>上边是一个参数的情形，这种情况下紧接着引入参数和定义参数的类型，当为多个参数，调用另一个find方法，它的后两个 <BR>参数都是数组的形式。 <BR><BR>还有另外一种方法来解决上边的问题，JDO也有这样的方法，不过和hibernate的表现形式上有差别，但他们两个骨子里却是 <BR>一样的，如： <BR>Query q = sess.createQuery("select employee.name from Employee as employee where employee.Name=:name"); <BR>q.setString("name", "Jplateau"); <BR>//当有多个参数的时候在此逐一定义 <BR>Iterator employees = q.iterate(); <BR><BR>9。order 语句 <BR>和sql语句没什么差别，如： <BR>select employee.name from Employee as employee where employee.Name like 'J%' order by employee.ID desc (或者asc) <BR><BR>10。group by 语句 <BR>同样和sql语句没什么差别，如： <BR><BR>select employee.name,employee.DepNo from Employee as employee group by employee.DepNo <BR><BR>select foo.id, avg( elements(foo.names) ), max( indices(foo.names) ) from eg.Foo foo group by foo.id <BR>{Note: You may use the elements and indices constructs inside a select clause, even on databases with no subselects.} <BR>谁帮我解释一下上边两句，谢过！ <BR><BR>11。子查询 <BR>hibernate同样支持子查询，写几个例子： <BR><BR>from eg.Cat as fatcat where fatcat.weight &gt; ( select avg(cat.weight) from eg.DomesticCat cat ) <BR><BR><SPAN style="COLOR: red">（二）条件查询</SPAN> <BR>Session osession = ownerSession.getSession(); <BR>Criteria criteria = osession.createCriteria(Owner.class); <BR>criteria.add(Expression.eq("age", new Integer(100))); <BR>criteria.setFirstResult(2); //从返回结果的第二条记录开始的5条记录 <BR>criteria.setMaxResults(5); <BR>List lc=criteria.list(); <BR>System.out.println("条件查询"); <BR>System.out.println(lc.size()); <BR><BR><SPAN style="COLOR: red">（三）原生sql语句查询 </SPAN><BR>Query query=osession.createSQLQuery("select {owner.*} from Owner as owner", "owner", Owner.class); <BR>query.setMaxResults(4); <BR>List l=query.list(); <BR>System.out.println("原生sql语句查询"); <BR>System.out.println(l.get(0)); </FONT><BR></SPAN><img src ="http://www.blogjava.net/terry-zj/aggbug/21233.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2005-11-24 10:27 <a href="http://www.blogjava.net/terry-zj/archive/2005/11/24/21233.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate3主要的新特性（转载）</title><link>http://www.blogjava.net/terry-zj/archive/2005/11/24/21232.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Thu, 24 Nov 2005 02:26:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2005/11/24/21232.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/21232.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2005/11/24/21232.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/21232.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/21232.html</trackback:ping><description><![CDATA[Hibernate3主要的新特性包括：<BR><BR>1:实现了EJB3风格的持久化操作。在原有的saveOrUpdate()和saveOrUpdateCopy()两个方法之外，又提供了EJB3风格的create()和merge()两个操作。<BR><BR>2:提供更强的映射灵活性。允许将一个类映射到多张表，允许混合使用“每个继承体系一张表”和“每个子类一张表”的映射策略，等等。<BR><BR>3:支持存储过程和手写SQL，并且可以用手写SQL替代Hibernate自动生成的SQL语句。<BR><BR>4:基于AST（抽象语法树）的HQL解析。<BR><BR>5:字段级的懒式获取。每个属性都可以在映射描述符中声明“lazy=true”，这样声明的属性会到真正使用时才从数据库加载。不过，实现这项功能需要首先在编译期对字节码进行增强。<BR><BR>具体特性请访问<A href="http://www.hibernate.org/200.html">http://www.hibernate.org/200.html</A><img src ="http://www.blogjava.net/terry-zj/aggbug/21232.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2005-11-24 10:26 <a href="http://www.blogjava.net/terry-zj/archive/2005/11/24/21232.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>