<?xml version="1.0" encoding="GBK" ?>
<rss version="2.0" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dcterms="http://purl.org/dc/terms/">
 <channel>
  	  <title><![CDATA[星 雨]]></title>
	  <link>http://hejianke83.blog.163.com</link>
	  <description><![CDATA[人与天斗其乐无穷，人与地斗其乐无穷，人与人斗其乐无穷！   感激伤害你的人,因为他磨炼了你的心志,
  感激绊倒你的人,因为他强化你的双腿,
  感激欺骗你的人,因为他增进了你的智慧,
  感激蔑视你的人,因为他醒觉了你的自尊,
  感激放弃你的人,因为他教会了你该独立。
  凡事感激——感激一切造就了我的人！]]></description>
	  <language>zh-CN</language>
	  <pubDate>Thu, 4 Sep 2008 14:37:54 +0800</pubDate>
	  <lastBuildDate>Thu, 4 Sep 2008 14:37:54 +0800</lastBuildDate>
	  <docs>http://blogs.law.harvard.edu/tech/rss</docs>
	  <generator><![CDATA[NetEase Space]]></generator>
	  <managingEditor><![CDATA[hejianke83]]></managingEditor>
	  <webMaster><![CDATA[jack'he]]></webMaster>
		  <ttl>120</ttl>
	  <image>
	  	<title><![CDATA[星 雨]]></title>
	  	<url>http://ava.blog.163.com/photo/AHb7vw_hZR6ky4R1HL-q4A==/171699735795081885.jpg</url>
	  	<link>http://hejianke83.blog.163.com</link>
	  </image>
  <item>
  	<title><![CDATA[JAVA实现FTP服务器文件的上传,下载,删除功能]]></title>	
    <link>http://hejianke83.blog.163.com/blog/static/607651620088421243434</link>
    <description><![CDATA[<div><P>import java.io.FileInputStream;<BR>import java.io.FileOutputStream;<BR>import java.io.IOException;</P>
<P>import org.apache.log4j.Logger;</P>
<P>import com.sinosoft.platform.handup.business.submitcapture.service.CaptureServiceImpl;<BR>import com.sinosoft.platform.handup.utils.HandupInitialiser.Handup;</P>
<P>import sun.net.TelnetOutputStream;<BR>import sun.net.TelnetInputStream;<BR>import sun.net.ftp.FtpClient;</P>
<P>/**<BR>&nbsp;* FTP文件服务器上传,下载,删除操作<BR>&nbsp;* @author&nbsp;hejianke83<BR>&nbsp;*<BR>&nbsp;*/<BR>public class FtpClientUtil{</P>
<P>&nbsp;&nbsp;&nbsp; String localfilename;<BR>&nbsp;&nbsp;&nbsp; String remotefilename;<BR>&nbsp;&nbsp;&nbsp; FtpClient ftpClient;</P>
<P>&nbsp;&nbsp;&nbsp; /**<BR>&nbsp;&nbsp;&nbsp;&nbsp; * @param ip 服务器名字<BR>&nbsp;&nbsp;&nbsp;&nbsp; * @param port 端口<BR>&nbsp;&nbsp;&nbsp;&nbsp; * @param user 用户名<BR>&nbsp;&nbsp;&nbsp;&nbsp; * @param password 密码<BR>&nbsp;&nbsp;&nbsp;&nbsp; * @param path 服务器上的路径<BR>&nbsp;&nbsp;&nbsp;&nbsp; */<BR>&nbsp;&nbsp;&nbsp; public void connectServer(String ip, int port, String user,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String password, String path){</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ftpClient = new FtpClient();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ftpClient.openServer(ip, port);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ftpClient.login(user, password);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("login success!");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (path.length() != 0)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ftpClient.cd(path);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ftpClient.binary();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (IOException ex){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("not login");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(ex);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;&nbsp;&nbsp; public void closeConnect() {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ftpClient.closeServer();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("disconnect success");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (IOException ex) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("not disconnect");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(ex);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;&nbsp;&nbsp; public void upload() {</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.localfilename = "D://1.txt";<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.remotefilename = "test2.txt";</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TelnetOutputStream os = ftpClient.put(this.remotefilename);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; java.io.File file_in = new java.io.File(this.localfilename);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FileInputStream is = new FileInputStream(file_in);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; byte[] bytes = new byte[1024];<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int c;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while ((c = is.read(bytes)) != -1) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; os.write(bytes, 0, c);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("upload success");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; is.close();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; os.close();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (IOException ex) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("not upload");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(ex);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;&nbsp;&nbsp; public void download() {</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TelnetInputStream is = ftpClient.get(this.remotefilename);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; java.io.File file_in = new java.io.File(this.localfilename);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FileOutputStream os = new FileOutputStream(file_in);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; byte[] bytes = new byte[1024];<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int c;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while ((c = is.read(bytes)) != -1) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // System.out.println((char)is.read());<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // System.out.println(file_in);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; os.write(bytes, 0, c);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("download success");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; os.close();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; is.close();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (IOException ex) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("not download");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(ex);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;&nbsp;&nbsp; public void download(String remotePath, String remoteFile, String localFile) {</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (remotePath.length() != 0)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ftpClient.cd(remotePath);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TelnetInputStream is = ftpClient.get(remoteFile);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; java.io.File file_in = new java.io.File(localFile);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FileOutputStream os = new FileOutputStream(file_in);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; byte[] bytes = new byte[1024];<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int c;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while ((c = is.read(bytes)) != -1) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // System.out.println((char)is.read());<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // System.out.println(file_in);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; os.write(bytes, 0, c);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("download success");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; os.close();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; is.close();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (IOException ex) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("not download");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(ex);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;&nbsp;&nbsp; public void download(String remoteFile, String localFile) {</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TelnetInputStream is = ftpClient.get(remoteFile);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; java.io.File file_in = new java.io.File(localFile);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FileOutputStream os = new FileOutputStream(file_in);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; byte[] bytes = new byte[1024];<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int c;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while ((c = is.read(bytes)) != -1) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // System.out.println((char)is.read());<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // System.out.println(file_in);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; os.write(bytes, 0, c);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("download success");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; os.close();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; is.close();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (IOException ex) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("not download");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(ex);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; public void delete_file(FtpClientUtil fu,String url) throws Exception {<BR>&nbsp;&nbsp;&nbsp; &nbsp;fu.ftpClient.sendServer("DELE "+url+"\r\n");<BR>&nbsp;&nbsp;&nbsp; &nbsp;int status = fu.ftpClient.readServerResponse();<BR>&nbsp;&nbsp;&nbsp; &nbsp;System.out.print("ftp delete file status:"+status);<BR>&nbsp;&nbsp;&nbsp; &nbsp;if(status == 250){<BR>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;System.out.println("&nbsp; 成功删除FTP服务器中文件");<BR>&nbsp;&nbsp;&nbsp; &nbsp;}<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; public static void main(String agrs[]) {</P>
<P>//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String filepath[] = { "/callcenter/index.jsp"};<BR>//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String localfilepath[] = { "C:\FTP_Test\index.jsp"};<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FtpClientUtil fu = new FtpClientUtil();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String url = Handup.getPropertie(Constants.PropertyKeys.FTP_SERVER_URL); <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String username = Handup.getPropertie(Constants.PropertyKeys.FTP_USERNAME); <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String password = Handup.getPropertie(Constants.PropertyKeys.FTP_PASSWORD); <BR>//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fu.connectServer(url, 21, username,password,"");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fu.connectServer("192.168.1.9", 21, "root","sinosoft","");</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;//System.out.print(fu.ftpClient.welcomeMsg);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;fu.ftpClient.sendServer("DELE 博硕士论文/2008/10611/20208/测试上传_20080904525964/Div+CSS布局入门教程.chm\r\n");&nbsp;&nbsp; //删除服务器上的文件<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;System.out.println(fu.ftpClient.readServerResponse());<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch(Exception e)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;e.printStackTrace();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //fu.upload();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //fu.download();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fu.closeConnect();</P>
<P>&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;public FtpClient getFtpClient() {<BR>&nbsp;&nbsp;return ftpClient;<BR>&nbsp;}</P>
<P>&nbsp;public void setFtpClient(FtpClient ftpClient) {<BR>&nbsp;&nbsp;this.ftpClient = ftpClient;<BR>&nbsp;}<BR>}<BR></P></div>]]></description>
	    <author><![CDATA[jack&apos;he]]></author>
	    <comments>http://hejianke83.blog.163.com/blog/static/607651620088421243434</comments>
    <slash:comments>0</slash:comments>
    <guid isPermaLink="true">http://hejianke83.blog.163.com/blog/static/607651620088421243434</guid>
    <pubDate>Thu, 4 Sep 2008 14:12:43 +0800</pubDate>
    <dcterms:modified>2008-09-04T14:12:43+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[五个启示]]></title>	
    <link>http://hejianke83.blog.163.com/blog/static/60765162008818322529</link>
    <description><![CDATA[<div><P style="TEXT-INDENT: 2em">1、 宽容 </P>
<P style="TEXT-INDENT: 2em">　　一只小猪、一只绵羊和一头乳牛，被关在同一个畜栏里。有一次，牧人捉住小猪，牠大声号叫，猛烈地抗拒。绵羊和乳牛讨厌牠的号叫，便说：「他常常捉我们，我们并不大呼小叫。小猪听了回答道：「捉你们和捉我完全是两回事，他捉你们，只是要你们的毛和乳汁，但是捉住我，却是要我的命呢! </P>
<P style="TEXT-INDENT: 2em">　　立场不同、所处环境不同的人，很难了解对方的感受；因此对别人的失意、挫折、伤痛，不宜幸灾乐祸，而应要有关怀、了解的心情。要有宽容的心！ </P>
<P style="TEXT-INDENT: 2em">2、 靠自己 </P>
<P style="TEXT-INDENT: 2em">　　小蜗牛问妈妈：为什么我们从生下来，就要背负这个又硬又重的壳呢？ </P>
<P style="TEXT-INDENT: 2em">　　妈妈：因为我们的身体没有骨骼的支撑，只能爬，又爬不快。所以要这个壳的保护！ </P>
<P style="TEXT-INDENT: 2em">　　小蜗牛：毛虫姊姊没有骨头，也爬不快，为什么她却不用背这个又硬又重的壳呢？ </P>
<P style="TEXT-INDENT: 2em">　　妈妈：因为毛虫姊姊能变成蝴蝶，天空会保护她啊。 </P>
<P style="TEXT-INDENT: 2em">　　小蜗牛：可是蚯蚓弟弟也没骨头爬不快，也不会变成蝴蝶他什么不背这个又硬又重的壳呢？ </P>
<P style="TEXT-INDENT: 2em">　　妈妈：因为蚯蚓弟弟会钻土, 大地会保护他啊。 </P>
<P style="TEXT-INDENT: 2em">　　小蜗牛哭了起来：我们好可怜，天空不保护，大地也不保护。 </P>
<P style="TEXT-INDENT: 2em">　　蜗牛妈妈安慰他：「所以我们有壳啊！」 </P>
<P style="TEXT-INDENT: 2em">　　我们不靠天，也不靠地，我们靠自己。 </P>
<P style="TEXT-INDENT: 2em">3、 鲨鱼与鱼 </P>
<P style="TEXT-INDENT: 2em">　　曾有人做过实验，将一只最凶猛的鲨鱼和一群热带鱼放在同一个池子，然后用强化玻璃隔开，最初，鲨鱼每天不断冲撞那块看不到的玻璃，耐何这只是徒劳，它始终不能过到对面去，而实验人员每天都有放一些鲫鱼在池子里，所以鲨鱼也没缺少猎物，只是它仍想到对面去，想尝试那美丽的滋味，每天仍是不断的冲撞那块玻璃，它试了每个角落，每次都是用尽全力，但每次也总是弄的伤痕累累，有好几次都浑身破裂出血，持续了好一些日子，每当玻璃一出现裂痕，实验人员马上加上一块更厚的玻璃。 </P>
<P style="TEXT-INDENT: 2em">　　后来，鲨鱼不再冲撞那块玻璃了，对那些斑斓的热带鱼也不再在意，好像他们只是墙上会动的壁画，它开始等着每天固定会出现的鲫鱼，然后用他敏捷的本能进行狩猎，好像回到海中不可一世的凶狠霸气，但这一切只不过是假像罢了，实验到了最后的阶段，实验人员将玻璃取走，但鲨鱼却没有反应，每天仍是在固定的区域游着它不但对那些热带鱼视若无睹，甚至于当那些鲫鱼逃到那边去，他就立刻放弃追逐，说什么也不愿再过去，实验结束了，实验人员讥笑它是海里最懦弱的鱼。 </P>
<P style="TEXT-INDENT: 2em">　　可是失恋过的人都知道为什么，它怕痛。 </P>
<P style="TEXT-INDENT: 2em">4、 神迹 </P>
<P style="TEXT-INDENT: 2em">　　法国一个偏僻的小镇，据传有一个特别灵验的水泉，常会出现神迹，可以医治各种疾病。有一天，一个拄着拐杖，少了一条腿的退伍军人，一跛一跛的走过镇上的马路，旁边的镇民带着同情的回吻说："可怜的家伙，难道他要向上帝祈求再有一条腿吗??"这一句话被退伍的军人听到了，他转过身对他们说："我不是要向上帝祈求有一条新的腿，而是要祈求祂帮助我，叫我没有一条腿后，也知道如何过日子。" </P>
<P style="TEXT-INDENT: 2em">　　试想：学习为所失去的感恩，也接纳失去的事实，不管人生的得与失，总是要让自已的生命充满了亮丽与光彩，不再为过去掉泪，努力的活出自己的生命。 </P>
<P style="TEXT-INDENT: 2em">5、 钓竿 </P>
<P style="TEXT-INDENT: 2em">　　有个老人在河边钓鱼，一个小孩走过去看他钓鱼，老人技巧纯熟，所以没多久就钓上了满篓的鱼，老人见小孩很可爱，要把整篓的鱼送给他，小孩摇摇头，老人惊异的问道：「你为何不要？」小孩回答：「我想要你手中的钓竿。」老人问：「你要钓竿做什么？」小孩说：「这篓鱼没多久就吃完了，要是我有钓竿，我就可以自己钓，一辈子也吃不完。」 </P>
<P style="TEXT-INDENT: 2em">　　我想你一定会说：好聪明的小孩。错了，他如果只要钓竿，那他一条鱼也吃不到。因为，他不懂钓鱼的技巧，光有鱼竿是没用的，因为钓鱼重要的不在"钓竿"，而在"钓技"。 </P>
<P style="TEXT-INDENT: 2em">　　有太多人认为自己拥有了人生道上的钓竿，再也无惧于路上的风雨，如此，难免会跌倒于泥泞地上。就如小孩看老人，以为只要有钓竿就有吃不完的鱼，像职员看老板，以为只要坐在办公室，就有滚进的财源。 </P>
<P style="TEXT-INDENT: 2em"></P></div>]]></description>
	    <author><![CDATA[jack&apos;he]]></author>
	    <comments>http://hejianke83.blog.163.com/blog/static/60765162008818322529</comments>
    <slash:comments>0</slash:comments>
    <guid isPermaLink="true">http://hejianke83.blog.163.com/blog/static/60765162008818322529</guid>
    <pubDate>Mon, 1 Sep 2008 20:03:22 +0800</pubDate>
    <dcterms:modified>2008-09-01T20:03:22+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[根据ORACLE数据自动生成PDF授权书]]></title>	
    <link>http://hejianke83.blog.163.com/blog/static/60765162008712512813</link>
    <description><![CDATA[<div><P>package com.sinosoft.platform.handup.utils;</P>
<P>import java.io.FileNotFoundException;<BR>import java.io.FileOutputStream;<BR>import java.io.IOException;</P>
<P>import com.lowagie.text.Document;<BR>import com.lowagie.text.DocumentException;<BR>import com.lowagie.text.Font;<BR>import com.lowagie.text.PageSize;<BR>import com.lowagie.text.Paragraph;<BR>import com.lowagie.text.Rectangle;<BR>import com.lowagie.text.pdf.BaseFont;<BR>import com.lowagie.text.pdf.PdfPCell;<BR>import com.lowagie.text.pdf.PdfPTable;</P>
<P>import com.lowagie.text.pdf.PdfWriter;<BR>import com.sinosoft.platform.handup.pojo.SubmitCapture;<BR>import com.sinosoft.platform.handup.utils.HandupInitialiser.Handup;<BR>/**<BR>&nbsp;* 自动生成PDF授权书<BR>&nbsp;* @author heguanhua<BR>&nbsp;*<BR>&nbsp;*/<BR>public class CreatePdfUtil {</P>
<P>&nbsp;public static String createPDF(String file_url,String filename,SubmitCapture sc){<BR>&nbsp;&nbsp;<BR>&nbsp;&nbsp;//授权书存放路径<BR>&nbsp;&nbsp;filename = file_url+filename+"_"+Handup.getPropertie(Constants.PropertyKeys.GRANT_FILE_NAME)+".pdf"; <BR>&nbsp;&nbsp;<BR>&nbsp;&nbsp;//创建一个文档对象<BR>&nbsp;&nbsp;Rectangle pageSize = new Rectangle(PageSize.A4);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Document doc=new Document(pageSize);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //定义输出位置并把文档对象装入输出对象中<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PdfWriter.getInstance(doc, new FileOutputStream(filename));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BaseFont bfChinese = null;<BR>&nbsp;&nbsp;try {<BR>&nbsp;&nbsp;&nbsp;//设置授权书支持的中文编码<BR>&nbsp;&nbsp;&nbsp;bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);<BR>&nbsp;&nbsp;} catch (IOException e) {<BR>&nbsp;&nbsp;&nbsp;e.printStackTrace();<BR>&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp; //设置授权书中的中文字体<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Font FontChinese = new Font(bfChinese, 12, Font.NORMAL);</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //打开文档对象<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; doc.open();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 加入文字<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; doc.add(new Paragraph("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; " +<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 授权书",new Font(bfChinese, 12, Font.BOLD)));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; doc.add(new Paragraph(" "));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; doc.add(new Paragraph(" "));&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; doc.addAuthor(sc.getAuthor());<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; doc.addTitle("授权书");<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //创建一个3列16行的表格<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; float[] widths = {0.2f,0.4f,0.4f};<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PdfPTable table = new PdfPTable(3);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //设置table每一列的宽度，widths里写的是百分比，他们加和需要是1<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.setWidths(widths);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //设置表格在页面上的宽度，设成100表示可以表格填满页面，但是要去掉页面margin<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.setWidthPercentage(100);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //设置表格上端的空白距离，类似css中的margin-top:xxpx;这样在给表格加上标题后，标题就不会跟表格重叠在一起了。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.setSpacingBefore(3f);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //设置表格边框未空白<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.getDefaultCell().setBorder(Rectangle.NO_BORDER);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //每截为1行三列<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(new Paragraph(""));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(new Paragraph("中文题目:",FontChinese));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(new Paragraph(sc.getTitlecn(),FontChinese));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(new Paragraph(""));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(new Paragraph("作者姓名:",FontChinese));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(new Paragraph(sc.getAuthor(),FontChinese));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(new Paragraph(""));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(new Paragraph("导师姓名:",FontChinese));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(new Paragraph(sc.getTutor(),FontChinese));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(new Paragraph(""));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(new Paragraph("学位级别:",FontChinese));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(new Paragraph(sc.getDegree(),FontChinese));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(new Paragraph(""));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(new Paragraph("研究生学号:",FontChinese));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(sc.getUser_sno());<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(new Paragraph(""));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(new Paragraph("学位授予单位:",FontChinese));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(new Paragraph(sc.getConfercompany(),FontChinese));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(new Paragraph(""));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(new Paragraph("学位授予时间:",FontChinese));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(sc.getConfertime());<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(new Paragraph(""));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(new Paragraph("学科专业:",FontChinese));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(new Paragraph(sc.getSubject(),FontChinese));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(new Paragraph(""));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(new Paragraph("研究方向:",FontChinese));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(new Paragraph(sc.getReinto(),FontChinese));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(new Paragraph(""));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(new Paragraph("科研成果:",FontChinese));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(new Paragraph(sc.getResults(),FontChinese));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(new Paragraph(""));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(new Paragraph("时间授权:",FontChinese));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(new Paragraph("O 1年&nbsp;&nbsp;&nbsp;&nbsp; O 3年&nbsp;&nbsp;&nbsp;&nbsp; O 5年&nbsp;&nbsp;&nbsp;&nbsp; O 7年&nbsp;&nbsp;&nbsp;&nbsp; O 10年" +<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;"&nbsp;&nbsp; O 不开放&nbsp; O 立即开放",FontChinese));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(new Paragraph(""));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(new Paragraph("空间授权:",FontChinese));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(new Paragraph("O 校内&nbsp;&nbsp;&nbsp; O 互联网",FontChinese));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(new Paragraph("签名：_____________________",FontChinese));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //分列<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(new Paragraph(""));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PdfPCell sign = new PdfPCell();&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sign.setColspan(2);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sign.addElement(new Paragraph("授权书的邮寄方式： 通过邮局邮寄到国家图书馆",FontChinese));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sign.setBorder(Rectangle.NO_BORDER);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(sign);</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(new Paragraph(""));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sign = new PdfPCell();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sign.setColspan(2);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sign.addElement(new Paragraph("授权书的邮寄地址： 北京市海淀区国家图书馆1号",FontChinese));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sign.setBorder(Rectangle.NO_BORDER);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table.addCell(sign);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //doc.add(new Paragraph("我的授权书", FontFactory.getFont(FontFactory.HELVETICA, 12, Font.BOLD, new Color(0, 0, 0))));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //由于设置了table.setSpacingBefore(3f);所以table跟标题不会重合。<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //把表格内容添加到PDF文件中<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; doc.add(table);</P>
<P><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 关闭文档对象，释放资源<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; doc.close();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (FileNotFoundException e) {</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e.printStackTrace();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (DocumentException e) {</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e.printStackTrace();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<BR>&nbsp;&nbsp;return filename;<BR>&nbsp;}<BR>}<BR></P></div>]]></description>
	    <author><![CDATA[jack&apos;he]]></author>
	    <comments>http://hejianke83.blog.163.com/blog/static/60765162008712512813</comments>
    <slash:comments>0</slash:comments>
    <guid isPermaLink="true">http://hejianke83.blog.163.com/blog/static/60765162008712512813</guid>
    <pubDate>Fri, 1 Aug 2008 14:51:02 +0800</pubDate>
    <dcterms:modified>2008-08-01T14:51:02+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[Oracle中CLOB字段JAVA开发]]></title>	
    <link>http://hejianke83.blog.163.com/blog/static/607651620087124643250</link>
    <description><![CDATA[<div><P>public class LobFactory {</P>
<P>&nbsp;private static Connection con;<BR>&nbsp;String clobValue = null; //表的CLOB字段值<BR>&nbsp;<BR>&nbsp;/**<BR>&nbsp; * 创建数据库连接<BR>&nbsp; * @return<BR>&nbsp; * @throws SQLException<BR>&nbsp; * @throws ClassNotFoundException<BR>&nbsp; */<BR>&nbsp;public static Connection getConnection() throws SQLException,ClassNotFoundException {</P>
<P>&nbsp;&nbsp;Class.forName("oracle.jdbc.driver.OracleDriver");</P>
<P>&nbsp;&nbsp;con = DriverManager.getConnection("jdbc:oracle:thin:@192.168.1.88:1521:ORCL","handup","handup");</P>
<P>&nbsp;&nbsp;return con;</P>
<P>&nbsp;}</P>
<P>&nbsp;/**<BR>&nbsp; * 读取CLOB字段值<BR>&nbsp; * @param serialno<BR>&nbsp; * @param table_name<BR>&nbsp; * @param Clob_value<BR>&nbsp; * @return<BR>&nbsp; * @throws SQLException<BR>&nbsp; * @throws IOException<BR>&nbsp; */<BR>&nbsp;public static List read(BigDecimal serialno,String table_name) throws SQLException,IOException {<BR>&nbsp;&nbsp;<BR>&nbsp;&nbsp;String rtn = null;<BR>&nbsp;&nbsp;String c_name = null;<BR>&nbsp;&nbsp;<BR>&nbsp;&nbsp;List rtnlist = new ArrayList();<BR>&nbsp;&nbsp;try {<BR>&nbsp;&nbsp;&nbsp;String sql = "SELECT resource_clob.serialno,resource_clob.c_name"<BR>&nbsp;&nbsp;&nbsp;+",resource_clob.c_value from resource_clob where resource_clob.serialno = "+serialno<BR>&nbsp;&nbsp;&nbsp;+"and resource_clob.table_name = '"+table_name+ "'";<BR>&nbsp;&nbsp;&nbsp;con = getConnection();<BR>&nbsp;&nbsp;&nbsp;PreparedStatement pstmt = con.prepareStatement(sql);<BR>&nbsp;&nbsp;&nbsp;ResultSet rs = pstmt.executeQuery();<BR>&nbsp;&nbsp;&nbsp;java.sql.Clob clob = null;<BR>&nbsp;&nbsp;&nbsp;while(rs.next()) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;HashMap map = new HashMap();<BR>&nbsp;&nbsp;&nbsp;&nbsp;clob = rs.getClob("C_VALUE");&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;rtn=clob.getSubString((long)1,(int)clob.length());&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;c_name = rs.getString("C_NAME");<BR>&nbsp;&nbsp;&nbsp;&nbsp;map.put("Serialno", serialno);<BR>&nbsp;&nbsp;&nbsp;&nbsp;map.put("C_NAME", c_name);<BR>&nbsp;&nbsp;&nbsp;&nbsp;map.put("C_VALUE", rtn);<BR>//&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("serialno :"+serialno+"&nbsp; c_name:"+c_name);<BR>//&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("c_value :"+rtn);<BR>&nbsp;&nbsp;&nbsp;&nbsp;rtnlist.add(map);<BR>&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;rs.close();<BR>&nbsp;&nbsp;&nbsp;pstmt.close();</P>
<P>&nbsp;&nbsp;}catch (SQLException e){<BR>&nbsp;&nbsp;&nbsp;throw e;<BR>&nbsp;&nbsp;}catch (Exception ee) {<BR>&nbsp;&nbsp;&nbsp;ee.printStackTrace();<BR>&nbsp;&nbsp;}<BR>//&nbsp;&nbsp;System.out.println("----------"+rtn);<BR>&nbsp;&nbsp;<BR>&nbsp;&nbsp;con.close();<BR>&nbsp;&nbsp;return rtnlist;<BR>&nbsp;}<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;/**<BR>&nbsp; * 更新对clob字段值的持久化<BR>&nbsp; * @param content<BR>&nbsp; * @param lob_table<BR>&nbsp; * @param serialno<BR>&nbsp; * @param Clob_value<BR>&nbsp; * @param table_name<BR>&nbsp; * @throws SQLException<BR>&nbsp; * @throws IOException<BR>&nbsp; * @throws ClassNotFoundException<BR>&nbsp; */<BR>&nbsp;public static boolean update(String content,String lob_table,BigDecimal serialno,<BR>&nbsp;&nbsp;&nbsp;String Clob_value,String table_name) throws SQLException,IOException, <BR>&nbsp;&nbsp;&nbsp;ClassNotFoundException {</P>
<P>&nbsp;&nbsp;String sql = "update " + lob_table + " set c_value =empty_clob() "<BR>&nbsp;&nbsp;&nbsp;+"where serialno =" + serialno +" and c_name='"+Clob_value+"'";</P>
<P>&nbsp;&nbsp;con = getConnection();<BR>&nbsp;&nbsp;con.setAutoCommit(false);<BR>&nbsp;&nbsp;PreparedStatement pstmt = con.prepareStatement(sql);<BR>&nbsp;&nbsp;pstmt.executeUpdate();<BR>&nbsp;&nbsp;sql = "select c_value from " + lob_table + " where&nbsp; serialno =" + serialno +" and c_name='"+Clob_value+"'";</P>
<P>&nbsp;&nbsp;Statement st = con.createStatement();</P>
<P>&nbsp;&nbsp;ResultSet rs = st.executeQuery(sql);</P>
<P>&nbsp;&nbsp;java.sql.Clob clob ;<BR>&nbsp;&nbsp;boolean isInsert = false;<BR>&nbsp;&nbsp;if (rs.next()) {<BR>&nbsp;&nbsp;&nbsp;isInsert = true;<BR>&nbsp;&nbsp;&nbsp;clob = ((OracleResultSet)rs).getClob("C_VALUE");<BR>&nbsp;&nbsp;&nbsp;oracle.sql.CLOB my_clob = (CLOB)clob;<BR>&nbsp;&nbsp;&nbsp;<BR>&nbsp;//&nbsp;&nbsp;clob = ((org.apache.commons.dbcp.DelegatingResultSet)rs).getClob(fieldName);<BR>&nbsp;//&nbsp;&nbsp;OutputStream writer = my_clob.getAsciiOutputStream();<BR>&nbsp;//&nbsp;&nbsp;byte[] contentStr = content.getBytes();<BR>&nbsp;//&nbsp;&nbsp;writer.write(contentStr);<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;java.io.Writer writer = my_clob.getCharacterOutputStream();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; writer.write(content);<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;writer.flush();<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;writer.close();</P>
<P>&nbsp;&nbsp;}<BR>&nbsp;&nbsp;<BR>&nbsp;&nbsp;con.commit();<BR>&nbsp;&nbsp;rs.close();<BR>&nbsp;&nbsp;st.close();<BR>&nbsp;&nbsp;pstmt.close();<BR>&nbsp;&nbsp;con.setAutoCommit(true);<BR>&nbsp;&nbsp;con.close();<BR>&nbsp;&nbsp;return isInsert;<BR>&nbsp;&nbsp;}</P>
<P>&nbsp;/**<BR>&nbsp; * 实现对clob字段值的持久化<BR>&nbsp; * @param content<BR>&nbsp; * @param lob_table<BR>&nbsp; * @param serialno<BR>&nbsp; * @param Clob_value<BR>&nbsp; * @param table_name<BR>&nbsp; * @throws SQLException<BR>&nbsp; * @throws IOException<BR>&nbsp; * @throws ClassNotFoundException<BR>&nbsp; */<BR>&nbsp;public static void write(String content,String lob_table,BigDecimal serialno,<BR>&nbsp;&nbsp;&nbsp;Integer c_no,String c_name,String table_name,Integer multiply,Integer multiply_id) throws SQLException,IOException, <BR>&nbsp;&nbsp;&nbsp;ClassNotFoundException {<BR>&nbsp;&nbsp;<BR>&nbsp;&nbsp;String sql = "INSERT INTO " + lob_table + "(SERIALNO,TABLE_NAME,C_NO,C_NAME,C_VALUE,MULTIPLY,MULTIPLY_ID)"<BR>&nbsp;&nbsp;&nbsp;+" VALUES(?,?,?,?,?,?,?)";<BR>&nbsp;&nbsp;<BR>&nbsp;&nbsp;con = getConnection();<BR>&nbsp;&nbsp;con.setAutoCommit(false);<BR>&nbsp;&nbsp;PreparedStatement pstmt = con.prepareStatement(sql);<BR>&nbsp;&nbsp;pstmt.setBigDecimal(1, serialno);<BR>&nbsp;&nbsp;pstmt.setString(2, table_name);<BR>&nbsp;&nbsp;pstmt.setInt(3, c_no);<BR>&nbsp;&nbsp;pstmt.setString(4, c_name);<BR>&nbsp;&nbsp;pstmt.setString(5, "empty_clob()");<BR>&nbsp;&nbsp;pstmt.setInt(6, multiply);<BR>&nbsp;&nbsp;pstmt.setInt(7, multiply_id);<BR>&nbsp;&nbsp;pstmt.execute();<BR>&nbsp;&nbsp;sql = "select c_value from " + lob_table + " where&nbsp; serialno =" + serialno +" and c_name='"+c_name+"'";</P>
<P>&nbsp;&nbsp;Statement st = con.createStatement();<BR>&nbsp;&nbsp;ResultSet rs = st.executeQuery(sql);<BR>&nbsp;&nbsp;java.sql.Clob clob ;</P>
<P>&nbsp;&nbsp;if (rs.next()) {</P>
<P>&nbsp;&nbsp;&nbsp;clob = ((OracleResultSet)rs).getClob("C_VALUE");<BR>&nbsp;&nbsp;&nbsp;oracle.sql.CLOB my_clob = (CLOB)clob;<BR>&nbsp;&nbsp;&nbsp;<BR>&nbsp;//&nbsp;&nbsp;clob = ((org.apache.commons.dbcp.DelegatingResultSet)rs).getClob(fieldName);<BR>&nbsp;//&nbsp;&nbsp;OutputStream writer = my_clob.getAsciiOutputStream();<BR>&nbsp;//&nbsp;&nbsp;byte[] contentStr = content.getBytes();<BR>&nbsp;//&nbsp;&nbsp;writer.write(contentStr);<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;java.io.Writer writer = my_clob.getCharacterOutputStream();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; writer.write(content);<BR>&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;writer.flush();<BR>&nbsp;&nbsp;&nbsp;writer.close();<BR>&nbsp;&nbsp;}<BR>&nbsp;&nbsp;con.commit();<BR>&nbsp;&nbsp;rs.close();<BR>&nbsp;&nbsp;st.close();<BR>&nbsp;&nbsp;pstmt.close();<BR>&nbsp;&nbsp;con.setAutoCommit(true);<BR>&nbsp;&nbsp;con.close();<BR>&nbsp;&nbsp;}<BR>}</P>
<P>&nbsp;</P>
<P>代码测试过,已经能够正常使用,欢迎提意见和建议!</P></div>]]></description>
	    <author><![CDATA[jack&apos;he]]></author>
	    <comments>http://hejianke83.blog.163.com/blog/static/607651620087124643250</comments>
    <slash:comments>0</slash:comments>
    <guid isPermaLink="true">http://hejianke83.blog.163.com/blog/static/607651620087124643250</guid>
    <pubDate>Fri, 1 Aug 2008 14:46:43 +0800</pubDate>
    <dcterms:modified>2008-08-01T14:46:43+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[mysql锁机制]]></title>	
    <link>http://hejianke83.blog.163.com/blog/static/6076516200845111139892</link>
    <description><![CDATA[<div><P style="TEXT-INDENT: 2em">锁机制</P>
<P style="TEXT-INDENT: 2em">当前MySQL已经支持 ISAM, MyISAM, MEMORY (HEAP) 类型表的表级锁了，BDB 表支持页级锁，InnoDB 表支持行级锁。</P>
<P style="TEXT-INDENT: 2em">很多时候，可以通过经验来猜测什么样的锁对应用程序更合适，不过通常很难说一个锁比别的更好，这全都要依据应用程序来决定，不同的地方可能需要不同的锁。</P>
<P style="TEXT-INDENT: 2em">想要决定是否需要采用一个支持行级锁的存储引擎，就要看看应用程序都要做什么，其中的查询、更新语句是怎么用的。例如，很多的web应用程序大量的做查询，很少删除，主要是基于索引的更新，只往特定的表中插入记录。采用基本的MySQL MyISAM 表就很合适了。</P>
<P style="TEXT-INDENT: 2em">MySQL中对表级锁的存储引擎来说是释放死锁的。避免死锁可以这样做到：在任何查询之前先请求锁，并且按照请求的顺序锁表。</P>
<P style="TEXT-INDENT: 2em">MySQL中用于 WRITE（写） 的表锁的实现机制如下：</P>
<P style="TEXT-INDENT: 2em">如果表没有加锁，那么就加一个写锁。</P>
<P style="TEXT-INDENT: 2em">否则的话，将请求放到写锁队列中。</P>
<P style="TEXT-INDENT: 2em">MySQL中用于 READ（读） 的表锁的实现机制如下：</P>
<P style="TEXT-INDENT: 2em">如果表没有加写锁，那么就加一个读锁。</P>
<P style="TEXT-INDENT: 2em">否则的话，将请求放到读锁队列中。</P>
<P style="TEXT-INDENT: 2em">当锁释放后，写锁队列中的线程可以用这个锁资源，然后才轮到读锁队列中的线程。</P>
<P style="TEXT-INDENT: 2em">这就是说，如果表里有很多更新操作的话，那么 SELECT 必须等到所有的更新都完成了之后才能开始。</P>
<P style="TEXT-INDENT: 2em">从 MySQL 3.23.33 开始，可以通过状态变量 Table_locks_waited 和 Table_locks_immediate 来分析系统中的锁表争夺情况：</P>
<P style="TEXT-INDENT: 2em">mysql&gt; SHOW STATUS LIKE 'Table%';</P>
<P style="TEXT-INDENT: 2em">+-----------------------+---------+</P>
<P style="TEXT-INDENT: 2em">| Variable_name | Value |</P>
<P style="TEXT-INDENT: 2em">+-----------------------+---------+</P>
<P style="TEXT-INDENT: 2em">| Table_locks_immediate | 1151552 |</P>
<P style="TEXT-INDENT: 2em">| Table_locks_waited | 15324 |</P>
<P style="TEXT-INDENT: 2em">+-----------------------+---------+</P>
<P style="TEXT-INDENT: 2em">在 MySQL 3.23.7（在Windows上是3.23.25）以后，在 MyISAM 表中只要没有冲突的 INSERT 操作，就可以无需使用锁表自由地并行执行 INSERT 和 SELECT 语句。也就是说，可以在其它客户端正在读取 MyISAM 表记录的同时时插入新记录。如果数据文件的中间没有空余的磁盘块的话，就不会发生冲突了，因为这种情况下所有的新记录都会写在数据文件的末尾（当在表的中 间做删除或者更新操作时，就可能导致空洞）。当空洞被新数据填充后，并行插入特性就会自动重新被启用了。</P>
<P style="TEXT-INDENT: 2em">如果想要在一个表上做大量的 INSERT 和 SELECT 操作，但是并行的插入却不可能时，可以将记录插入到临时表中，然后定期将临时表中的数据更新到实际的表里。可以用以下命令实现：</P>
<P style="TEXT-INDENT: 2em">mysql&gt; LOCK TABLES real_table WRITE, insert_table WRITE;</P>
<P style="TEXT-INDENT: 2em">mysql&gt; INSERT INTO real_table SELECT * FROM insert_table;</P>
<P style="TEXT-INDENT: 2em">mysql&gt; TRUNCATE TABLE insert_table;</P>
<P style="TEXT-INDENT: 2em">mysql&gt; UNLOCK TABLES;</P>
<P style="TEXT-INDENT: 2em">InnoDB 使用行级锁，BDB 使用页级锁。对于 InnoDB 和 BDB 存储引擎来说，是可能产生死锁的。这是因为 InnoDB 会自动捕获行锁，BDB 会在执行 SQL 语句时捕获页锁的，而不是在事务的开始就这么做。</P>
<P style="TEXT-INDENT: 2em">行级锁的优点有：</P>
<P style="TEXT-INDENT: 2em">在很多线程请求不同记录时减少冲突锁。</P>
<P style="TEXT-INDENT: 2em">事务回滚时减少改变数据。</P>
<P style="TEXT-INDENT: 2em">使长时间对单独的一行记录加锁成为可能。</P>
<P style="TEXT-INDENT: 2em">行级锁的缺点有：</P>
<P style="TEXT-INDENT: 2em">比页级锁和表级锁消耗更多的内存。</P>
<P style="TEXT-INDENT: 2em">当在大量表中使用时，比页级锁和表级锁更慢，因为他需要请求更多的所资源。</P>
<P style="TEXT-INDENT: 2em">当需要频繁对大部分数据做 GROUP BY 操作或者需要频繁扫描整个表时，就明显的比其它锁更糟糕。</P>
<P style="TEXT-INDENT: 2em">使用更高层的锁的话，就能更方便的支持各种不同的类型应用程序，因为这种锁的开销比行级锁小多了。</P>
<P style="TEXT-INDENT: 2em">表级锁在下列几种情况下比页级锁和行级锁更优越：</P>
<P style="TEXT-INDENT: 2em">很多操作都是读表。</P>
<P style="TEXT-INDENT: 2em">在严格条件的索引上读取和更新，当更新或者删除可以用单独的索引来读取得到时：</P>
<P style="TEXT-INDENT: 2em">UPDATE tbl_name SET column=value WHERE unique_key_col=key_value;</P>
<P style="TEXT-INDENT: 2em">DELETE FROM tbl_name WHERE unique_key_col=key_value;</P>
<P style="TEXT-INDENT: 2em">SELECT 和 INSERT 语句并发的执行，但是只有很少的 UPDATE 和 DELETE 语句。</P>
<P style="TEXT-INDENT: 2em">很多的扫描表和对全表的 GROUP BY 操作，但是没有任何写表。</P>
<P style="TEXT-INDENT: 2em">表级锁和行级锁或页级锁之间的不同之处还在于：</P>
<P style="TEXT-INDENT: 2em">将同时有一个写和多个读的地方做版本（例如在MySQL中的并发插入）。也就是说，数据库/表支持根据开始访问数据时间点的不同支持各种不同的试图。其它名有：时间行程，写复制，或者是按需复制。</P>
<P style="TEXT-INDENT: 2em">原文： Versioning (such as we use in MySQL for concurrent inserts) where you can have one writer at the same time as many readers. This means that the database/table supports different views for the data depending on when you started to access it. Other names for this are time travel, copy on write, or copy on demand.</P>
<P style="TEXT-INDENT: 2em">按需复制在很多情况下比页级锁或行级锁好多了。尽管如此，最坏情况时还是比其它正常锁使用了更多的内存。</P>
<P style="TEXT-INDENT: 2em">可以用应用程序级锁来代替行级锁，例如MySQL中的 GET_LOCK() 和 RELEASE_LOCK()。但它们是劝告锁（原文：These are advisory locks），因此只能用于安全可信的应用程序中。</P>
<P style="TEXT-INDENT: 2em">7.3.2 锁表</P>
<P style="TEXT-INDENT: 2em">为了能有快速的锁，MySQL除了 InnoDB 和 BDB 这两种存储引擎外，所有的都是用表级锁（而非页、行、列级锁）。</P>
<P style="TEXT-INDENT: 2em">对于 InnoDB 和 BDB 表，MySQL只有在指定用 LOCK TABLES 锁表时才使用表级锁。在这两种表中，建议最好不要使用 LOCK TABLES，因为 InnoDB 自动采用行级锁，BDB 用页级锁来保证事务的隔离。</P>
<P style="TEXT-INDENT: 2em">如果数据表很大，那么在大多数应用中表级锁会比行级锁好多了，不过这有一些陷阱。</P>
<P style="TEXT-INDENT: 2em">表级锁让很多线程可以同时从数据表中读取数据，但是如果另一个线程想要写数据的话，就必须要先取得排他访问。正在更新数据时，必须要等到更新完成了，其他线程才能访问这个表。</P>
<P style="TEXT-INDENT: 2em">更新操作通常认为比读取更重要，因此它的优先级更高。不过最好要先确认，数据表是否有很高的 SELECT 操作，而更新操作并非很‘急需’。</P>
<P style="TEXT-INDENT: 2em">表锁锁在一个线程在等待，因为磁盘空间满了，但是却需要有空余的磁盘空间，这个线程才能继续处理时就有问题了。这种情况下，所有要访问这个出问题的表的线程都会被置为等待状态，直到有剩余磁盘空间了。</P>
<P style="TEXT-INDENT: 2em">表锁在以下设想情况中就不利了：</P>
<P style="TEXT-INDENT: 2em">一个客户端提交了一个需要长时间运行的 SELECT 操作。</P>
<P style="TEXT-INDENT: 2em">其他客户端对同一个表提交了 UPDATE 操作，这个客户端就要等到 SELECT 完成了才能开始执行。</P>
<P style="TEXT-INDENT: 2em">其他客户端也对同一个表提交了 SELECT 请求。由于 UPDATE 的优先级高于 SELECT，所以 SELECT 就会先等到 UPDATE 完成了之后才开始执行，它也在等待第一个 SELECT 操作。</P>
<P style="TEXT-INDENT: 2em">下列所述可以减少表锁带来的资源争夺：</P>
<P style="TEXT-INDENT: 2em">让 SELECT 速度尽量快，这可能需要创建一些摘要表。</P>
<P style="TEXT-INDENT: 2em">启动 mysqld 时使用参数 --low-priority-updates。这就会让更新操作的优先级低于 SELECT。这种情况下，在上面的假设中，第二个 SELECT 就会在 INSERT 之前执行了，而且也无需等待第一个SELECT 了。</P>
<P style="TEXT-INDENT: 2em">可以执行 SET LOW_PRIORITY_UPDATES=1 命令，指定所有的更新操作都放到一个指定的链接中去完成。详情请看“14.5.3.1 SET Syntax”。</P>
<P style="TEXT-INDENT: 2em">用 LOW_PRIORITY 属性来降低 INSERT，UPDATE，DELETE 的优先级。</P>
<P style="TEXT-INDENT: 2em">用 HIGH_PRIORITY 来提高 SELECT 语句的优先级。详情请看“14.1.7 SELECT Syntax”。</P>
<P style="TEXT-INDENT: 2em">从MySQL 3.23.7 开始，可以在启动 mysqld 时指定系统变量 max_write_lock_count 为一个比较低的值，它能强制临时地提高表的插入数达到一个特定值后的所有 SELECT 操作的优先级。它允许在 WRITE 锁达到一定数量后有 READ 锁。</P>
<P style="TEXT-INDENT: 2em">当 INSERT 和 SELECT 一起使用出现问题时，可以转而采用 MyISAM 表，它支持并发的SELECT 和 INSERT 操作。</P>
<P style="TEXT-INDENT: 2em">当在同一个表上同时有插入和删除操作时，INSERT DELAYED 可能会很有用。详情请看“14.1.4.2 INSERT DELAYED Syntax”。</P>
<P style="TEXT-INDENT: 2em">当 SELECT 和 DELETE 一起使用出现问题时，DELETE 的 LIMIT 参数可能会很有用。详情请看“14.1.1 DELETE Syntax”</P>
<P style="TEXT-INDENT: 2em">执行 SELECT 时使用 SQL_BUFFER_RESULT 有助于减短锁表的持续时间.详情请看“14.1.7 SELECT Syntax”。</P>
<P style="TEXT-INDENT: 2em">可以修改源代码 `mysys/thr_lock.c'，只用一个所队列。这种情况下，写锁和读锁的优先级就一样了，这对一些应用可能有帮助。</P>
<P style="TEXT-INDENT: 2em">以下是MySQL锁的一些建议：</P>
<P style="TEXT-INDENT: 2em">只要对同一个表没有大量的更新和查询操作混在一起，目前的用户并不是问题。</P>
<P style="TEXT-INDENT: 2em">执行 LOCK TABLES 来提高速度（很多更新操作放在一个锁之中比没有锁的很多更新快多了）。将数据拆分开到多个表中可能也有帮助。</P>
<P style="TEXT-INDENT: 2em">当MySQL碰到由于锁表引起的速度问题时，将表类型转换成 InnoDB 或 BDB 可能有助于提高性能。详情请看“16 The InnoDB Storage Engine”和“15.4 The BDB (BerkeleyDB) Storage Engine”。</P>
<P style="TEXT-INDENT: 2em">修改表结构：</P>
<P style="TEXT-INDENT: 2em">ALTER TABLE history add norenewdays int default 0;</P>
<P style="TEXT-INDENT: 2em">alter TABLE history modify norenewdays int default 0;</P>
<P style="TEXT-INDENT: 2em">alter table infos add ex tinyint not null default '0';</P>
<P style="TEXT-INDENT: 2em"></P></div>]]></description>
	    <author><![CDATA[jack&apos;he]]></author>
	    <comments>http://hejianke83.blog.163.com/blog/static/6076516200845111139892</comments>
    <slash:comments>1</slash:comments>
    <guid isPermaLink="true">http://hejianke83.blog.163.com/blog/static/6076516200845111139892</guid>
    <pubDate>Mon, 5 May 2008 23:11:39 +0800</pubDate>
    <dcterms:modified>2008-05-05T23:11:39+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[ 用dom4j建立,修改,格式化输出XML文档]]></title>	
    <link>http://hejianke83.blog.163.com/blog/static/607651620083237418725</link>
    <description><![CDATA[<div>package xmltest;<BR>import java.io.File;<BR>import java.io.FileWriter;<BR>import java.util.Iterator;<BR>import java.util.List;<BR>&nbsp;<BR>import org.dom4j.Attribute;<BR>import org.dom4j.Document;<BR>import org.dom4j.DocumentHelper;<BR>import org.dom4j.Element;<BR>import org.dom4j.io.OutputFormat;<BR>import org.dom4j.io.SAXReader;<BR>import org.dom4j.io.XMLWriter;<BR>/**<BR>&nbsp;* 创建一个XML文档<BR>&nbsp;* 对这个XML文档的属性和属性值进行修改、删除等操作<BR>&nbsp;* 对XML文档进行统一格式化<BR>&nbsp;* @author Administrator<BR>&nbsp;*<BR>&nbsp;*/<BR>public class Dom4jDemo {<BR>&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp; /**<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 建立一个XML文档,文档名由输入参数决定<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * @param filename 需建立的文件名<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * @return 返回操作结果, 0表失败, 1表成功<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<BR>&nbsp;&nbsp;&nbsp;&nbsp; public int createXMLFile(String filename){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /** 返回操作结果, 0表失败, 1表成功 */<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int returnValue = 0;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /** 建立document对象 */<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Document document = DocumentHelper.createDocument();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /** 建立XML文档的根books */<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Element booksElement = document.addElement("books");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /** 加入一行注释 */<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; booksElement.addComment("This is a test for dom4j, holen, 2008.4.23");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /** 加入第一个book节点 */<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Element bookElement = booksElement.addElement("book");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /** 加入show参数内容 */<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bookElement.addAttribute("show","yes");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /** 加入title节点 */<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Element titleElement = bookElement.addElement("title");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /** 为title设置内容 */<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; titleElement.setText("Dom4j Tutorials");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /** 类似的完成后两个book */<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bookElement = booksElement.addElement("book");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bookElement.addAttribute("show","yes");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; titleElement = bookElement.addElement("title");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; titleElement.setText("Lucene Studing");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bookElement = booksElement.addElement("book");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bookElement.addAttribute("show","no");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; titleElement = bookElement.addElement("title");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; titleElement.setText("Lucene in Action");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /** 加入owner节点 */<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Element ownerElement = booksElement.addElement("owner");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ownerElement.setText("O'Reilly");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /** 将document中的内容写入文件中 */<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; XMLWriter writer = new XMLWriter(new FileWriter(new File(filename)));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; writer.write(document);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; writer.close();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /** 执行成功,需返回1 */<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; returnValue = 1;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }catch(Exception ex){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ex.printStackTrace();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return returnValue;<BR>&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp; /**<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 修改XML文件中内容,并另存为一个新文件<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 重点掌握dom4j中如何添加节点,修改节点,删除节点<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * @param filename 修改对象文件<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * @param newfilename 修改后另存为该文件<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * @return 返回操作结果, 0表失败, 1表成功<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<BR>&nbsp;&nbsp;&nbsp;&nbsp; public int ModiXMLFile(String filename,String newfilename){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int returnValue = 0;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SAXReader saxReader = new SAXReader();&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Document document = saxReader.read(new File(filename));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /** 修改内容之一:如果book节点中show参数的内容为yes,则修改成no */<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /** 先用xpath查找对象 */<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; List list = document.selectNodes("<A>/books/book/@show</A>" );&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Iterator iter = list.iterator();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while(iter.hasNext()){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Attribute attribute = (Attribute)iter.next();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(attribute.getValue().equals("yes")){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; attribute.setValue("no");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /**<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 修改内容之二:把owner项内容改为Tshinghua<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 并在owner节点中加入date节点,date节点的内容为2004-09-11,还为date节点添加一个参数type<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list = document.selectNodes("/books/owner" );<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; iter = list.iterator();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(iter.hasNext()){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Element ownerElement = (Element)iter.next();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ownerElement.setText("Tshinghua");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Element dateElement = ownerElement.addElement("date");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dateElement.setText("2004-09-11");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dateElement.addAttribute("type","Gregorian calendar");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /** 修改内容之三:若title内容为Dom4j Tutorials,则删除该节点 */<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list = document.selectNodes("/books/book");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; iter = list.iterator();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while(iter.hasNext()){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Element bookElement = (Element)iter.next();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Iterator iterator = bookElement.elementIterator("title");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while(iterator.hasNext()){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Element titleElement=(Element)iterator.next();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(titleElement.getText().equals("Dom4j Tutorials")){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bookElement.remove(titleElement);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /** 将document中的内容写入文件中 */<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; XMLWriter writer = new XMLWriter(new FileWriter(new File(newfilename)));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; writer.write(document);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; writer.close();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /** 执行成功,需返回1 */<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; returnValue = 1;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }catch(Exception ex){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ex.printStackTrace();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }catch(Exception ex){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ex.printStackTrace();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return returnValue;<BR>&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp; /**<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 格式化XML文档,并解决中文问题<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * @param filename<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * @return<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<BR>&nbsp;&nbsp;&nbsp;&nbsp; public int formatXMLFile(String filename){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int returnValue = 0;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SAXReader saxReader = new SAXReader();&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Document document = saxReader.read(new File(filename));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; XMLWriter output = null;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /** 格式化输出,类型IE浏览一样 */<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OutputFormat format = OutputFormat.createPrettyPrint();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /** 指定XML字符集编码 */<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; format.setEncoding("GBK");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; output = new XMLWriter(new FileWriter(new File(filename)),format);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; output.write(document);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; output.close();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /** 执行成功,需返回1 */<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; returnValue = 1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }catch(Exception ex){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ex.printStackTrace();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return returnValue;<BR>&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp; public static void main(String[] args) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Dom4jDemo temp = new Dom4jDemo();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(temp.createXMLFile("c://domtest.xml"));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(temp.ModiXMLFile("c://domtest.xml","c://domtest2.xml"));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(temp.formatXMLFile("c://domtest2.xml"));<BR>&nbsp;&nbsp;&nbsp;&nbsp; }<BR>}<BR></div>]]></description>
	    <author><![CDATA[jack&apos;he]]></author>
	    <comments>http://hejianke83.blog.163.com/blog/static/607651620083237418725</comments>
    <slash:comments>3</slash:comments>
    <guid isPermaLink="true">http://hejianke83.blog.163.com/blog/static/607651620083237418725</guid>
    <pubDate>Wed, 23 Apr 2008 19:04:18 +0800</pubDate>
    <dcterms:modified>2008-04-23T19:04:18+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[JS跨域问题解决方法]]></title>	
    <link>http://hejianke83.blog.163.com/blog/static/6076516200831865112690</link>
    <description><![CDATA[<div><P style="TEXT-INDENT: 2em">近日在做web呼叫的时候碰到JS跨域问题，需与华为的服务器交互，用户提交客户号和验证码后，到华为的服务器上去验证用户信息，然后返回用户信息给我们的网页，直接用ajax访问在IE上有安全提示问题，用户信息可返回，调低安全级别可实现，但作为门户网站，让客户去适应我们的要求，这种方法是不可行的，参考了网上一篇“服务器端可控情形JS跨域访问解决方法”，这位老大写了个大概，对我这种低手来说仍然是有点不清不楚的，经过一天痛苦的摸索之后，用动态脚本的方式实现了跨域的解决，现把代码记录下来，以便今后查看。</P>
<P style="TEXT-INDENT: 2em">我启了两个服务，分别是tomcat和weblogic。用tomcat的工程模拟本地，weblogic的工程模拟远程。</P>
<P style="TEXT-INDENT: 2em">先在本地的页面中这样做</P>
<P style="TEXT-INDENT: 2em">java 代码</P>
<P style="TEXT-INDENT: 2em">
</P><OL>
<LI>function&nbsp;transTest(){ &nbsp;&nbsp; 
</LI><LI>&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;username&nbsp;=&nbsp;document.form1.username.value; &nbsp;&nbsp; 
</LI><LI>&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;email&nbsp;=&nbsp;escape(document.form1.email.value); &nbsp;&nbsp; 
</LI><LI>&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;url&nbsp;=&nbsp;"http://10.13.78.95:7001/finprog/registerCheckUserByAjax.do?username="+username+"&amp;email="+email; &nbsp;&nbsp; 
</LI><LI>&nbsp;&nbsp;&nbsp;&nbsp;url&nbsp;=&nbsp;encodeURI(url);&nbsp; &nbsp;&nbsp; 
</LI><LI>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; 
</LI><LI>&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;js_obj&nbsp;=&nbsp;document.createElement(&nbsp;"script"&nbsp;);&nbsp; &nbsp;&nbsp; 
</LI><LI>&nbsp;&nbsp;&nbsp;&nbsp;js_obj.type&nbsp;=&nbsp;"text/javascript";&nbsp; &nbsp;&nbsp; 
</LI><LI>js_obj.setAttribute(&nbsp;"src"&nbsp;,&nbsp;url);&nbsp; &nbsp;&nbsp; 
</LI><LI>document.body.appendChild(js_obj); &nbsp;&nbsp; 
</LI><LI>} &nbsp;&nbsp; 
</LI><LI>&nbsp;&nbsp; 
</LI><LI>function&nbsp;onServerResponse(responseText){ &nbsp;&nbsp; 
</LI><LI>&nbsp;&nbsp;&nbsp;&nbsp;alert(responseText); &nbsp;&nbsp; 
</LI><LI>&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;message&nbsp;=&nbsp;document.getElementById("message"); &nbsp;&nbsp; 
</LI><LI>&nbsp;&nbsp;&nbsp;&nbsp;if(message.hasChildNodes()){ &nbsp;&nbsp; 
</LI><LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;message.removeChild(message.childNodes[0]); &nbsp;&nbsp; 
</LI><LI>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp; 
</LI><LI>&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;messagenode=document.createTextNode(responseText);//?????? &nbsp;&nbsp; 
</LI><LI>&nbsp;&nbsp;&nbsp;&nbsp;message.appendChild(messagenode); &nbsp;&nbsp; 
</LI><LI>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; 
</LI><LI>}&nbsp;&nbsp; </LI></OL>
<P></P>
<P style="TEXT-INDENT: 2em"></P>
<P style="TEXT-INDENT: 2em">上面jsp页面中，执行transTest()方法后，document.createElement( "script" ); 会动态的在页面中生成一段script脚本，然后在脚本中，绕过IE的安全验证，js_obj.setArrribute() 将信息作为 src 的&nbsp;url 参数提交给了远程servlet，(用的.do请求，名字是finprog工程里的一个servlet，我懒，不想新写)。</P>
<P style="TEXT-INDENT: 2em">在registerCheckUserByAjax.do中的最末，我返回给建立通信的jsp页面以信息，代码如下：</P>
<P style="TEXT-INDENT: 2em">java 代码</P>
<P style="TEXT-INDENT: 2em">
</P><OL>
<LI>UserInfoDTO&nbsp;userinfoDTO&nbsp;=&nbsp;(UserInfoDTO)&nbsp;serviceModel.get("userinfoDTO"); &nbsp;&nbsp; 
</LI><LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;responseText; &nbsp;&nbsp; 
</LI><LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(userinfoDTO==null){ &nbsp;&nbsp; 
</LI><LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;responseText="成功"; &nbsp;&nbsp; 
</LI><LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}else&nbsp;if&nbsp;(userinfoDTO.getUserName().equals(username)&nbsp;&amp;&amp;&nbsp;userinfoDTO.getEmail().equals(email))&nbsp;{ &nbsp;&nbsp; 
</LI><LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;responseText="失败"; &nbsp;&nbsp; 
</LI><LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{ &nbsp;&nbsp; 
</LI><LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;responseText="成功"; &nbsp;&nbsp; 
</LI><LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp; 
</LI><LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;responseText&nbsp;=&nbsp;new&nbsp;String(responseText.getBytes(),&nbsp;"ISO-8859-1"); &nbsp;&nbsp; 
</LI><LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;response.getWriter().println("var&nbsp;a='"&nbsp;+&nbsp;responseText&nbsp;+&nbsp;"';");&nbsp; &nbsp;&nbsp; 
</LI><LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;response.getWriter().println("onServerResponse(a);&nbsp;");&nbsp;&nbsp;&nbsp; </LI></OL>
<P></P>
<P style="TEXT-INDENT: 2em">这里去调JSP页面中的onServerResponse()方法，回显信息给本地。 这样本地网页就会响应服务器结果，通过message节点把服务器端信息给回显出来，如果是中文要先编好码。</P>
<P style="TEXT-INDENT: 2em">上面的方法我在IE和FireFox中都测过，大功告成。</P>
<P style="TEXT-INDENT: 2em">另外参考网上的解决方法，还可以用本地代理页面，涉及到配置Apache的问题，看得我头昏，我想到了一些解决方法，用一个本地的servlet，在JS提交的时候，提交到本地servlet，然后本地servlet去请求远程servlet，至于怎么建立通信传值，可以这样，在远程servlet中再请求本地的servlet，这时本地servlet对于远程来说，也变成服务器端了，本地再response回给JSP,这是个笨办法。不过没试过。另外，可以用socket方案，不过对于我们公司的层层防火墙是个考验，还有可以在本地存放一个临时页面，用HttpURLConnection con = (HttpURLConnection)url.openConnection();&nbsp;&nbsp;&nbsp;</P>
<P style="TEXT-INDENT: 2em">与远程建立连接，不过也没试过。暂时没有精力去搞了。
</P><P style="TEXT-INDENT: 2em">引用来自：<A href="http://jeromefeng.javaeye.com/blog/41691">http://jeromefeng.javaeye.com/blog/41691</A></P></div>]]></description>
	    <author><![CDATA[jack&apos;he]]></author>
	    <comments>http://hejianke83.blog.163.com/blog/static/6076516200831865112690</comments>
    <slash:comments>0</slash:comments>
    <guid isPermaLink="true">http://hejianke83.blog.163.com/blog/static/6076516200831865112690</guid>
    <pubDate>Fri, 18 Apr 2008 18:51:12 +0800</pubDate>
    <dcterms:modified>2008-04-19T15:56:13+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[基于Java的全文索引/检索引擎——Lucene]]></title>	
    <link>http://hejianke83.blog.163.com/blog/static/6076516200831443629740</link>
    <description><![CDATA[<div><P><A><B>基于Java的全文索引/检索引擎——Lucene</B></A></P>
<P>Lucene不是一个完整的全文索引应用，而是是一个用Java写的全文索引引擎工具包，它可以方便的嵌入到各种应用中实现针对应用的全文索引/检索功能。</P>
<P>Lucene的作者：Lucene的贡献者<A href="http://www.nutch.org/blog/cutting.html">Doug Cutting</A>是一位资深全文索引/检索专家，曾经是V-Twin搜索引擎(Apple的Copland操作系统的成就之一)的主要开发者，后在Excite担任高级系统架构设计师，目前从事于一些INTERNET底层架构的研究。他贡献出的Lucene的目标是为各种中小型应用程序加入全文检索功能。</P>
<P>Lucene的发展历程：早先发布在作者自己的<A href="http://www.lucene.com/">www.lucene.com</A>，后来发布在<A href="http://sourceforge.net/projects/lucene/">SourceForge</A>，2001年年底成为APACHE基金会jakarta的一个子项目：<A href="http://jakarta.apache.org/lucene/">http://jakarta.apache.org/lucene/</A></P>
<P>已经有很多Java项目都使用了Lucene作为其后台的全文索引引擎，比较著名的有：</P>
<UL>
<LI><A href="http://www.jivesoftware.com/">J</A><A href="http://www.jivesoftware.com/">ive</A>：WEB论坛系统； </LI>
<LI><A href="http://eyebrowse.tigris.org/">Eyebrows</A>：邮件列表HTML归档/浏览/查询系统，本文的主要参考文档“<A href="http://www.javaworld.com/javaworld/jw-09-2000/jw-0915-lucene_p.html">TheLucene search engine: Powerful, flexible, and free</A>”作者就是EyeBrows系统的主要开发者之一，而EyeBrows已经成为目前APACHE项目的主要邮件列表归档系统。 </LI>
<LI><A href="http://xml.apache.org/cocoon/index.html">Cocoon</A>:基于XML的web发布框架，全文检索部分使用了Lucene </LI>
<LI>
<P align=left><A href="http://www.eclipse.org/">Eclipse</A>:基于Java的开放开发平台，帮助部分的全文索引使用了Lucene</P></LI></UL>
<P>对于中文用户来说，最关心的问题是其是否支持中文的全文检索。但通过后面对于Lucene的结构的介绍，你会了解到由于Lucene良好架构设计，对中文的支持只需对其语言词法分析接口进行扩展就能实现对中文检索的支持。</P>
<P><B><A>全文检索的实现机制</A></B></P>
<P>Lucene的API接口设计的比较通用，输入输出结构都很像数据库的表==&gt;记录==&gt;字段，所以很多传统的应用的文件、数据库等都可以比较方便的映射到Lucene的存储结构/接口中。总体上看：可以先把<B>Lucene当成一个支持全文索引的数据库系统</B>。</P>
<P>比较一下Lucene和数据库：</P>
<TABLE width="100%" border=1>
<TBODY>
<TR>
<TD align=middle width="50%">Lucene</TD>
<TD align=middle width="50%">数据库</TD></TR>
<TR>
<TD width="50%"><PRE>索引数据源：doc(field1,field2...) doc(field1,field2...)<BR>                  \  indexer /<BR>                 _____________<BR>                | Lucene Index|<BR>                --------------<BR>                 / searcher \<BR> 结果输出：Hits(doc(field1,field2) doc(field1...))</PRE></TD>
<TD width="50%"><PRE> 索引数据源：record(field1,field2...) record(field1..)<BR>              \  SQL: insert/<BR>               _____________<BR>              | DB  Index   |<BR>               -------------<BR>              / SQL: select \<BR>结果输出：results(record(field1,field2..) record(field1...))</PRE></TD></TR>
<TR>
<TD width="50%">Document：一个需要进行索引的“单元”<BR>一个Document由多个字段组成</TD>
<TD width="50%">Record：记录，包含多个字段</TD></TR>
<TR>
<TD width="50%">Field：字段</TD>
<TD width="50%">Field：字段</TD></TR>
<TR>
<TD width="50%">Hits：查询结果集，由匹配的Document组成</TD>
<TD width="50%">RecordSet：查询结果集，由多个Record组成</TD></TR></TBODY></TABLE>
<P><B>全文检索 ≠ like "%keyword%"</B></P>
<P>通常比较厚的书籍后面常常附关键词索引表（比如：北京：12, 34页，上海：3,77页……），它能够帮助读者比较快地找到相关内容的页码。而数据库索引能够大大提高查询的速度原理也是一样，想像一下通过书后面的索引查找的速度要比一页一页地翻内容高多少倍……而索引之所以效率高，另外一个原因是它是排好序的。<B>对于检索系统来说核心是一个排序问题</B>。</P>
<P align=left>由于数据库索引不是为全文索引设计的，因此，<B>使用like "%keyword%"时，数据库索引是不起作用的</B>，在使用like查询时，搜索过程又变成类似于一页页翻书的遍历过程了，所以对于含有模糊查询的数据库服务来说，LIKE对性能的危害是极大的。如果是需要对多个关键词进行模糊匹配：like"%keyword1%" and like "%keyword2%" ...其效率也就可想而知了。</P>
<P>所以建立一个高效检索系统的关键是建立一个类似于科技索引一样的反向索引机制，将数据源（比如多篇文章）排序顺序存储的同时，有另外一个排好序的关键词列表，用于存储关键词==&gt;文章映射关系，利用这样的映射关系索引：[关键词==&gt;出现关键词的文章编号，出现次数（甚至包括位置：起始偏移量，结束偏移量），出现频率]，检索过程就是把<B>模糊查询变成多个可以利用索引的精确查询的逻辑组合的过程</B>。从而大大提高了多关键词查询的效率，所以，全文检索问题归结到最后是一个排序问题。</P>
<P>由此可以看出模糊查询相对数据库的精确查询是一个非常不确定的问题，这也是大部分数据库对全文检索支持有限的原因。Lucene最核心的特征是通过特殊的索引结构实现了传统数据库不擅长的全文索引机制，并提供了扩展接口，以方便针对不同应用的定制。</P>
<P>可以通过一下表格对比一下数据库的模糊查询：</P>
<TABLE height=283 width="100%" border=1>
<TBODY>
<TR>
<TD align=middle width="9%" height=16>　</TD>
<TD align=middle width="47%" height=16>Lucene全文索引引擎</TD>
<TD align=middle width="40%" height=16>数据库</TD></TR>
<TR>
<TD width="9%" height=48>索引</TD>
<TD width="47%" height=48>将数据源中的数据都通过全文索引一一建立反向索引</TD>
<TD width="40%" height=48>对于LIKE查询来说，数据传统的索引是根本用不上的。数据需要逐个便利记录进行GREP式的模糊匹配，比有索引的搜索速度要有多个数量级的下降。</TD></TR>
<TR>
<TD width="9%" height=49>匹配效果</TD>
<TD width="47%" height=49>通过词元(term)进行匹配，通过语言分析接口的实现，可以实现对中文等非英语的支持。</TD>
<TD width="40%" height=49>使用：like "%net%" 会把netherlands也匹配出来，<BR>多个关键词的模糊匹配：使用like "%com%net%"：就不能匹配词序颠倒的xxx.net..xxx.com</TD></TR>
<TR>
<TD width="9%" height=32>匹配度</TD>
<TD width="47%" height=32>有匹配度算法，将匹配程度（相似度）比较高的结果排在前面。</TD>
<TD width="40%" height=32>没有匹配程度的控制：比如有记录中net出现5词和出现1次的，结果是一样的。</TD></TR>
<TR>
<TD width="9%" height=32>结果输出</TD>
<TD width="47%" height=32>通过特别的算法，将最匹配度最高的头100条结果输出，结果集是缓冲式的小批量读取的。</TD>
<TD width="40%" height=32>返回所有的结果集，在匹配条目非常多的时候（比如上万条）需要大量的内存存放这些临时结果集。</TD></TR>
<TR>
<TD width="9%" height=32>可定制性</TD>
<TD width="47%" height=32>通过不同的语言分析接口实现，可以方便的定制出符合应用需要的索引规则（包括对中文的支持）</TD>
<TD width="40%" height=32>没有接口或接口复杂，无法定制</TD></TR>
<TR>
<TD width="9%" height=32>结论</TD>
<TD width="47%" height=32>高负载的模糊查询应用，需要负责的模糊查询的规则，索引的资料量比较大</TD>
<TD width="40%" height=32>使用率低，模糊匹配规则简单或者需要模糊查询的资料量少</TD></TR></TBODY></TABLE>
<P><SPAN style="FONT-WEIGHT: bold">全文检索和数据库应用最大的不同在于：让</SPAN><SPAN style="FONT-WEIGHT: bold">最相关的</SPAN><SPAN style="FONT-WEIGHT: bold">头100条结果满足98%以上用户的需求<BR></SPAN><BR>Lucene的创新之处：</P>
<P>大部分的搜索（数据库）引擎都是用B树结构来维护索引，索引的更新会导致大量的IO操作，Lucene在实现中，对此稍微有所改进：不是维护一个索引文件，而是在扩展索引的时候不断创建新的索引文件，然后定期的把这些新的小索引文件合并到原先的大索引中（针对不同的更新策略，批次的大小可以调整），这样在不影响检索的效率的前提下，提高了索引的效率。</P>
<P>Lucene和其他一些全文检索系统/应用的比较：</P>
<TABLE width="100%" border=1>
<TBODY>
<TR>
<TD align=middle width="18%">　</TD>
<TD align=middle width="45%">Lucene</TD>
<TD align=middle width="37%">其他开源全文检索系统</TD></TR>
<TR>
<TD width="18%">增量索引和批量索引</TD>
<TD width="45%">可以进行增量的索引(Append)，可以对于大量数据进行批量索引，并且接口设计用于优化批量索引和小批量的增量索引。</TD>
<TD width="37%">很多系统只支持批量的索引，有时数据源有一点增加也需要重建索引。</TD></TR>
<TR>
<TD width="18%">数据源</TD>
<TD width="45%">Lucene没有定义具体的数据源，而是一个文档的结构，因此可以非常灵活的适应各种应用（只要前端有合适的转换器把数据源转换成相应结构），</TD>
<TD width="37%">很多系统只针对网页，缺乏其他格式文档的灵活性。</TD></TR>
<TR>
<TD width="18%">索引内容抓取</TD>
<TD width="45%">Lucene的文档是由多个字段组成的，甚至可以控制那些字段需要进行索引，那些字段不需要索引，近一步索引的字段也分为需要分词和不需要分词的类型：<BR>&nbsp;&nbsp; 需要进行分词的索引，比如：标题，文章内容字段<BR>&nbsp;&nbsp; 不需要进行分词的索引，比如：作者/日期字段</TD>
<TD width="37%">缺乏通用性，往往将文档整个索引了</TD></TR>
<TR>
<TD width="18%">语言分析</TD>
<TD width="45%">通过语言分析器的不同扩展实现：<BR>可以过滤掉不需要的词：an the of 等，<BR>西文语法分析：将jumps jumped jumper都归结成jump进行索引/检索<BR>非英文支持：对亚洲语言，阿拉伯语言的索引支持</TD>
<TD width="37%">缺乏通用接口实现</TD></TR>
<TR>
<TD width="18%">查询分析</TD>
<TD width="45%">通过查询分析接口的实现，可以定制自己的查询语法规则：<BR>比如： 多个关键词之间的 + - and or关系等</TD>
<TD width="37%">　</TD></TR>
<TR>
<TD width="18%">并发访问</TD>
<TD width="45%">能够支持多用户的使用</TD>
<TD width="37%">　</TD></TR></TBODY></TABLE>
<P>　</P>
<P><B><A>关于亚洲语言的的切分词问题(Word Segment)</A></B></P>
<P>对于中文来说，全文索引首先还要解决一个语言分析的问题，对于英文来说，语句中单词之间是天然通过空格分开的，但亚洲语言的中日韩文语句中的字是一个字挨一个，所有，首先要把语句中按“词”进行索引的话，这个词如何切分出来就是一个很大的问题。</P>
<P>首先，肯定不能用单个字符作(si-gram)为索引单元，否则查“上海”时，不能让含有“海上”也匹配。</P>
<P>但一句话：“北京天安门”，计算机如何按照中文的语言习惯进行切分呢？<BR>“北京 天安门” 还是“北 京 天安门”？让计算机能够按照语言习惯进行切分，往往需要机器有一个比较丰富的词库才能够比较准确的识别出语句中的单词。</P>
<P>另外一个解决的办法是采用自动切分算法：将单词按照2元语法(bigram)方式切分出来，比如：<BR>"北京天安门" ==&gt; "北京 京天 天安 安门"。</P>
<P>这样，在查询的时候，无论是查询"北京" 还是查询"天安门"，将查询词组按同样的规则进行切分："北京"，"天安安门"，多个关键词之间按与"and"的关系组合，同样能够正确地映射到相应的索引中。这种方式对于其他亚洲语言：韩文，日文都是通用的。</P>
<P>基于自动切分的最大优点是没有词表维护成本，实现简单，缺点是索引效率低，但对于中小型应用来说，基于2元语法的切分还是够用的。基于2元切分后的索引一般大小和源文件差不多，而对于英文，索引文件一般只有原文件的30%-40%不同，</P>
<TABLE height=68 width="100%" border=1>
<TBODY>
<TR>
<TD align=middle width="11%" height=18><BR></TD>
<TD align=middle width="39%" height=18>自动切分</TD>
<TD align=middle width="50%" height=18>词表切分</TD></TR>
<TR>
<TD width="11%" height=16>实现</TD>
<TD width="39%" height=16>实现非常简单</TD>
<TD width="50%" height=16>实现复杂</TD></TR>
<TR>
<TD width="11%" height=16>查询</TD>
<TD width="39%" height=16>增加了查询分析的复杂程度，</TD>
<TD width="50%" height=16>适于实现比较复杂的查询语法规则</TD></TR>
<TR>
<TD width="11%" height=16>存储效率</TD>
<TD width="39%" height=16>索引冗余大，索引几乎和原文一样大</TD>
<TD width="50%" height=16>索引效率高，为原文大小的30％左右</TD></TR>
<TR>
<TD width="11%" height=16>维护成本</TD>
<TD width="39%" height=16>无词表维护成本</TD>
<TD width="50%" height=16>词表维护成本非常高：中日韩等语言需要分别维护。<BR>还需要包括词频统计等内容</TD></TR>
<TR>
<TD width="11%" height=16>适用领域</TD>
<TD width="39%" height=16>嵌入式系统：运行环境资源有限<BR>分布式系统：无词表同步问题<BR>多语言环境：无词表维护成本</TD>
<TD width="50%" height=16>对查询和存储效率要求高的专业搜索引擎<BR></TD></TR></TBODY></TABLE>
<P>目前比较大的搜索引擎的语言分析算法一般是基于以上2个机制的结合。关于中文的语言分析算法，大家可以在Google查关键词"wordsegment search"能找到更多相关的资料。</P>
<P><A><B>安装和使用</B></A></P>
<P>下载：<A href="http://jakarta.apache.org/lucene/">http://jakarta.apache.org/lucene/</A></P>
<P>注意：Lucene中的一些比较复杂的词法分析是用JavaCC生成的（JavaCC：JavaCompilerCompiler，纯Java的词法分析生成器），所以如果从源代码编译或需要修改其中的QueryParser、定制自己的词法分析器，还需要从<A href="https://javacc.dev.java.net/">https://javacc.dev.java.net/</A>下载javacc。</P>
<P>lucene的组成结构：对于外部应用来说索引模块(index)和检索模块(search)是主要的外部应用入口</P>
<TABLE width="100%" border=1>
<TBODY>
<TR>
<TD width="27%">org.apache.Lucene.search/</TD>
<TD width="73%">搜索入口</TD></TR>
<TR>
<TD width="27%">org.apache.Lucene.index/</TD>
<TD width="73%">索引入口</TD></TR>
<TR>
<TD width="27%">org.apache.Lucene.analysis/</TD>
<TD width="73%">语言分析器</TD></TR>
<TR>
<TD width="27%">org.apache.Lucene.queryParser/</TD>
<TD width="73%">查询分析器</TD></TR>
<TR>
<TD width="27%">org.apache.Lucene.document/</TD>
<TD width="73%">存储结构</TD></TR>
<TR>
<TD width="27%">org.apache.Lucene.store/&nbsp;</TD>
<TD width="73%">底层IO/存储结构</TD></TR>
<TR>
<TD width="27%">org.apache.Lucene.util/</TD>
<TD width="73%">一些公用的数据结构</TD></TR></TBODY></TABLE>
<P>简单的例子演示一下Lucene的使用方法：</P>索引过程：从命令行读取文件名（多个），将文件分路径(path字段)和内容(body字段)2个字段进行存储，并对内容进行全文索引：索引的单位是Document对象，每个Document对象包含多个字段Field对象，针对不同的字段属性和数据输出的需求，对字段还可以选择不同的索引/存储字段规则，列表如下： 
<TABLE border=1>
<TBODY>
<TR>
<TH>方法</TH>
<TH>切词</TH>
<TH>索引</TH>
<TH>存储</TH>
<TH>用途</TH></TR>
<TR>
<TD>Field.Text(String name, String value)</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD vAlign=top>切分词索引并存储，比如：标题，内容字段</TD></TR>
<TR>
<TD>Field.Text(String name, Reader value)</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD vAlign=top>切分词索引不存储，比如：META信息，<BR>不用于返回显示，但需要进行检索内容</TD></TR>
<TR>
<TD>Field.Keyword(String name, String value)</TD>
<TD>No</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD vAlign=top>不切分索引并存储，比如：日期字段</TD></TR>
<TR>
<TD>Field.UnIndexed(String name, String value)</TD>
<TD>No</TD>
<TD>No</TD>
<TD>Yes</TD>
<TD vAlign=top>不索引，只存储，比如：文件路径</TD></TR>
<TR>
<TD>Field.UnStored(String name, String value)</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD vAlign=top>只全文索引，不存储</TD></TR></TBODY></TABLE><PRE>public class IndexFiles { <BR>  //使用方法：: IndexFiles [索引输出目录] [索引的文件列表] ... <BR>  public static void main(String[] args) throws Exception {<BR>    String indexPath = args[0];<BR>    IndexWriter writer;<BR>    //用指定的语言分析器构造一个新的写索引器（第3个参数表示是否为追加索引）<BR>    writer = new IndexWriter(indexPath, new SimpleAnalyzer(), false);<BR><BR>    for (int i=1; i&lt;args.length; i++) {<BR>      System.out.println("Indexing file " + args[i]);<BR>      InputStream is = new FileInputStream(args[i]);<BR><BR>      //构造包含2个字段Field的Document对象<BR>      //一个是路径path字段，不索引，只存储<BR>      //一个是内容body字段，进行全文索引，并存储<BR>      Document doc = new Document();<BR>      doc.add(Field.UnIndexed("path", args[i]));<BR>      doc.add(Field.Text("body", (Reader) new InputStreamReader(is)));<BR>      //将文档写入索引<BR>      writer.addDocument(doc);<BR>      is.close();<BR>    };<BR>    //关闭写索引器<BR>    writer.close();<BR>  }<BR>}<BR>　</PRE>
<P>索引过程中可以看到：</P>
<UL>
<LI>语言分析器提供了抽象的接口，因此语言分析(Analyser)是可以定制的，虽然lucene缺省提供了2个比较通用的分析器SimpleAnalyser和StandardAnalyser，这2个分析器缺省都不支持中文，所以要加入对中文语言的切分规则，需要修改这2个分析器。 </LI>
<LI>Lucene并没有规定数据源的格式，而只提供了一个通用的结构（Document对象）来接受索引的输入，因此输入的数据源可以是：数据库，WORD文档，PDF文档，HTML文档……只要能够设计相应的解析转换器将数据源构造成成Docuement对象即可进行索引。 </LI>
<LI>对于大批量的数据索引，还可以通过调整IndexerWrite的文件合并频率属性（mergeFactor）来提高批量索引的效率。 </LI></UL>
<P>检索过程和结果显示：</P>
<P>搜索结果返回的是Hits对象，可以通过它再访问Document==&gt;Field中的内容。</P>
<P>假设根据body字段进行全文检索，可以将查询结果的path字段和相应查询的匹配度(score)打印出来，</P><PRE>public class Search { <BR>  public static void main(String[] args) throws Exception {<BR>    String indexPath = args[0], queryString = args[1];<BR>    //指向索引目录的搜索器<BR>    Searcher searcher = new IndexSearcher(indexPath);<BR>    //查询解析器：使用和索引同样的语言分析器<BR>    Query query = QueryParser.parse(queryString, "body", <BR>                              new SimpleAnalyzer());<BR>    //搜索结果使用Hits存储<BR>    Hits hits = searcher.search(query);<BR>    //通过hits可以访问到相应字段的数据和查询的匹配度<BR>    for (int i=0; i&lt;hits.length(); i++) {<BR>      System.out.println(hits.doc(i).get("path") + "; Score: " + <BR>                         hits.score(i));<BR>    };<BR>  }<BR>}</PRE>在整个检索过程中，语言分析器，查询分析器，甚至搜索器（Searcher）都是提供了抽象的接口，可以根据需要进行定制。 
<P><B><A>Hacking Lucene</A></B></P>
<P><B>简化的查询分析器</B></P>
<P>个人感觉lucene成为JAKARTA项目后，画在了太多的时间用于调试日趋复杂QueryParser，而其中大部分是大多数用户并不很熟悉的，目前LUCENE支持的语法：</P>
<P>Query ::= ( Clause )*<BR>Clause ::= ["+", "-"] [&lt;TERM&gt; ":"] ( &lt;TERM&gt; | "(" Query ")")</P>
<P>中间的逻辑包括：and or + - &amp;&amp;||等符号，而且还有"短语查询"和针对西文的前缀/模糊查询等，个人感觉对于一般应用来说，这些功能有一些华而不实，其实能够实现目前类似于Google的查询语句分析功能其实对于大多数用户来说已经够了。所以，Lucene早期版本的QueryParser仍是比较好的选择。</P>
<P><B>添加修改删除指定记录（Document）</B></P>
<P>Lucene提供了索引的扩展机制，因此索引的动态扩展应该是没有问题的，而指定记录的修改也似乎只能通过记录的删除，然后重新加入实现。如何删除指定的记录呢？删除的方法也很简单，只是需要在索引时根据数据源中的记录ID专门另建索引，然后利用IndexReader.delete(Termterm)方法通过这个记录ID删除相应的Document。</P>
<P><B>根据某个字段值的排序功能</B></P>
<P>lucene缺省是按照自己的相关度算法（score）进行结果排序的，但能够根据其他字段进行结果排序是一个在LUCENE的开发邮件列表中经常提到的问题，很多原先基于数据库应用都需要除了基于匹配度（score）以外的排序功能。而从全文检索的原理我们可以了解到，任何不基于索引的搜索过程效率都会导致效率非常的低，如果基于其他字段的排序需要在搜索过程中访问存储字段，速度回大大降低，因此非常是不可取的。</P>
<P>但这里也有一个折中的解决方法：在搜索过程中能够影响排序结果的只有索引中已经存储的docID和score这2个参数，所以，基于score以外的排序，其实可以通过将数据源预先排好序，然后根据docID进行排序来实现。这样就避免了在LUCENE搜索结果外对结果再次进行排序和在搜索过程中访问不在索引中的某个字段值。</P>
<P>这里需要修改的是IndexSearcher中的HitCollector过程：</P><PRE>...<BR>　scorer.score(new HitCollector() {<BR> private float minScore = 0.0f;<BR> public final void collect(int doc, float score) {<BR>   if (score &gt; 0.0f &amp;&amp;     // ignore zeroed buckets<BR>       (bits==null || bits.get(doc))) {   // skip docs not in bits<BR>     totalHits[0]++;<BR>     if (score &gt;= minScore) {<BR>              /* 原先：Lucene将docID和相应的匹配度score例入结果命中列表中：<BR>        * hq.put(new ScoreDoc(doc, score));   // update hit queue<BR>               * 如果用doc 或 1/doc 代替 score，就实现了根据docID顺排或逆排<BR>               * 假设数据源索引时已经按照某个字段排好了序，而结果根据docID排序也就实现了<BR>               * 针对某个字段的排序，甚至可以实现更复杂的score和docID的拟合。<BR>               */<BR>              hq.put(new ScoreDoc(doc, (float) 1/doc )); <BR>       if (hq.size() &gt; nDocs) {    // if hit queue overfull<BR>  hq.pop();     // remove lowest in hit queue<BR>  minScore = ((ScoreDoc)hq.top()).score; // reset minScore<BR>       }<BR>     }<BR>   }<BR> }<BR>      }, reader.maxDoc());</PRE>
<P><B>更通用的输入输出接口</B></P>
<P>虽然lucene没有定义一个确定的输入文档格式，但越来越多的人想到使用一个标准的中间格式作为Lucene的数据导入接口，然后其他数据，比如PDF只需要通过解析器转换成标准的中间格式就可以进行数据索引了。这个中间格式主要以XML为主，类似实现已经不下4，5个：</P><PRE>数据源: WORD       PDF     HTML    DB       other<BR>         \          |       |      |         /<BR>                       XML中间格式<BR>                            |<BR>                     Lucene INDEX</PRE>
<P>目前还没有针对MSWord文档的解析器，因为Word文档和基于ASCII的RTF文档不同，需要使用COM对象机制解析。这个是我在Google上查的相关资料：<A href="http://www.intrinsyc.com/products/enterprise_applications.asp">http://www.intrinsyc.com/products/enterprise_applications.asp</A><BR>另外一个办法就是把Word文档转换成text：<A href="http://www.winfield.demon.nl/index.html">http://www.winfield.demon.nl/index.html</A><BR></P>
<P><BR><B>索引过程优化</B></P>
<P>索引一般分2种情况，一种是小批量的索引扩展，一种是大批量的索引重建。在索引过程中，并不是每次新的DOC加入进去索引都重新进行一次索引文件的写入操作（文件I/O是一件非常消耗资源的事情）。</P>
<P>Lucene先在内存中进行索引操作，并根据一定的批量进行文件的写入。这个批次的间隔越大，文件的写入次数越少，但占用内存会很多。反之占用内存少，但文件IO操作频繁，索引速度会很慢。在IndexWriter中有一个MERGE_FACTOR参数可以帮助你在构造索引器后根据应用环境的情况充分利用内存减少文件的操作。根据我的使用经验：缺省Indexer是每20条记录索引后写入一次，每将MERGE_FACTOR增加50倍，索引速度可以提高1倍左右。<BR></P>
<P><SPAN style="FONT-WEIGHT: bold">搜索过程优化<BR></SPAN></P>
<P><SPAN style="FONT-WEIGHT: bold"></SPAN>lucene支持内存索引：这样的搜索比基于文件的I/O有数量级的速度提升。<BR><A href="http://www.onjava.com/lpt/a/3273">http://www.onjava.com/lpt/a/3273</A><BR>而尽可能减少IndexSearcher的创建和对搜索结果的前台的缓存也是必要的。<BR><SPAN style="FONT-WEIGHT: bold"></SPAN></P>
<P>Lucene面向全文检索的优化在于首次索引检索后，并不把所有的记录（Document）具体内容读取出来，而起只将所有结果中匹配度最高的头100条结果（TopDocs）的ID放到结果集缓存中并返回，这里可以比较一下数据库检索：如果是一个10,000条的数据库检索结果集，数据库是一定要把所有记录内容都取得以后再开始返回给应用结果集的。所以即使检索匹配总数很多，Lucene的结果集占用的内存空间也不会很多。对于一般的模糊检索应用是用不到这么多的结果的，头100条已经可以满足90%以上的检索需求。<BR></P>
<P>如果首批缓存结果数用完后还要读取更后面的结果时Searcher会再次检索并生成一个上次的搜索缓存数大1倍的缓存，并再重新向后抓取。所以如果构造一个Searcher去查1－120条结果，Searcher其实是进行了2次搜索过程：头100条取完后，缓存结果用完，Searcher重新检索再构造一个200条的结果缓存，依此类推，400条缓存，800条缓存。由于每次Searcher对象消失后，这些缓存也访问那不到了，你有可能想将结果记录缓存下来，缓存数尽量保证在100以下以充分利用首次的结果缓存，不让Lucene浪费多次检索，而且可以分级进行结果缓存。<BR></P>
<P>Lucene的另外一个特点是在收集结果的过程中将匹配度低的结果自动过滤掉了。这也是和数据库应用需要将搜索的结果全部返回不同之处。</P>
<P><A href="http://sourceforge.net/projects/weblucene/">我的一些尝试</A>：</P>
<UL>
<LI>支持中文的Tokenizer：这里有2个版本，一个是通过JavaCC生成的，对CJK部分按一个字符一个TOKEN索引，另外一个是从SimpleTokenizer改写的，对英文支持数字和字母TOKEN，对中文按迭代索引。 </LI>
<LI>基于XML数据源的索引器：XMLIndexer，因此所有数据源只要能够按照DTD转换成指定的XML，就可以用XMLIndxer进行索引了。 </LI>
<LI>根据某个字段排序：按记录索引顺序排序结果的搜索器：IndexOrderSearcher，因此如果需要让搜索结果根据某个字段排序，可以让数据源先按某个字段排好序（比如：PriceField），这样索引后，然后在利用这个按记录的ID顺序检索的搜索器，结果就是相当于是那个字段排序的结果了。 </LI></UL>
<P><A><B>从Lucene学到更多</B></A></P>
<P>Luene的确是一个面对对象设计的典范</P>
<UL>
<LI>所有的问题都通过一个额外抽象层来方便以后的扩展和重用：你可以通过重新实现来达到自己的目的，而对其他模块而不需要； </LI>
<LI>简单的应用入口Searcher, Indexer，并调用底层一系列组件协同的完成搜索任务； </LI>
<LI>所有的对象的任务都非常专一：比如搜索过程：QueryParser分析将查询语句转换成一系列的精确查询的组合(Query),通过底层的索引读取结构IndexReader进行索引的读取，并用相应的打分器给搜索结果进行打分/排序等。所有的功能模块原子化程度非常高，因此可以通过重新实现而不需要修改其他模块。&nbsp; </LI>
<LI>除了灵活的应用接口设计，Lucene还提供了一些适合大多数应用的语言分析器实现（SimpleAnalyser,StandardAnalyser），这也是新用户能够很快上手的重要原因之一。 </LI></UL>
<P>这些优点都是非常值得在以后的开发中学习借鉴的。作为一个通用工具包，Lunece的确给予了需要将全文检索功能嵌入到应用中的开发者很多的便利。</P>
<P>此外，通过对Lucene的学习和使用，我也更深刻地理解了为什么很多数据库优化设计中要求，比如：</P>
<UL>
<LI>尽可能对字段进行索引来提高查询速度，但过多的索引会对数据库表的更新操作变慢，而对结果过多的排序条件，实际上往往也是性能的杀手之一。 </LI>
<LI>很多商业数据库对大批量的数据插入操作会提供一些优化参数，这个作用和索引器的merge_factor的作用是类似的， </LI>
<LI>20%/80%原则：查的结果多并不等于质量好，尤其对于返回结果集很大，如何优化这头几十条结果的质量往往才是最重要的。 </LI>
<LI>尽可能让应用从数据库中获得比较小的结果集，因为即使对于大型数据库，对结果集的随机访问也是一个非常消耗资源的操作。<BR></LI></UL></div>]]></description>
	    <author><![CDATA[jack&apos;he]]></author>
	    <comments>http://hejianke83.blog.163.com/blog/static/6076516200831443629740</comments>
    <slash:comments>0</slash:comments>
    <guid isPermaLink="true">http://hejianke83.blog.163.com/blog/static/6076516200831443629740</guid>
    <pubDate>Mon, 14 Apr 2008 16:36:29 +0800</pubDate>
    <dcterms:modified>2008-04-16T10:42:48+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[Java多线程编程基础之synchornized]]></title>	
    <link>http://hejianke83.blog.163.com/blog/static/6076516200831141644940</link>
    <description><![CDATA[<div><P><STRONG>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [wait(),notify()/notityAll()方法]</STRONG> <BR><BR>　　关于这两个方法,有很多的内容需要说明.在下面的说明中可能会有很多地方不能一下子明白,但在看完本节后,即使不能完全明白,你也一定要回过头来记住下面的两句话:<BR><BR>　　<STRONG>[wait(),notify()/notityAll()方法是普通对象的方法(Object超类中实现),而不是对象的方法]</STRONG><BR><BR>　　<STRONG>[wait(),notify()/notityAll()方法只能在同步方法中调用]</STRONG><BR><BR>　　<STRONG>[线程的互斥控制]</STRONG> <BR><BR>　　多个线程同时操作某一对象时,一个线程对该对象的操作可能会改变其状态,而该状态会影响另一线程对该对象的真正结果.<BR><BR>　　这个例子我们在太多的文档中可以看到,就象两个操售票员同时售出同一张票一样.</P>
<P style="TEXT-INDENT: 2em">1.线程A在中查询存票,发现票C可以卖出 &nbsp; class="left"</P>
<P style="TEXT-INDENT: 2em">2.线程A接受用户订票请求,<A href="http://action.vogate.com/c/c.php?r=http%3A//www.baidu.com/s%3Flm%3D0%26si%3D%26rn%3D10%26ie%3Dgb2312%26ct%3D0%26wd%3Dsynchornized%26pn%3D40%26ver%3D0%26cl%3D3&amp;aid=6073&amp;sid=6235007045043573&amp;click=1&amp;url=http%3A//www.023qz.com&amp;v=0&amp;s=http%3A//www.src119.com/article/2007/0906/java_42875.html&amp;rn=564643&amp;k=%u51C6%u5907">准备</A>出票. &nbsp; &nbsp; </P>
<P style="TEXT-INDENT: 2em">3.这时切换到了线程B执行 &nbsp; </P>
<P style="TEXT-INDENT: 2em">4.线程B在数据库中查询存票,发现票C可以卖出 &nbsp; </P>
<P style="TEXT-INDENT: 2em">5.线程B将票卖了出去 </P>
<P style="TEXT-INDENT: 2em">6.切换到线程A执行,线程A卖了一张已经卖出的票 &nbsp;</P>
<P style="TEXT-INDENT: 2em">　　所以需要一种机制来管理这类<A href="http://action.vogate.com/c/c.php?r=http%3A//www.baidu.com/s%3Flm%3D0%26si%3D%26rn%3D10%26ie%3Dgb2312%26ct%3D0%26wd%3Dsynchornized%26pn%3D40%26ver%3D0%26cl%3D3&amp;aid=4501&amp;sid=6235007045043573&amp;click=1&amp;url=http%3A//buytech.searchina.net.cn&amp;v=0&amp;s=http%3A//www.src119.com/article/2007/0906/java_42875.html&amp;rn=959092&amp;k=%u95EE%u9898">问题</A>的发生,当某个线程正在执行一个不可分割的部分时,<A href="http://action.vogate.com/c/c.php?r=http%3A//www.baidu.com/s%3Flm%3D0%26si%3D%26rn%3D10%26ie%3Dgb2312%26ct%3D0%26wd%3Dsynchornized%26pn%3D40%26ver%3D0%26cl%3D3&amp;aid=1686&amp;sid=6235007045043573&amp;click=1&amp;url=http%3A//www.xiacode.com&amp;v=0&amp;s=http%3A//www.src119.com/article/2007/0906/java_42875.html&amp;rn=623761&amp;k=%u5176%u5B83">其它</A>线程不能不能同时执行这一部分.</P>
<P style="TEXT-INDENT: 2em">　　象这种控制某一时刻只能有一个线程执行某个执行单元的机制就叫互斥控制或共享互斥(mutual exclusion)</P>
<P style="TEXT-INDENT: 2em">　　在中,用synchornized关键字来实现互斥控制(暂时这样认为,1.5已经<A href="http://action.vogate.com/c/c.php?r=http%3A//www.baidu.com/s%3Flm%3D0%26si%3D%26rn%3D10%26ie%3Dgb2312%26ct%3D0%26wd%3Dsynchornized%26pn%3D40%26ver%3D0%26cl%3D3&amp;aid=5535&amp;sid=6235007045043573&amp;click=1&amp;url=http%3A//www.hjmgs.cn&amp;v=0&amp;s=http%3A//www.src119.com/article/2007/0906/java_42875.html&amp;rn=726740&amp;k=%u53D1%u5C55">发展</A>了新的机制)</P>
<P style="TEXT-INDENT: 2em"><STRONG>　　[synchornized关键字]</STRONG> </P>
<P style="TEXT-INDENT: 2em">　　把一个单元声明为synchornized,就可以让在同一时间只有一个线程操作该方法.</P>
<P style="TEXT-INDENT: 2em">　　有人说synchornized就是一把锁,事实上它确实存在锁,但是是谁的锁,锁谁,这是一个非常复杂的问题.</P>
<P style="TEXT-INDENT: 2em">　　每个对象只有一把监视锁(monitor lock),一次只能被一个线程获取.当一个线程获取了这一个锁后,其它线程就只能等待这个线程释放锁才能再获取.</P>
<P style="TEXT-INDENT: 2em">　　那么synchornized关键字到底锁什么?得到了谁的锁?</P>
<P style="TEXT-INDENT: 2em">　　对于同步块,synchornized获取的是参数中的对象锁:</P>
<P style="TEXT-INDENT: 2em">synchornized(obj){ //............... }</P>
<P style="TEXT-INDENT: 2em">　　线程执行到这里时,首先要获取obj这个实例的锁,如果没有获取到线程只能等待.如果多个线程执行到这里,只能有一个线程获取obj的锁,然后执行{}中的语句,所以,obj对象的作用范围不同,控制程序不同.</P>
<P style="TEXT-INDENT: 2em">　　假如:</P>
<P style="TEXT-INDENT: 2em">public void test(){ Object o = new Object(); synchornized(obj){ //............... } } </P>
<P style="TEXT-INDENT: 2em">　　这段程序控制不了任何,多个线程之间执行到Object o = new Object();时会各自产生一个对象然后获取这个对象有监视锁,各自皆大欢喜地执行.</P>
<P style="TEXT-INDENT: 2em">　　而如果是类的属性:</P>
<P style="TEXT-INDENT: 2em">class Test{ Object o = new Object(); public void test(){ synchornized(o){ //............... } } }</P>
<P style="TEXT-INDENT: 2em">　　所有执行到Test实例的synchornized(o)的线程,只有一个线程可以获取到监视锁.</P>
<P style="TEXT-INDENT: 2em">　　有时我们会这样:</P>
<P style="TEXT-INDENT: 2em">public void test(){ synchornized(this){ //............... } }</P>
<P style="TEXT-INDENT: 2em">　　那么所有执行Test实例的线程只能有一个线程执行.而synchornized(o)和synchornized(this)的范围是不同的,因为执行到Test实例的synchornized(o)的线程等待时,其它线程可以执行Test实例的synchornized(o1)部分,但多个线程同时只有一个可以执行Test实例的synchornized(this).]</P>
<P style="TEXT-INDENT: 2em">　　而对于</P>
<P style="TEXT-INDENT: 2em">synchornized(Test.class){ //............... }</P>
<P style="TEXT-INDENT: 2em">　　这样的同步块而言,所有调用Test多个实例的线程赐教只能有一个线程可以执行.</P>
<P style="TEXT-INDENT: 2em">[synchornized方法] </P>
<P style="TEXT-INDENT: 2em">　　如果一个方法声明为synchornized的,则等同于把在为个方法上调用synchornized(this).</P>
<P style="TEXT-INDENT: 2em">　　如果一个静态方法被声明为synchornized,则等同于把在为个方法上调用synchornized(类.class).</P>
<P style="TEXT-INDENT: 2em">　　现在进入wait方法和notify/notifyAll方法.这两个(或叫三个)方法都是Object对象的方法,而不是线程对象的方法.如同锁一样,它们是在线程中调用某一对象上执行的.</P>
<P style="TEXT-INDENT: 2em">class Test{ public synchornized void test(){ //获取条件,int x 要求大于100; if(x &lt; 100) wait(); } }</P>
<P style="TEXT-INDENT: 2em">　　这里为了说明方法没有加在try{}catch(){}中,如果没有明确在哪个对象上调用wait()方法,则为this.wait();</P>
<P style="TEXT-INDENT: 2em">　　假如:</P>
<P style="TEXT-INDENT: 2em">　　Test t = new Test();</P>
<P style="TEXT-INDENT: 2em">　　现在有两个线程都执行到t.test();方法.其中线程A获取了t的对象锁,进入test()方法内.</P>
<P style="TEXT-INDENT: 2em">　　这时x小于100,所以线程A进入等待.</P>
<P style="TEXT-INDENT: 2em">　　当一个线程调用了wait方法后,这个线程就进入了这个对象的休息室(waitset),这是一个虚拟的对象,但JVM中一定存在这样的一个数据结构用来记录当前对象中有哪些程线程在等待.</P>
<P style="TEXT-INDENT: 2em">　　当一个线程进入等待时,它就会释放锁,让其它线程来获取这个锁.</P>
<P style="TEXT-INDENT: 2em">　　所以线程B有机会获得了线程A释放的锁,进入test()方法,如果这时x还是小于100,线程B也进入了t的休息室.</P>
<P style="TEXT-INDENT: 2em">　　这两个线程只能等待其它线程调用notity[All]来唤醒.</P>
<P style="TEXT-INDENT: 2em">　　但是如果调用的是有参数的wait(time)方法,则线程A,B都会在休息室中等待这个时间后自动唤醒.</P>
<P style="TEXT-INDENT: 2em">[为什么真正的应用都是用while(条件)而不用if(条件)] </P>
<P style="TEXT-INDENT: 2em">　　在实际的编程中我们看到大量的例子都是用?</P>
<P style="TEXT-INDENT: 2em">　　while(x &lt; 100)</P>
<P style="TEXT-INDENT: 2em">　　wait();go();而不是用if,为什么呢?</P>
<P style="TEXT-INDENT: 2em">　　在多个线程同时执行时,if(x &lt;100)是不安全的.因为如果线程A和线程B都在t的休息室中等待,这时另一个线程使x==100了,并调用notifyAll方法,线程A继续执行下面的go().而它执行完成后,x有可能又小于100,比如下面的程序中调用了--x,这时切换到线程B,线程B没有继续判断,直接执行go();就产生一个错误的条件,只有while才能保证线程B又继续检查一次。</P>
<P style="TEXT-INDENT: 2em">　　[notify/notifyAll方法] </P>
<P style="TEXT-INDENT: 2em">　　这两个方法都是把某个对象上休息区内的线程唤醒,notify只能唤醒一个,但究竟是哪一个不能确定,而notifyAll则唤醒这个对象上的休息室中所有的线程.</P>
<P style="TEXT-INDENT: 2em">　　一般有为了安全性,我们在绝对多数时候应该<A href="http://action.vogate.com/c/c.php?r=http%3A//www.baidu.com/s%3Flm%3D0%26si%3D%26rn%3D10%26ie%3Dgb2312%26ct%3D0%26wd%3Dsynchornized%26pn%3D40%26ver%3D0%26cl%3D3&amp;aid=5383&amp;sid=6235007045043573&amp;click=1&amp;url=http%3A//biyela.net&amp;v=0&amp;s=http%3A//www.src119.com/article/2007/0906/java_42875.html&amp;rn=972406&amp;k=%u4F7F%u7528">使用</A>notifiAll(),除非你明确知道只唤醒其中的一个线程.</P>
<P style="TEXT-INDENT: 2em">　　那么是否是只要调用一个对象的wait()方法,当前线程就进入了这个对象的休息室呢?事实中,要调用一个对象的wait()方法,只有当前线程获取了这个对象的锁,换句话说一定要在这个对象的同步方法或以这个对象为参数的同步块中.</P>
<P style="TEXT-INDENT: 2em">class MyThread extends Thread{ Test t = new Test(); public void run(){ t.test(); System.out.println("Thread say:Hello,World!"); } } public class Test { int x = 0; public void test(){ if(x==0) try{ wait(); }catch(Exception e){} } public static void main(String[] args) throws Exception{ new MyThread().start(); } } </P>
<P style="TEXT-INDENT: 2em">　　这个线程就不会进入t的wait方法而直接打印出Thread say:Hello,World!.</P>
<P style="TEXT-INDENT: 2em">　　而如果改成:</P>
<P style="TEXT-INDENT: 2em">public class Test { int x = 0; public synchornized void test(){ if(x==0) try{ wait(); }catch(Exception e){} } public static void main(String[] args) throws Exception{ new MyThread().start(); } }　　我们就可以看到线程一直等待,注意这个线程进入等待后没有其它线程唤醒,除非强行退出JVM环境,否则它一直等待.</P>
<P style="TEXT-INDENT: 2em">　　所以请记住:</P>
<P style="TEXT-INDENT: 2em">　　[线程要想调用一个对象的wait()方法就要先获得该对象的监视锁,而一旦调用wait()后又立即释放该锁]</P>
<P style="TEXT-INDENT: 2em"><BR></P></div>]]></description>
	    <author><![CDATA[jack&apos;he]]></author>
	    <comments>http://hejianke83.blog.163.com/blog/static/6076516200831141644940</comments>
    <slash:comments>2</slash:comments>
    <guid isPermaLink="true">http://hejianke83.blog.163.com/blog/static/6076516200831141644940</guid>
    <pubDate>Fri, 11 Apr 2008 16:16:44 +0800</pubDate>
    <dcterms:modified>2008-04-11T16:16:44+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[做网络必须掌握的83句话]]></title>	
    <link>http://hejianke83.blog.163.com/blog/static/6076516200831093832115</link>
    <description><![CDATA[<div><p>做网络必须掌握的83句话，网络成功可以复制<br>1，网络的成功，是可以复制的。 <br>2，自己做不了的事情，找别人来完成。 <br>3，交际是网络创业成功的捷径。 <br>4，做网络的真正的高手，都是年龄大于35岁的。 <br>5，技术是最次要的一个环节。 <br>6，一个人从开始做网络到正规站阶段，至少需要5年的时间。 <br>7，一个垃圾团队的能力远超出一个天才的全部。 <br>8，在投资上节约的人，就是最会浪费的人。 <br>9，用最简单的程序来完成最复杂的要求，就是最完美的网站。 <br>10，广告的最高境界，就是不像广告。 <br>11，绝不放过任何一个比我们收入高的人。 <br>12，创意站，将是未来10年内网络发展的主角。 <br>13，网络从来不相信什么元老。 <br>14，身边一定要有大于自己20岁以上的朋友。 <br>15，全民皆赚，全民皆转，唯我独赚。 <br>16，真正的网络高手，都看起来像新手，真正的新手，在群上往往表现的像高手。 <br>17，一个团队的年龄段可以拉大，但是层次一定不要拉的太大。 <br>18，别人把自己的商业机密告诉你，只有两个原因，一是你是他的朋友，二是你是他的潜在投资者。 <br>19，一个群，要想有团结力，要想由一个群变成一个团队，必须要做到的就是高门槛。 <br>20，当别人都在做网站的时候，我们就要出售网站创意，当别人都在出售网站创意的时候，我们就要出售网站，当别人又在出售网站的时候，我们就去出售字画。 <br>21，我在群上对你好，说明我害怕你，因为我怕你捣乱，所以我对你好，我越对你好，说明我越讨厌你，生怕你给我惹事。 <br>22，被朋友利用，那说明你没有做事的原则，朋友之间绝对不能有经济来往，朋友不会成为你的客户，但是客户有可能成为你的朋友。 <br>23，一个领导者，一个管理者，最应该避讳的就是与自己团队里的女性朋友的亲密接触，哪怕是狼，在团队面前，也要披上羊皮，否则很快就将失去自己的色彩。 <br>24，一个人，到了30岁，在实业上还没有起色，想通过网络来获得高收入，那么我可以答复你，可能性为0，因为收入决定于一个人的情商，无论实业，还是网络行业，都是通用的。是金子，在哪里都发光，换句话说，是垃圾，到哪里都成不了金子。 <br>25，在网络上，小钱靠技术，中钱靠技巧，大钱靠运营。 <br>26，让关键词排名第一，不一定就是要靠SEO，还可以创造搜索源。 <br>27，三等软文带网址，二等软文带QQ，一等软文被置顶。 <br>28，你应该最大化的利用懂懂，无论懂懂脾气多么不好，性格多么古怪，在这一块网络地皮上，还是他的土地拥有权，他曾经利用这块地皮炒出过十多个月收入10万元以上的人，你能不能走红，能不能发展起来，关键是看你有没有靠近他，有没有让他主动的为你宣传。 <br>29，每10个跟着懂懂的人，就有5个人能够达到500元/天以上的收入，就有1个能够达到1000元/天的收入，就有1/1000个人能够做到一年几百万的利润，但是有50%的人是发展不起来的，你有50%的可能是发展不起来的，你只有千分之一的可能会成为网络奇才。 <br>30，无论是谁，只要产生了群内交易，那么出售方都会被这个群体所淘汰，因为群内交易，肯定会出问题的，到现在为止，有几十个人都因为这个出局了，没有一个人跳出这个怪圈。 <br>31，对你真正发自内心好的人，不是口口声声赞美你的人，也不是口口声声喊你哥哥或者弟弟的人，而是那些在背后默默的支持着的人，君子之交淡如水，同样比油还浓的交情，肯定不是君子。 <br>32，如果你和我说，你的QQ有个牛人，他说一天能挣几万块，那么我可以告诉你，你找错人了，因为如果他连你的QQ的信息都回复的话，那么说明他要回复更 多的和你一样傻的人的信息，那么他一天除了聊QQ外基本上不做事，这不是做事人的做事态度，所以判断一个人是不是高手，一个粗略的判断方法，那就是你加他 QQ，他和不和你聊天。 <br>33，如果一个人，主动的要推销，要带你做网络，那么你可以放弃选择他为老师，因为真正的高手，都是没有时间带学生的，真正带学生的，没有高手。 <br>34，如果你小于20岁，你在网络上骂街，那么我佩服你的年轻，如果你是20-30岁之间在骂街，那么我怀疑你的无聊，如果你大于30岁，那么我怀疑的不是你的无聊，而是怀疑你的智商和神经。 <br>35，智者不骂，骂者不智，要想去惩罚一个人，最好的办法就是鼓励他，而不是去遏止他。 <br>36，第三页+正规广告页=广告中的罗那尔多。 <br>37，如果你想赚钱，那么请你拿出半年的时间来学习，如果你不想赚钱，那么你可能会在学习上浪费1年以上的时间，最后还是选择了放弃网络。 <br>38，如果你准备做网络培训来装B，那么我建议你什么都要学，如果你准备挣钱，那么我建议你抓住一个小小的知识点，然后做起来。 <br>39，做网络的，收入越高，长相越丑，刚才我照了一下镜子，突然发现自己帅了很多。呕咽！ <br>40，群管理的法宝，就是让群上的每一个人都把这里当家，让他们把这里当家的法宝就是把他们每天都介绍一遍。 <br>41，如果你的网站被黑了，首先怀疑的就是和你关系最好的，而不是平时你最讨厌的那个。 <br>42，在商界，没有永远的客户，只有永恒的利益，一旦你的团队没有了新的知识，新的动力，那么也就是你的团队宣布结束的时刻。 <br>43，说自己一分钱没挣到的，这种是真没收入，说自己挣到了1000元/天的，这种收入在100元/天以内，说自己收入很了了的，这种收入在1000元/天以上。 <br>44，这几年，跟着我的人中，有收入过万/天的，他们有的希望我倒下，因为他们不希望他们的背后曾经挂着我的学生的名头，有收入低于10元/天的，他们希 望我倒下，因为他们除了呐喊两声，实在是找不到发泄的地方了，有同行希望我倒下，因为我来的太突然了，忘了给他们送礼，影响了他们的地位。 <br>46，当有人决定让你和被批斗的地主一样，游行街头的时候，你最佳的回击方式是选择沉默，因为你对他最大的打击，就是根本就没把他当回事。 <br>47，网络和现实一样， 不是暴利，99%的网站的日收入不会超过50元人民币，注意是99% 。 <br>50，你应该提防每一个奉承你的人，因为他是一个善于评头论足的人，今天评你的头，后天就论你的足。 <br>51，做网络，一定要表现出来自己的一点爱好，哪怕自己根本就不懂这行，你也要表现出来，因为它可以给你带来巨额收入，例如懂懂，连个字都不认识几个，还装比去收藏字画， 不过是敛财的手段而已。。 <br>52，你要真准备做网络，首先应该放弃使用QQ。 <br>53，一个人在网络上的素质，绝对正比于他的学历和年龄。 <br>54，做网络的最高境界，就是实事求是。 <br>55，如果你准备与一个人谈生意，千万不要男扮女装，因为一旦成交后，你在他心中永远对是一个另类，因为他觉得你这个人太不实在了，记住，不要去装女的。 <br>56，给对方打电话前，要先短信预约。 <br>57，我今年25岁，看一个10岁天才的孩子的话，觉得他很幼稚，同样一个45岁的人，看我的行为，一样能够看出我的幼稚，我玩一个10岁的孩子，玩的他不知道东南西北，同样，45岁的朋友玩我，也会玩的我不知道东南西北，所以人与人之间最大的差距，就在年龄和经验上。 <br>58，走到一个团队，首先想到的就是要做这个团队的老大，要把这个团队上能够对自己有利的人全部拉为自己的人，当自己离开这个团队的时候，也就是这个团队宣布属于自己的时候。 <br>59，你问我中创值不值做，那么我给你的答案就是，只要符合两个条件的事业，就值得你去做，一是合法，二是暴利。 <br>60，如果你比别人晚1年半入群，而想马上跟上节奏，那么你就问一下自己，你在上学的时候，是不是从小学直接上的高一？所以你最应该做的不是去挣钱，而是花更多的时间去补习过去的功课。 <br>61，买空间哪里的好啊？买就买最贵的，你问我是不是SB？那么我可以告诉你，2个月后，你就知道自己是多么SB了。 <br>62，如果你收100元入你的群，那么来的都是25岁以下的，如果你收1000元，那么进你的群的都是创业失败的中年人，如果你收5000元入群，那么来的都是在实业上做的不错的，如果你收1万元入群，那么他们可能都不是来听你讲课的。。 <br>63，你犯了错误，我不说你，我还会去为你辩护，一方面说明我是对这个群负责的，无论你对也好，错也好，我都是支持你的，但是同时我有更深层的意思，那就是纵容你继续犯错误，然后被群上的兄弟们把你主动的赶走。。 <br>66，一个方法，如果我1万元卖给你，你能收入5万元，如果我1000元卖给你，你有可能做起来，如果我免费告诉你的，那么你肯定做不起来。所以为了让你 挣到钱，我有这个责任来收你的钱。。<br>67，看不惯别人，是自己的修养不够，所以为了锻炼自己的修养，我找了一个脾气最多的老婆。。 <br>68，一个人，生活的质量如何，不看他的收入，而是看他是否活的快乐，活的开心，我说钟情姐是群上最笨的一个，但是我觉得她反过来是活的最开心的一个，因为老朋友们都喜欢她，她的流量网站等都是老朋友们帮他做的。 <br>69，如果一个软件，描述的非常好，你准备去买，那么我可以告诉你，你没有必要投资了，真正可以产生暴利的软件，都是在这个软件没有开发以前，当一个软件，连你都知道是暴利的时候，你就没有必要投资了， 因为在你知道之前，肯定有更多的人知道。 <br>71，网站流量高，不一定网站就有人气，有人气，一定就会慢慢的有流量的。 <br>72，不要指望别人对你忠诚一辈子，因为你仅仅代表了一个层次，当对方发展的高于你这个层次或者低于这个层次的时候，他就脱离了你这个团队。 <br>73，在一个团队里也好，在一个公司里也好，在一个企业里也好，在一个小组里也好，与领头羊搞好关系，是你能够在这里工作的很愉快的前提，当然也是你事业有所突破的前提。 <br>74，如果有谣言传出，这个最值得怀疑的人，就是天天向你打听进展，关心你的人。。 <br>75，当你的团队中或者你的圈子中有人出了问题，或者是经济纠纷或者是其他问题， 别人来攻击你的时候，你应该保持沉默，而且不要去掺合，去解释，因为一杯水，你要想让他澄清，最好的办法就是让它静止下来，而不是去摇晃它。<br>76，如果一个群，你花了100元就可以进去，那么说明这个群的价值，低于100元，因为群主对你的重视程度，就是100块钱的。 <br>77，南方人智商高，一方面可能是网络精英，一方面可能是网络大盗，北方人豪爽，一方面是怒气冲天，一方面是两肋插刀，山东人喜欢礼尚往来，但是在生意场上，礼尚往来是破坏规矩的最大的隐患。 <br>78，如果你组建了团队，而你又不敢去淘汰的糟粕的话， 说明你本身就是一个胆怯的人。 <br>79，正常情况下，一个人从0日收入到500元/天的收入，至少也要经历1年的学习时间。 <br>80，如果有人推出了网络项目，他承诺一天收入500元，而且这个人在网络上有网站，也有一个固定的圈子，首先我可以肯定这个项目是真实可以达到500元/天的收入的，但是网络项目都是具有时效性的，一般暴利期不会超过1个月。 <br>82，读万卷书，不如阅百人，所以通过一个站，能够结交各类朋友，能够快速的提升自己的生活阅历。<br>83，生活中，无意中遇到比我们强的人，一定要想法把他运营成自己的朋友，无论吃饭还是游玩，都要自己主动的去买单，因为我们可以得到更高的回报，他之所 以比我们强，因为他们更懂的投资回报比，他们心里的称更准，没有一个高人愿意接受一个比自己差的人的恩赐的，所以他随意一个小动作，就让你成名或者有银子 了。</p>
<p>&nbsp;</p></div>]]></description>
	    <author><![CDATA[jack&apos;he]]></author>
	    <comments>http://hejianke83.blog.163.com/blog/static/6076516200831093832115</comments>
    <slash:comments>1</slash:comments>
    <guid isPermaLink="true">http://hejianke83.blog.163.com/blog/static/6076516200831093832115</guid>
    <pubDate>Thu, 10 Apr 2008 21:38:32 +0800</pubDate>
    <dcterms:modified>2008-04-14T16:28:42+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[百万数据分页技术]]></title>	
    <link>http://hejianke83.blog.163.com/blog/static/60765162008310105522261</link>
    <description><![CDATA[<div><P>用java程序查询1百万的数据库,如何加快分页跳转的速度? </P>
<P>一般有常用几种基本的方法可以借鉴：</P>
<P>第一：</P>
<P>hibernate中的oracle分页查询原代码：<BR>StringBuffer pagingSelect = new StringBuffer(100);<BR>pagingSelect.append("select * from ( select row_.*, rownum rownum_ from ( ");<BR>pagingSelect.append(sql);<BR>pagingSelect.append(" ) row_ where rownum &lt;= ?) where rownum_ &gt; ?");<BR><BR>其实就是<BR>select * from ( select row_.*, rownum rownum_ from ( 你的查询语句 ) <BR>row_ where rownum &lt;= 结束行) where rownum_ &gt; 开始行</P>
<P>&nbsp;</P>
<P>第二：</P>
<P>这个要看用哪个字段排序了，如果按照ID之类的，即是主键聚集索引，下面这个思想的分页很快，百万级别，分到后面100W条左右600毫秒，解决千万级别估计没啥问题。<BR><BR>先取出第N条的ID，例如 select top 1000000 @ID = ID;<BR>上句将占99%的查询成本。<BR>然后select top 10 * where ID &gt;前面取出的ID即可<BR></P>
<P>第三：</P>
<P>1. 总共只需要一个查询总页数: select count(proid) from sys.tblproduct，而不是每翻页就去查询一次<BR><BR>2. SQL语句中只需要一次排序就可以了，不需要多次排序<BR>select productname,proid,addtime,prodetail from <BR>(select productname,proid,addtime,prodetail, rownum as rid <BR>from (select productname,proid,addtime,prodetail from sys.tblproduct order by proid)<BR>where rownum &lt;= &amp;intPage * &amp;intPageSize<BR>) where rid &gt;= (&amp;intPage-1) * &amp;intPageSize+1<BR></P>
<P>第四：</P>
<P>采用orcale的数据分区功能，分区后速度提升很明显。<BR>另外一个关键是要合理的索引设置<BR>硬件的配置也要跟上</P>
<P>第五：</P>
<P>用分析函数row_number(order by XX)会比较快，比rownum的性能好一些<BR>hibernate不用的主要原因，我猜测是解析起来有点麻烦，必须在查询语句中间插一句，容易错。<BR><BR>问题的另一个关键是，有必要在任何条件下给客户看全部数据么？客户关心么？<BR>和客户交流，看他们能接受什么样的默认的查询条件限制，这来得实际多了。<BR><BR></P></div>]]></description>
	    <author><![CDATA[jack&apos;he]]></author>
	    <comments>http://hejianke83.blog.163.com/blog/static/60765162008310105522261</comments>
    <slash:comments>0</slash:comments>
    <guid isPermaLink="true">http://hejianke83.blog.163.com/blog/static/60765162008310105522261</guid>
    <pubDate>Thu, 10 Apr 2008 10:55:22 +0800</pubDate>
    <dcterms:modified>2008-04-10T10:55:22+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[JMS编程]]></title>	
    <link>http://hejianke83.blog.163.com/blog/static/60765162008386457274</link>
    <description><![CDATA[<div><br>用JMS编程<br>在本章中，我们将讨论Java 消息发送服务（JMS）接口概念和MQSeries 实施，以及如<br>何使用JMS 编程。我们将在消息发送编程模式的上下文中探讨JMS 概念。<br><br><strong>8.1 什么是JMS?</strong><br>与JDBC API for databases 一样，Java Message Services（JMS）是消息发送的标准API。<br>JMS 规范（1.0.2）由Sun Microsystems 开发，IBM 和其他企业消息发送销售商、事务处<br>理销售商以及RDBMS 销售商都积极参与了开发过程。JMS 为Java 程序与对消息发送<br>系统对象进行各种操作的消息发送系统进行互动提供了一个常见的模型。程序对消息发<br>送系统对象进行的常见操作包括创建消息、发送消息、接收消息以及从企业消息发送系<br>统中读取消息。JMS 为那些用Java 开发的程序提供了一种访问这些消息发送系统操作<br>的常见方法。<br><strong>JMS 具有两种消息发送风格，或者说它具有两个域：<br></strong>&#1048599; 一对一或点到点模型；<br>&#1048599; 发布／预订模型。<br>JMS 仅仅是种规范。每个企业消息发送系统销售商都必须就其特定的消息发送系统提供<br>实施规范的类。<br>在本章中，我们将描述JMS API 的MQSeries 实施、讨论JMS API 概念和MQSeries 的<br>JMS 实施能力，并讲解在可以利用MQSeries JMS 实施的不同情境中如何利用MQSeries<br>JMS。<br>为什么要使用JMS？<br>JMS 标准非常重要，其原因在于：<br>&#1048599; 它是第一个获取广泛跨行业支持的企业消息发送API；<br>&#1048599; 它提供的标准消息发送概念和惯例适用于广泛的企业消息发送系统，因而简化了<br>企业应用程序的开发；<br>&#1048599; 它可以利用现有的、企业证明成功可行的消息发送系统；<br>&#1048599; 它添加了完全用现有非JMS 客户机解释的新JMS 客户机，从而允许您扩展现有的<br>基于消息的应用程序；<br>&#1048599; 它允许您可以编写便携性强的基于消息的商业应用程序。<br><br><strong>8.2 概述<br></strong>JMS 是定义JMS 客户机如何访问企业消息发送产品功能的一系列接口和相关语义。我<br>们这里所描述的消息是指企业应用程序所使用的异步请求、报表或事件。它们既包含协<br>同这些系统所需的重要信息；又包含着描述特定商业行为的精确格式化的数据。通过这<br>些消息的交流，每个应用程序都能跟踪企业的发展。<br>JMS 定义了一系列常见的企业消息发送概念和功能。它最大限度地减少了Java 语言程<br>序设计人员在使用企业消息发送产品前必须学会的概念集。也最大限度地加强了消息发<br>送应用程序的便携性。JMS 标准虽然提供了独立于不同销售商的编程接口，但是并不定<br>义出通讯协议。<br>JMS 模型<br>JMS 定义了消息传递服务的一般视图。理解该视图，并弄清它是如何映射到底层的<br>MQSeries 传输上的，相当重要。一般JMS 模型是建立在Sun 的javax.jms 包所定义的接<br>口上的，请见图8－1。<br><br><br>连接<br>连接提供了到底层传输的访问，并被用来创建会话。在MQSeries 上下文中，连接提供<br>了储存参数，如队列管理器名、远程主机名（在Java 客户连接性中）等的地方。换言之，<br>MQSeries JMS 连接一般都在Java 虚拟机之外分配MQSeries 资源。连接也支持同时使用。<br>连接可以提供以下好处：<br>&#1048599; 包括与JMS 供应方的开放式连接。它通常代表客户机和供应方服务端口之间的一<br>个开放的TCP／IP 槽；<br>&#1048599; 它的创建就是客户机认证发生之处；<br>&#1048599; 它可以指定唯一的客户机标识符；<br><br>&#1048599; 它提供ConnectionMetaData；<br>&#1048599; 它支持可选的ExceptionListener。<br>由于建立连接时完成了认证和通讯设置，因此连接相对来说是个重量级的JMS 对象。<br>大多数客户机都使用单一的连接进行消息发送。其他更先进的应用程序可能会使用几个<br>连接。JMS 并不为使用多个连接而设计原因；但是，这样做可能有操作上的原因。<br>JMS 客户机一般创建一个连接、一个或多个会话以及许多消息生成器和使用者。当创建<br>连接时，它处在停止模式，这就是说没有消息再被送达。<br>重点：连接是在停止模式中创建的。<br>通常，直到设置完成前，连接都处在停止模式中。在完成时，将调用连接的start（）方<br>法，而消息则开始到达连接的使用者。此设置惯例可以在客户机仍在进行设置过程中尽<br>可能减少异步消息送达所带来的任何客户机混乱。<br>连接可以立即启动，而设置可在随后进行。这样做的客户机必须在设置过程中就准备好<br>处理异步消息送达。<br>提示：消息生成器可以在停止连接时发送消息。<br>不是直接创建连接的，而是利用连接库建立的。库对象可以储存在JNDI 名称空间中，<br>从而将JMS 应用程序与供应方特定信息隔离开来。连接库对象是利用MQSeries JMS 管<br>理工具JMSAdmin 创建的。该工具使得管理员可以给JNDI 名称空间定义MQSeries JMS<br>对象的8 种类型。请参见第8.4.9 节《利用JMSAdmin 以VisualAge for Java 管理JMS JNDI<br>对象》（见本书第260 页）。<br>创建连接<br>客户机利用连接库来创建连接。要使用何种连接库类型取决于您想要哪种类型的连接：<br>&#1048599; 就PTP 连接而言，我们利用QueueConnectionFactory 或XAQueueConnectionFactory<br>来获取QueueConnection 或XAQueueConnection；<br><br>&#1048599; 就发布／ 预订消息发送模式而言， 我们利用TopicConnectionFactory 或<br>XATopicConnectionFactory 来获取TopicConnection 或XATopicConnection。<br>为了创建连接，我们应当进行以工作：<br>&#1048599; 从JNDI 名称空间接收库对象<br>JNDI API 向以Java 编写的应用程序提供了命名和目录功能。它是利用Java 的对象<br>模型专门为Java 设计的。利用JNDI，Java 应用程序可以储存并接收任何类型的命<br>名为Java 的对象。另外，JNDI 提供进行标准目录操作的方法，如将属性与对象相<br>关联并利用对象属性查找对象等。<br>在此常见的API 之后，可以无缝地插入不同的命名和目录服务供应方。这使得Java<br>应用程序可以通过各种各样的命名和目录服务来利用信息，如LDAP、NDS、DNS<br>和NIS（YP）等，也使得Java 应用程序可以与传统应用程序和系统并存。<br>在JNDI 中，所有的命名和目录操作都是根据上下文进行的。没有绝对的根。因此，<br>JNDI 定义了初始上下文，它是命名和目录操作名解析的起始点。一旦有了初始上<br>下文，您就可以利用它来查看其他上下文和对象。<br>&#1048599; 为了从JNDI 名称空间接收对象，必须按照下面这段代码所显示的那样设置初始上<br>下文：<br>import javax.jms.*<br>import javax.naming.*；<br>import javax.naming.directory.*；<br>java.util.Hashtable ；<br>Hashtable env ＝new Hashtable（）；<br>env.put（Context.INITIAL_CCONTEXT_FACTORY,icf）；<br>env.put（Context.PROVIDER_URL,url）；<br>Context ctx ＝new InitialDirContext（env）；<br>Icf 为初始上下文定义了库类，url 则定义了随上下文而变的URL。<br>&#1048599; 一旦获取了初始上下文，我们就可以利用lookup（）方法来从名称空间接收对象。<br>下面这段代码从基于LDAP 的名称空间接收QueueConnectionFactory 名firstQCF；<br>QueueConnectionFactory qFactory ；<br>queueFactory ＝（QueueConnectionFactory）ctx.lookup（“cn＝firstQCF ”）；<br>&#1048599; 利用库对象来获取连接。<br>241<br>利用库对象的createQueueConnection（）方法来创建连接，请参见如下的例子：<br>QueueConnection connection ；<br>connection ＝qFactory.createQueueConnection（）；<br>&#1048599; 启动连接<br>JMS 规范定义指出，应当在“停止”状态下创建连接。在您可以利用连接发送消息<br>之前，必须显式启动连接。<br>我们利用start（）方法启动连接，请参见如下的例子：<br>connection.start（）；<br>会话<br>为生成和使用消息提供上下文，包括用来创建消息生成器和消息使用者的方法。<br>JMS 会话是生成和使用消息的单线程上下文。尽管它可以在Java 虚拟机之外分配供应<br>方资源，但我们还是将其看作轻量级JMS 对象。<br>我们可以分别利用连接对象的createQueueSession（）或createTopicSession（）方法来创<br>建会话。<br>创建会话方法包括两个参数：<br>1. 可决定会话是否进行事务处理的boolean。<br>在事务处理的会话中，全部发送、或者全部接收作为一个单位的一组消息。<br>在非事务处理会话中，分别发送或接收消息。<br>2. 定义识别模式的参数。<br>请参见如下的例子：<br>session ＝connection.createQueueSession（false ,Session.AUTO_ACKNOWLEDGE）；<br>这是用AUTO_ACKNOWLEDGE 来创建非事务处理会话的最简单的情况。连接是<br>线程安全的，但会话和由会话创建的对象不是线程安全的。我们建议多线程应用程<br>序应当对每个线程都使用不同的会话。<br>会话有以下几种用途：<br>&#1048599; 它是消息生成器和使用者的库；<br>&#1048599; 它提供了供应方优化的消息库；<br><br>&#1048599; 它既支持单一事务处理，又支持一系列将跨越生成器和使用者的库结合到原子单<br>位的事务处理；<br>&#1048599; 会话为它使用和生成的消息定义了连续序列；会话保存了它使用的消息，直到识<br>别该消息；<br>&#1048599; 会话串行化注册到消息使用者的消息侦听器。<br>会话可以创建并服务于多个消息生成器和使用者。<br>一种典型的用法就是在消息到达前一直在同步消息使用者上保持线程块。然后线程可以<br>使用一个或更多的会话消息生成器。<br>如果一个客户机希望在其他客户机使用消息时具备一个生成消息的线程，那么该客户机<br>就应当为生成线程使用另外的会话。<br>一旦启动了连接，任何具有侦听器或注册消息侦听器的会话就会被赋予送达消息的控制<br>线程。客户机代码从另一个控制线程利用会话或任何构成会话的对象都是错误的。唯一<br>的例外就是使用会话或连接关闭方法。<br>大多数客户机将它们的库自然地分成会话应当是比较容易的。该模型允许客户机简单启<br>动并随着并行操作需要的增加而逐渐增加消息线程的复杂度。<br>关闭方法是当另一个线程正在执行某个其他会话方法时唯一可以调用的会话方法。<br>我们可以选择地指定会话为事务处理会话。每个事务处理会话都支持单一系列的事务处<br>理。每个事务处理会将一系列消息发送和一系列消息接收归组到原子库单元中。事实上，<br>事务处理将会话的输入消息流和输出消息流组织到原子单位集中。当提交事务处理时，<br>会确认输入的原子单位，同时发送与其相关联的输出原子单位。如果已经进行了事务处<br>理回退，那么其发送的消息则被毁坏，会话的输入也被自动恢复。<br>事务处理输入和输出单位的内容就是会话的当前事务处理中所生成和使用的那些消息。<br><br>我们可以利用会话的提交或回退方法完成事务处理。会话的当前事务处理的完成将自动<br>开始下一个事务处理。其结果就是，事务处理会话总是具有一个当前事务处理，且其库<br>就在当前事务处理中完成。<br>消息生成器<br>JMS 客户机利用消息生成器发送消息到特定的目的地。我们通过传递目的地到会话对象<br>提供的创建消息生成器方法，从而创建消息生成器。<br>在点到点消息发送中，这将是利用QueueSession 对象上的createSender 方法所创建的<br>QueueSender。QueueSender 通常是为特定队列创建的，因此所有利用该发送器发送的消<br>息都会被发送到同样的目的地。我们利用队列对象指定目的地。队列对象即可以在运行<br>时间中创建，也可以在JNDI 名称空间中构造和储存。请参见如下的例子：<br>Queue ioQueue ；<br>ioQueue ＝ （Queue）.ctx.lookup（qLookUp） ；<br>sender ＝ session.createSender（ioQueue）；<br>在发布／预订消息发送中，这将是在TopicSession 对象上利用createPublisher 方法创建<br>的TopicPublisher。<br>通常，T