﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-The blog of Astro Qi-随笔分类-Java</title><link>http://www.blogjava.net/AstroQi/category/32540.html</link><description>I'm Astro Qi. If call me, please send email to closoastroqi@126.com</description><language>zh-cn</language><lastBuildDate>Thu, 09 Jun 2011 10:01:28 GMT</lastBuildDate><pubDate>Thu, 09 Jun 2011 10:01:28 GMT</pubDate><ttl>60</ttl><item><title>对 java.nio.ByteBuffer 的理解</title><link>http://www.blogjava.net/AstroQi/archive/2011/05/18/350457.html</link><dc:creator>Astro.Qi</dc:creator><author>Astro.Qi</author><pubDate>Wed, 18 May 2011 02:53:00 GMT</pubDate><guid>http://www.blogjava.net/AstroQi/archive/2011/05/18/350457.html</guid><wfw:comment>http://www.blogjava.net/AstroQi/comments/350457.html</wfw:comment><comments>http://www.blogjava.net/AstroQi/archive/2011/05/18/350457.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/AstroQi/comments/commentRss/350457.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/AstroQi/services/trackbacks/350457.html</trackback:ping><description><![CDATA[<div><div id="xspace-showmessage" style="word-break: break-all; margin-right: auto; margin-left: auto; margin-top: 0.5em; margin-bottom: 0.5em; width: 554px; overflow-x: auto; overflow-y: hidden; font-family: Arial, Helvetica, sans-serif; font-size: 12px; "><span class="Apple-style-span" style="line-height: 1.8em; "><strong style="word-break: break-all; line-height: normal; "><br />今晚用到 ByteBuffer, 我跟 joy 都是初学&nbsp;<a href="http://space.itpub.net/14734416/viewspace-434476" target="_self" style="word-break: break-all; text-decoration: underline; color: #000066; line-height: normal; "><u style="word-break: break-all; line-height: normal; "><strong style="word-break: break-all; line-height: normal; ">java</strong></u></a>, 文档里的中文翻译实在是看他母亲不懂, 晕了半天, 作了几个测试, 终于把这个类的用法搞清楚了, 顺便臆想了哈其工作原理.<wbr style="word-break: break-all; line-height: normal; "><br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " /></strong>先列点代码片段:<br style="word-break: break-all; line-height: normal; " />// ...<br style="word-break: break-all; line-height: normal; " />//<br style="word-break: break-all; line-height: normal; " />// 此段代码功能为从 t.txt 里复制所有数据到 out_j.txt:<br style="word-break: break-all; line-height: normal; " />//<br style="word-break: break-all; line-height: normal; " />...<br style="word-break: break-all; line-height: normal; " />1　FileChannel fcin = new FileInputStream( "d:/t.txt" ).getChannel();<wbr style="word-break: break-all; line-height: normal; "><br style="word-break: break-all; line-height: normal; " />2　FileChannel fcout = new FileOutputStream( new File( "d:/out_j.txt" )).getChannel();<wbr style="word-break: break-all; line-height: normal; "><br style="word-break: break-all; line-height: normal; " />3　ByteBuffer buff = ByteBuffer.allocate( 1024 );<wbr style="word-break: break-all; line-height: normal; "><br style="word-break: break-all; line-height: normal; " />4　long t1 = System.currentTimeMillis();<wbr style="word-break: break-all; line-height: normal; "><br style="word-break: break-all; line-height: normal; " />5<wbr style="word-break: break-all; line-height: normal; "><br style="word-break: break-all; line-height: normal; " />6　while( fcin.read( buff ) != -1 )<wbr style="word-break: break-all; line-height: normal; "><br style="word-break: break-all; line-height: normal; " />7　{<wbr style="word-break: break-all; line-height: normal; "><br style="word-break: break-all; line-height: normal; " />8　　　buff.flip();<wbr style="word-break: break-all; line-height: normal; "><br style="word-break: break-all; line-height: normal; " />9　　　fcout.write( buff );<wbr style="word-break: break-all; line-height: normal; "><br style="word-break: break-all; line-height: normal; " />10　　　buff.clear();<wbr style="word-break: break-all; line-height: normal; "><br style="word-break: break-all; line-height: normal; " />11　}<wbr style="word-break: break-all; line-height: normal; "><br style="word-break: break-all; line-height: normal; " />12<wbr style="word-break: break-all; line-height: normal; "><br style="word-break: break-all; line-height: normal; " />13　long t2 = System.currentTimeMillis();<wbr style="word-break: break-all; line-height: normal; "><br style="word-break: break-all; line-height: normal; " />14　long size = fcin.size();<wbr style="word-break: break-all; line-height: normal; "><br style="word-break: break-all; line-height: normal; " />15　javax.swing.JOptionPane.showMessageDialog( null, size + " 字节, 耗时 " + ( t2 - t1 + 1 ) + " ms." );<wbr style="word-break: break-all; line-height: normal; "><br style="word-break: break-all; line-height: normal; " />...<br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " />----------------------------------------------------------------------------------------------------<wbr style="word-break: break-all; line-height: normal; "><br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " />SDK 文档里对 ByteBuffer 的说明为:<br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " />public abstract class ByteBuffer<br style="word-break: break-all; line-height: normal; " />extends Buffer<br style="word-break: break-all; line-height: normal; " />implements Comparable &lt;ByteBuffer&gt;<br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " />这说明 ByteBuffer 是继承于 Buffer 的抽象类, 实现了两个接口.<br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " />行3 通过 allocate() 分配了一块 1024 字节的缓冲区, 并返回一个 ByteBuffer 对象. (抽象类不能直接 new)<br style="word-break: break-all; line-height: normal; " />行6 fcin.read() 将数据读入到 buff. 此处的 read() 是 FileChannel 类的一个虚函数.<br style="word-break: break-all; line-height: normal; " />行8 buff.flip() 这个调用就是开头一直无法理解的部分.<br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " />----------------------------------------------------------------------------------------------------<wbr style="word-break: break-all; line-height: normal; "><br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " />SDK 文档里的对 flip() 的说明是:<br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " />public final Buffer flip()<br style="word-break: break-all; line-height: normal; " />反转<wbr style="word-break: break-all; line-height: normal; ">此缓冲区。首先对当前位置<wbr style="word-break: break-all; line-height: normal; ">设置限制<wbr style="word-break: break-all; line-height: normal; ">，然后将该位置设置为零。如果已定义了标记，则丢弃该标记。<br style="word-break: break-all; line-height: normal; " />当将数据从一个地方传输到另一个地方时，经常将此方法与 compact 方法一起使用。<br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " />我最终的理解是: 文档翻译得太差了, 把不应该翻译的内容也译成了中文, 所以反而不容易理解.<br style="word-break: break-all; line-height: normal; " />关键就在以下 2 处:<br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " />当前位置<wbr style="word-break: break-all; line-height: normal; ">: 这个可以直观地理解为缓冲区中的当前数据指针, 或是&nbsp;<a href="http://space.itpub.net/14734416/viewspace-434476" target="_self" style="word-break: break-all; text-decoration: underline; color: #000066; line-height: normal; "><u style="word-break: break-all; line-height: normal; "><strong style="word-break: break-all; line-height: normal; ">SQL</strong></u></a>&nbsp;中的游标, 记为 curPointer.<br style="word-break: break-all; line-height: normal; " />限制<wbr style="word-break: break-all; line-height: normal; ">: 这个可以理解成实际操作的缓冲区段的结束标记, 记为 endPointer.<br style="word-break: break-all; line-height: normal; " />反转<wbr style="word-break: break-all; line-height: normal; ">: 这个完全是对 flip 这个词不负责的翻译, 如果参照 DirectX 里的 flip() 而译为翻转/翻页, 那就好理解得多, 就像写信/看信, 写/看完一页后, 翻到下一页, 眼睛/笔从页底重新移回页首.<br style="word-break: break-all; line-height: normal; " />这个翻转背后的操作其实就是 "把 endPointer 定位到 curPointer 处, 并把 curPointer 设为 0".<br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " />关于标记, 在这里不涉及. 下一句说到常与 compact 方法一起使用, 是可以想像的, 因为 compact 方法对数据进<br style="word-break: break-all; line-height: normal; " />行了压缩, 有效数据的真实长度发生了变化, 肯定需要用 flip 重新定位结束标记.<br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " />在填充, 压缩等数据操作时, curPointer 估计都是自动更新了位置的, 总是指向最后一个有效数据, 所以每次调<br style="word-break: break-all; line-height: normal; " />用 flip() 后, endPointer 就指向了有效数据的结尾, 而 curPointer 指向了 0 (缓冲起始处).<br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " /><strong style="word-break: break-all; line-height: normal; "><wbr style="word-break: break-all; line-height: normal; ">举个图例:</strong><wbr style="word-break: break-all; line-height: normal; "><br style="word-break: break-all; line-height: normal; " />(c 和 e 分别代表 curPointer 和 endPointer 两个指针)<br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " />* 先是一个空的 ByteBuffer (大小为 10 字节)<br style="word-break: break-all; line-height: normal; " />-------------------<br style="word-break: break-all; line-height: normal; " />-------------------<br style="word-break: break-all; line-height: normal; " />c<br style="word-break: break-all; line-height: normal; " />e<br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " />* 然后填充 5 字节数据<br style="word-break: break-all; line-height: normal; " />-------------------<br style="word-break: break-all; line-height: normal; " />0 1 2 3 4<br style="word-break: break-all; line-height: normal; " />-------------------<br style="word-break: break-all; line-height: normal; " />e &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; c<br style="word-break: break-all; line-height: normal; " />此时, endPointer 尚在 0 处, curPointer 移到了数据结尾.<br style="word-break: break-all; line-height: normal; " />经测试, 此时若取数据, 将得到 5 个字节, 内容通常为 0 (也有可能是未知), 因为实际上取到的是从 c 处到缓冲</span><span class="Apple-style-span" style="line-height: 1.8em;">区实际结束处的 5 个未初始化的字节.</span><span class="Apple-style-span" style="line-height: 21px;"><br style="word-break: break-all; " /></span><br style="word-break: break-all; line-height: normal; " /><span class="Apple-style-span" style="line-height: 1.8em;">* 调用一次 flip() 后</span><br style="word-break: break-all; line-height: normal; " /><span class="Apple-style-span" style="line-height: 1.8em;">-------------------</span><br style="word-break: break-all; line-height: normal; " /><span class="Apple-style-span" style="line-height: 1.8em;">0 1 2 3 4</span><br style="word-break: break-all; line-height: normal; " /><span class="Apple-style-span" style="line-height: 1.8em;">-------------------</span><br style="word-break: break-all; line-height: normal; " /><span class="Apple-style-span" style="line-height: 1.8em;">c &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e</span><br style="word-break: break-all; line-height: normal; " /><span class="Apple-style-span" style="line-height: 1.8em;">此时, endPointer 先被移到 curPointer, 然后 curPointer 移到 0.</span><br style="word-break: break-all; line-height: normal; " /><span class="Apple-style-span" style="line-height: 1.8em;">通过测试可见, ByteBuffer 取数据时, 是从 curPointer 起, 到 endPointer 止, 若 curPointer &gt; endPointer, 则取到缓冲区结束.</span><br style="word-break: break-all; line-height: normal; " /><span class="Apple-style-span" style="line-height: 21px;"><br style="word-break: break-all; " /></span><br style="word-break: break-all; line-height: normal; " /><span class="Apple-style-span" style="line-height: 1.8em;">再看上面代码的关键片段, 行 8 处调用 flip() 即有两个作用, 一是将 curPointer 移到 0, 二是将 endPointer 移到有效数据结尾.</span><br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " /><span class="Apple-style-span" style="line-height: 1.8em;">此行可由以下两行代替:</span><br style="word-break: break-all; line-height: normal; " /><span class="Apple-style-span" style="line-height: 1.8em;">buff.limit( buff.position());</span><br style="word-break: break-all; line-height: normal; " /><span class="Apple-style-span" style="line-height: 1.8em;">buff.position( 0 );</span><br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " /><span class="Apple-style-span" style="line-height: 1.8em;">可见对其工作原理的理解, 应该是正确的.</span><br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " /><span class="Apple-style-span" style="line-height: 1.8em;">----------------------------</span><wbr style="word-break: break-all; line-height: normal; "><span class="Apple-style-span" style="line-height: 1.8em;">------------------------------------------------------------------------</span><wbr style="word-break: break-all; line-height: normal; "><br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " /><strong style="word-break: break-all; line-height: normal; "><wbr style="word-break: break-all; line-height: normal; ">总结如下:</strong><wbr style="word-break: break-all; line-height: normal; "><wbr style="word-break: break-all; line-height: normal; "><br style="word-break: break-all; line-height: normal; " /><span class="Apple-style-span" style="line-height: 1.8em;">1. put 数据时, 不会自动清除缓冲区中现有的数据.</span><br style="word-break: break-all; line-height: normal; " /><span class="Apple-style-span" style="line-height: 1.8em;">2. 每一次 get 或 put 后, curPointer 都将向缓冲区尾部移动, 移动量=操作的数据量.</span><br style="word-break: break-all; line-height: normal; " /><span class="Apple-style-span" style="line-height: 1.8em;">3. get/put 均是从 curPointer 起, 到 curPointer + 操作的数据长度止.</span><br style="word-break: break-all; line-height: normal; " /><span class="Apple-style-span" style="line-height: 1.8em;">4. get/put 操作中, 若 curPointer 超过了 endPointer 或缓冲区总长度, 将抛出 java.nio.BufferUnderflowException 异常.</span><br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " /><span class="Apple-style-span" style="line-height: 1.8em;">注: curPointer 和 endPointer 只是为文中方便描述命名的, 实际分别对应到 ByteBuffer.position() 和 ByteBuffer.limit() 两个方法.</span><br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " /><span class="Apple-style-span" style="line-height: 1.8em;">----------------------------------------------------------------------------------------------------</span><wbr style="word-break: break-all; line-height: normal; "><br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " /><strong style="word-break: break-all; line-height: normal; "><wbr style="word-break: break-all; line-height: normal; ">疑惑:</strong><wbr style="word-break: break-all; line-height: normal; "><wbr style="word-break: break-all; line-height: normal; "><br style="word-break: break-all; line-height: normal; " /><span class="Apple-style-span" style="line-height: 1.8em;">curPointer 是用 ByteBuffer.position() 取值, 用 ByteBuffer.position( int ) 赋值, 不知道 JDK 为什么要用多态来实现这两个功能, 按我的想法,&nbsp;</span><a href="http://space.itpub.net/14734416/viewspace-434476" target="_self" style="word-break: break-all; text-decoration: underline; color: #000066; line-height: normal; "><u style="word-break: break-all; line-height: normal; "><strong style="word-break: break-all; line-height: normal; ">设计</strong></u></a><span class="Apple-style-span" style="line-height: 1.8em;">成 getPosition(), setPosition() 不是要好看好记得多啊.</span><br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " /><span class="Apple-style-span" style="line-height: 1.8em;">----------------------------------------------------------------------------------------------------</span><wbr style="word-break: break-all; line-height: normal; "><br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " /><strong style="word-break: break-all; line-height: normal; "><wbr style="word-break: break-all; line-height: normal; ">跟 C++ 的简单比较:<wbr style="word-break: break-all; line-height: normal; "></strong><wbr style="word-break: break-all; line-height: normal; "><br style="word-break: break-all; line-height: normal; " /><span class="Apple-style-span" style="line-height: 1.8em;">C++ 里面没有类似 ByteBuffer 的现成实现, 实现上述类似的文件复制功能, 通常要自己创建</span><a href="http://space.itpub.net/14734416/viewspace-434476" target="_self" style="word-break: break-all; text-decoration: underline; color: #000066; line-height: normal; "><u style="word-break: break-all; line-height: normal; "><strong style="word-break: break-all; line-height: normal; ">管理</strong></u></a><span class="Apple-style-span" style="line-height: 1.8em;">缓冲区. C++ 里读写文件通常用 FileRead(), FileWrite() 函数, 在读/写的时候, 可以直接指定读/写的数据长度, 相比下显得</span><br style="word-break: break-all; line-height: normal; " /><span class="Apple-style-span" style="line-height: 1.8em;">直观方便些, 但 JDK 这个 ByteBuffer 的方式, 确实更方便好用.</span><br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " /><span class="Apple-style-span" style="line-height: 1.8em;">ByteBuffer 作为继承自 Buffer 的抽象类, 实现了对 Byte 型缓冲的管理, 同时 JDK 里还有对应其他数据类型的</span><br style="word-break: break-all; line-height: normal; " /><span class="Apple-style-span" style="line-height: 1.8em;">继承自 Buffer 的抽象类, 分别实现对应类型的缓冲管理. 这种设计减少了编程时的工作. 如果在 C++ 中, 调用</span><br style="word-break: break-all; line-height: normal; " /><span class="Apple-style-span" style="line-height: 1.8em;">读/写函数时, 还需要考虑传入数据的类型, 通常用传入 sizeof(数据类型) 的方式指定, 除了函数调用时增加耗</span><br style="word-break: break-all; line-height: normal; " /><span class="Apple-style-span" style="line-height: 1.8em;">费外, 灵活性也更差些.</span><br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " /><span class="Apple-style-span" style="line-height: 1.8em;">反过来再想, 为什么 C 要用这种方式? 个人认为, 这是 C 标准库的实现方式, 因为在不同 OS 平台上, 对文件和</span><br style="word-break: break-all; line-height: normal; " /><span class="Apple-style-span" style="line-height: 1.8em;">设备的访问方法在系统层不一定相同, 同时硬件平台(主要是 CPU)上基本数据类型宽度也有可能不同, 标准库通过</span><br style="word-break: break-all; line-height: normal; " /><span class="Apple-style-span" style="line-height: 1.8em;">sizeof 这个宏在编译时才能确定数据宽度, 所以标准 C 代码通常可以在不同平台上重新编译.</span><br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " /><span class="Apple-style-span" style="line-height: 1.8em;">再想 C++ 为什么要用这种方式? 首先, C++ 里沿用 C 标准库的模式是可以理解的, 其次, 也许只是 C++ 标准库</span><br style="word-break: break-all; line-height: normal; " /><span class="Apple-style-span" style="line-height: 1.8em;">里没有类似的设计, 说不定早就有第三方通过模板实现的了.</span><br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " /><span class="Apple-style-span" style="line-height: 1.8em;">个人认为, ByteBuffer 在实现上, 可以算是一种数据结构, 在类设计上, 可以算是一种设计模式了.</span></div></div><img src ="http://www.blogjava.net/AstroQi/aggbug/350457.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/AstroQi/" target="_blank">Astro.Qi</a> 2011-05-18 10:53 <a href="http://www.blogjava.net/AstroQi/archive/2011/05/18/350457.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>字符编码详解及由来(UNICODE,UTF-8,GBK)</title><link>http://www.blogjava.net/AstroQi/archive/2010/11/18/338412.html</link><dc:creator>Astro.Qi</dc:creator><author>Astro.Qi</author><pubDate>Thu, 18 Nov 2010 09:51:00 GMT</pubDate><guid>http://www.blogjava.net/AstroQi/archive/2010/11/18/338412.html</guid><wfw:comment>http://www.blogjava.net/AstroQi/comments/338412.html</wfw:comment><comments>http://www.blogjava.net/AstroQi/archive/2010/11/18/338412.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/AstroQi/comments/commentRss/338412.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/AstroQi/services/trackbacks/338412.html</trackback:ping><description><![CDATA[<p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; line-height: 19px; font-size: 13px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; ">一直对字符的各种编码方式懵懵懂懂，什么ANSI、UNICODE、UTF-8、GB2312、GBK、DBCS、UCS&#8230;&#8230;是不是看的很晕，假如您细细的阅读本文你一定可以清晰的理解他们。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp; 很久很久以前，有一群人，他们决定用8个可以开合的晶体管来组合成不同的状态，以表示世界上的万物。他们看到8个开关状态是好的，于是他们把这称为"字节"。</p>
<p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; line-height: 19px; font-size: 13px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; ">&nbsp;&nbsp;&nbsp; 再后来，他们又做了一些可以处理这些字节的机器，机器开动了，可以用字节来组合出很多状态，状态开始变来变去。他们看到这样是好的，于是它们就这机器称为"计算机"。<br />
&nbsp;&nbsp;&nbsp; 开始计算机只在美国用。八位的字节一共可以组合出256(2的8次方)种不同的状态。&nbsp;<br />
&nbsp;&nbsp;&nbsp; 他们把其中的编号从0开始的32种状态分别规定了特殊的用途，一但终端、打印机遇上约定好的这些字节被传过来时，就要做一些约定的动作。遇上00x10, 终端就换行，遇上0x07, 终端就向人们嘟嘟叫，例如遇上0x1b, 打印机就打印反白的字，或者终端就用彩色显示字母。他们看到这样很好，于是就把这些0x20以下的字节状态称为"控制码"。&nbsp;<br />
&nbsp;&nbsp;&nbsp; 他们又把所有的空格、标点符号、数字、大小写字母分别用连续的字节状态表示，一直编到了第127号，这样计算机就可以用不同字节来存储英语的文字了。大家 看到这样，都感觉很好，于是大家都把这个方案叫做 ANSI 的"Ascii"编码（American Standard Code for Information Interchange，美国信息互换标准代码）。当时世界上所有的计算机都用同样的ASCII方案来保存英文文字。&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp; 后来，就像建造巴比伦塔一样，世界各地的都开始使用计算机，但是很多国家用的不是英文，他们的字母里有许多是ASCII里没有的，为了可以在计算机保存他 们的文字，他们决定采用127号之后的空位来表示这些新的字母、符号，还加入了很多画表格时需要用下到的横线、竖线、交叉等形状，一直把序号编到了最后一 个状态255。从128到255这一页的字符集被称"扩展字符集"。从此之后，贪婪的人类再没有新的状态可以用了，美帝国主义可能没有想到还有第三世界国 家的人们也希望可以用到计算机吧！</p>
<p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; line-height: 19px; font-size: 13px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; ">&nbsp;&nbsp;&nbsp; 等中国人们得到计算机时，已经没有可以利用的字节状态来表示汉字，况且有6000多个常用汉字需要保存呢。但是这难不倒智慧的中国人民，我们不客气地把那些127号之后的奇异符号们直接取消掉,&nbsp;<br />
&nbsp;&nbsp;&nbsp; 规定：一个小于127的字符的意义与原来相同，但两个大于127的字符连在一起时，就表示一个汉字，前面的一个字节（他称之为高字节）从0xA1用到 0xF7，后面一个字节（低字节）从0xA1到0xFE，这样我们就可以组合出大约7000多个简体汉字了。在这些编码里，我们还把数学符号、罗马希腊的 字母、日文的假名们都编进去了，连在 ASCII 里本来就有的数字、标点、字母都统统重新编了两个字节长的编码，这就是常说的"全角"字符，而原来在127号以下的那些就叫"半角"字符了。&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 中国人民看到这样很不错，于是就把这种汉字方案叫做 "GB2312"。GB2312 是对 ASCII 的中文扩展。&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 但是中国的汉字太多了，我们很快就就发现有许多人的人名没有办法在这里打出来，特别是某些很会麻烦别人的国家领导人。于是我们不得不继续把 GB2312 没有用到的码位找出来老实不客气地用上。&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 后来还是不够用，于是干脆不再要求低字节一定是127号之后的内码，只要第一个字节是大于127就固定表示这是一个汉字的开始，不管后面跟的是不是扩展字 符集里的内容。结果扩展之后的编码方案被称为 GBK 标准，GBK 包括了 GB2312 的所有内容，同时又增加了近20000个新的汉字（包括繁体字）和符号。&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 后来少数民族也要用电脑了，于是我们再扩展，又加了几千个新的少数民族的字，GBK 扩成了GB18030。从此之后，中华民族的文化就可以在计算机时代中传承了。&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 中国的程序员们看到这一系列汉字编码的标准是好的，于是通称他们叫做 "DBCS"（Double Byte Charecter Set 双字节字符集）。在DBCS系列标准里，最大的特点是两字节长的汉字字符和一字节长的英文字符并存于同一套编码方案里，因此他们写的程序为了支持中文处 理，必须要注意字串里的每一个字节的值，如果这个值是大于127的，那么就认为一个双字节字符集里的字符出现了。那时候凡是受过加持，会编程的计算机僧侣 们都要每天念下面这个咒语数百遍：</p>
<p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; line-height: 19px; font-size: 13px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "一个汉字算两个英文字符！一个汉字算两个英文字符&#8230;&#8230;"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 因为当时各个国家都像中国这样搞出一套自己的编码标准，结果互相之间谁也不懂谁的编码，谁也不支持别人的编码，连大陆和台湾这样只相隔了150海里，使用 着同一种语言的兄弟地区，也分别采用了不同的 DBCS 编码方案——当时的中国人想让电脑显示汉字，就必须装上一个"汉字系统"，专门用来处理汉字的显示、输入的问题，但是那个台湾的愚昧封建人士写的算命程序 就必须加装另一套支持 BIG5&nbsp; 编码的什么"倚天汉字系统"才可以用，装错了字符系统，显示就会乱了套！这怎么办？而且世界民族之林中还有那些一时用不上电脑的穷苦人民，他们的文字又怎 么办？</p>
<p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; line-height: 19px; font-size: 13px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 真是计算机的巴比伦塔命题啊！&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 正在这时，大天使加百列及时出现了——一个叫 ISO（国际标谁化组织）的国际组织决定着手解决这个问题。他们采用的方法很简单：废了所有的地区性编码方案，重新搞一个包括了地球上所有文化、所有字母 和符号的编码！他们打算叫它"Universal Multiple-Octet Coded Character Set"，简称 UCS, 俗称 "UNICODE"。&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UNICODE 开始制订时，计算机的存储器容量极大地发展了，空间再也不成为问题了。于是 ISO 就直接规定必须用两个字节，也就是16位来统一表示所有的字符，对于ascii里的那些&#8220;半角&#8221;字符，UNICODE 包持其原编码不变，只是将其长度由原来的8位扩展为16位，而其他文化和语言的字符则全部重新统一编码。由于"半角"英文符号只需要用到低8位，所以其高 8位永远是0，因此这种大气的方案在保存英文文本时会多浪费一倍的空间。</p>
<p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; line-height: 19px; font-size: 13px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这时候，从旧社会里走过来的程序员开始发现一个奇怪的现象：他们的strlen函数靠不住了，一个汉字不再是相当于两个字符了，而是一个！是的，从 UNICODE 开始，无论是半角的英文字母，还是全角的汉字，它们都是统一的"一个字符"！同时，也都是统一的"两个字节"，请注意"字符"和"字节"两个术语的不 同，&#8220;字节&#8221;是一个8位的物理存贮单元，而&#8220;字符&#8221;则是一个文化相关的符号。在UNICODE 中，一个字符就是两个字节。一个汉字算两个英文字符的时代已经快过去了。&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 从前多种字符集存在时，那些做多语言软件的公司遇上过很大麻烦，他们为了在不同的国家销售同一套软件，就不得不在区域化软件时也加持那个双字节字符集咒 语，不仅要处处小心不要搞错，还要把软件中的文字在不同的字符集中转来转去。UNICODE 对于他们来说是一个很好的一揽子解决方案，于是从 Windows NT 开始，MS 趁机把它们的操作系统改了一遍，把所有的核心代码都改成了用 UNICODE 方式工作的版本，从这时开始，WINDOWS 系统终于无需要加装各种本土语言系统，就可以显示全世界上所有文化的字符了。&nbsp;<br />
&nbsp;&nbsp;&nbsp; 但是，UNICODE 在制订时没有考虑与任何一种现有的编码方案保持兼容，这使得 GBK 与UNICODE 在汉字的内码编排上完全是不一样的，没有一种简单的算术方法可以把文本内容从UNICODE编码和另一种编码进行转换，这种转换必须通过查表来进行。&nbsp;<br />
&nbsp;&nbsp;&nbsp; 如前所述，UNICODE 是用两个字节来表示为一个字符，他总共可以组合出65535不同的字符，这大概已经可以覆盖世界上所有文化的符号。如果还不够也没有关系，ISO已经准备 了UCS-4方案，说简单了就是四个字节来表示一个字符，这样我们就可以组合出21亿个不同的字符出来（最高位有其他用途），这大概可以用到银河联邦成立 那一天吧！<br />
&nbsp;&nbsp;&nbsp; UNICODE 来到时，一起到来的还有计算机网络的兴起，UNICODE 如何在网络上传输也是一个必须考虑的问题，于是面向传输的众多 UTF（UCS Transfer Format）标准出现了，顾名思义，UTF8就是每次8个位传输数据，而UTF16就是每次16个位，只不过为了传输时的可靠性，从UNICODE到 UTF时并不是直接的对应，而是要过一些算法和规则来转换。</p>
<p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; line-height: 19px; font-size: 13px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; ">&nbsp;&nbsp;&nbsp; 受到过网络编程加持的计算机僧侣们都知道，在网络里传递信息时有一个很重要的问题，就是对于数据高低位的解读方式，一些计算机是采用低位先发送的方法，例 如我们PC机采用的 INTEL 架构，而另一些是采用高位先发送的方式，在网络中交换数据时，为了核对双方对于高低位的认识是否是一致的，采用了一种很简便的方法，就是在文本流的开始时 向对方发送一个标志符——如果之后的文本是高位在位，那就发送"FEFF"，反之，则发送"FFFE"。不信你可以用二进制方式打开一个UTF-X格式的 文件，看看开头两个字节是不是这两个字节？<br />
&nbsp;&nbsp;&nbsp; 讲到这里，我们再顺便说说一个很著名的奇怪现象：当你在 windows 的记事本里新建一个文件，输入"联通"两个字之后，保存，关闭，然后再次打开，你会发现这两个字已经消失了，代之的是几个乱码！呵呵，有人说这就是联通之所以拼不过移动的原因。</p>
<p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; line-height: 19px; font-size: 13px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; ">&nbsp;&nbsp;&nbsp; 其实这是因为GB2312编码与UTF8编码产生了编码冲撞的原因。&nbsp;<br />
&nbsp;&nbsp;&nbsp; 从网上引来一段从UNICODE到UTF8的转换规则：<br />
&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Unicode &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;UTF-8<br />
&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; (0-127) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0000 - 007F &nbsp; &nbsp;&nbsp;0xxxxxxx</p>
<p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; line-height: 19px; font-size: 13px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; ">
&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; ">(128-2047) &nbsp; &nbsp;&nbsp;</span>0080 - 07FF &nbsp; &nbsp;&nbsp;110xxxxx 10xxxxxx&nbsp;</p>
<p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; line-height: 19px; font-size: 13px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; ">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; (2048-65535)<span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; ">&nbsp;&nbsp;</span>0800 - FFFF &nbsp; &nbsp;&nbsp;1110xxxx 10xxxxxx 10xxxxxx</p>
<p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; line-height: 19px; font-size: 13px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; ">
&nbsp;&nbsp;&nbsp; 例如"汉"字的Unicode编码是6C49。6C49在0800-FFFF之间，所以要用3字节模板：1110xxxx 10xxxxxx 10xxxxxx。将6C49写成二进制是：0110 1100 0100 1001，将这个比特流按三字节模板的分段方法分为0110 110001 001001，依次代替模板中的x，得到：1110-0110 10-110001 10-001001，即E6 B1 89，这就是其UTF8的编码。&nbsp;<br />
&nbsp;&nbsp;&nbsp; 而当你新建一个文本文件时，记事本的编码默认是ANSI,如果你在ANSI的编码输入汉字，那么他实际就是GB系列的编码方式，在这种编码下，"联通"的内码是：&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c1 1100 0001&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; aa 1010 1010&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cd 1100 1101&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a8 1010 1000&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp; 注意到了吗？第一二个字节、第三四个字节的起始部分的都是"110"和"10"，正好与UTF8规则里的两字节模板是一致的，于是再次打开记事本时，记事 本就误认为这是一个UTF8编码的文件，让我们把第一个字节的110和第二个字节的10去掉，我们就得到了"00001 101010"，再把各位对齐，补上前导的0，就得到了"0000 0000 0110 1010"，不好意思，这是UNICODE的006A，也就是小写的字母"j"，而之后的两字节用UTF8解码之后是0368，这个字符什么也不是。这就 是只有"联通"两个字的文件没有办法在记事本里正常显示的原因。</p>
<p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; line-height: 19px; font-size: 13px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; ">&nbsp;&nbsp;&nbsp; 而如果你在"联通"之后多输入几个字，其他的字的编码不见得又恰好是110和10开始的字节，这样再次打开时，记事本就不会坚持这是一个utf8编码的文件，而会用ANSI的方式解读之，这时乱码又不出现了。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp; 好了，终于可以回答NICO的问题了，在数据库里，有n前缀的字串类型就是UNICODE类型，这种类型中，固定用两个字节来表示一个字符，无论这个字符是汉字还是英文字母，或是别的什么。</p>
<p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; line-height: 19px; font-size: 13px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; ">&nbsp;&nbsp;&nbsp; 如果你要测试"abc汉字"这个串的长度，在没有n前缀的数据类型里，这个字串是7个字符的长度，因为一个汉字相当于两个字符。而在有n前缀的数据类型里，同样的测试串长度的函数将会告诉你是5个字符，因为一个汉字就是一个字符。</p>
<img src ="http://www.blogjava.net/AstroQi/aggbug/338412.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/AstroQi/" target="_blank">Astro.Qi</a> 2010-11-18 17:51 <a href="http://www.blogjava.net/AstroQi/archive/2010/11/18/338412.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SLF4J + logBack</title><link>http://www.blogjava.net/AstroQi/archive/2010/11/17/338255.html</link><dc:creator>Astro.Qi</dc:creator><author>Astro.Qi</author><pubDate>Wed, 17 Nov 2010 06:33:00 GMT</pubDate><guid>http://www.blogjava.net/AstroQi/archive/2010/11/17/338255.html</guid><wfw:comment>http://www.blogjava.net/AstroQi/comments/338255.html</wfw:comment><comments>http://www.blogjava.net/AstroQi/archive/2010/11/17/338255.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/AstroQi/comments/commentRss/338255.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/AstroQi/services/trackbacks/338255.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 一.	Log4j+commons-logging&nbsp;	JAR包&nbsp;commons-logging-1.1.jar&nbsp;log4j-1.2.15.jar&nbsp;	配置文件&nbsp;commons-logging.properties&nbsp;log4j.xml&nbsp;	commons-logging.jar包读取commons-lo...&nbsp;&nbsp;<a href='http://www.blogjava.net/AstroQi/archive/2010/11/17/338255.html'>阅读全文</a><img src ="http://www.blogjava.net/AstroQi/aggbug/338255.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/AstroQi/" target="_blank">Astro.Qi</a> 2010-11-17 14:33 <a href="http://www.blogjava.net/AstroQi/archive/2010/11/17/338255.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>byte[] to int</title><link>http://www.blogjava.net/AstroQi/archive/2010/11/12/337898.html</link><dc:creator>Astro.Qi</dc:creator><author>Astro.Qi</author><pubDate>Fri, 12 Nov 2010 04:09:00 GMT</pubDate><guid>http://www.blogjava.net/AstroQi/archive/2010/11/12/337898.html</guid><wfw:comment>http://www.blogjava.net/AstroQi/comments/337898.html</wfw:comment><comments>http://www.blogjava.net/AstroQi/archive/2010/11/12/337898.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/AstroQi/comments/commentRss/337898.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/AstroQi/services/trackbacks/337898.html</trackback:ping><description><![CDATA[<div>
<div>public class NumberBytesUtils {</div>
<div><br />
</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>public static void main(String[] args) {</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>byte[] bytes = new byte[4];</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>bytes[0] = (byte) 65;</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>bytes[1] = (byte) 0;</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>bytes[2] = (byte) 97;</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>bytes[3] = (byte) 0;</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span></div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>System.out.println("String: " + new String(bytes));</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span></div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>int iv = bytesToInt(bytes);</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>float fv = bytesToFloat(bytes);</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>byte[] bs = intToBytes(iv);</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>byte[] fs = floatToBytes(fv);</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span></div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>System.out.println("Int: " + iv);</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>System.out.println("Float: " + fv);</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>System.out.println("------------");</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span></div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>for (int i = 0; i &lt; bs.length; i++) {</div>
<div><span class="Apple-tab-span" style="white-space:pre">			</span>System.out.println(bs[i]);</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>}</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>System.out.println("============");</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>for (int i = 0; i &lt; fs.length; i++) {</div>
<div><span class="Apple-tab-span" style="white-space:pre">			</span>System.out.println(fs[i]);</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>}</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>System.out.println("============");</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>System.out.println(bytesToFloat(floatToBytes(-0.45367f)));</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>System.out.println("************");</div>
<div>//<span class="Apple-tab-span" style="white-space:pre">		</span>System.out.println(0xff);</div>
<div>//<span class="Apple-tab-span" style="white-space:pre">		</span>System.out.println(0xff00);</div>
<div>//<span class="Apple-tab-span" style="white-space:pre">		</span>System.out.println(0xff0000);</div>
<div>//<span class="Apple-tab-span" style="white-space:pre">		</span>System.out.println(0xff000000);</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span></div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>byte[] bytesL = new byte[8];</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>System.arraycopy(bytes, 0, bytesL, 0, bytes.length);</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>bytesL[4] = (byte) 0;</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>bytesL[5] = (byte) 0;</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>bytesL[6] = (byte) 0;</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>bytesL[7] = (byte) 0;</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span></div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>long lv = bytesToLong(bytesL);</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>double dv = bytesToDouble(bytesL);</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>byte[] bls = longToBytes(lv);</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>byte[] dls = doubleToBytes(dv);</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>System.out.println("Long: " + lv);</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>System.out.println("Double: " + dv);</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>System.out.println("----");</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>for (int i = 0; i &lt; bls.length; i++) {</div>
<div><span class="Apple-tab-span" style="white-space:pre">			</span>System.out.println(bls[i]);</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>}</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>System.out.println("----");</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>for (int i = 0; i &lt; dls.length; i++) {</div>
<div><span class="Apple-tab-span" style="white-space:pre">			</span>System.out.println(dls[i]);</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>}</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>System.out.println("****");</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>System.out.println(bytesToDouble(doubleToBytes(2.345)));</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span></div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>}</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span></div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>/**</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span> * bytes[3] = value &gt;&gt; 24</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span> * bytes[2] = value &gt;&gt; 16</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span> * bytes[1] = value &gt;&gt; &nbsp;8</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span> * bytes[0] = value &gt;&gt; &nbsp;0</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span> * @param value</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span> * @return</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span> */</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>public static byte[] intToBytes(int value){</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>int length = 4;</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>byte[] bytes = new byte[length];</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>for (int i = length - 1; i &gt;= 0; i--) {</div>
<div><span class="Apple-tab-span" style="white-space:pre">			</span>int offset = i * 8; // 24, 16, 8</div>
<div><span class="Apple-tab-span" style="white-space:pre">			</span>bytes[i] = (byte) (value &gt;&gt; offset);</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>}</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>return bytes;</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>}</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span></div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>/**</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span> * bytes[7] = value &gt;&gt; 56</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span> * bytes[6] = value &gt;&gt; 48</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span> * bytes[5] = value &gt;&gt; 40</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span> * bytes[4] = value &gt;&gt; 32</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span> * bytes[3] = value &gt;&gt; 24</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span> * bytes[2] = value &gt;&gt; 16</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span> * bytes[1] = value &gt;&gt; &nbsp;8</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span> * bytes[0] = value &gt;&gt; &nbsp;0</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span> * @param value</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span> * @return</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span> */</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>public static byte[] longToBytes(long value){</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>int length = 8;</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>byte[] bytes = new byte[length];</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>for (int i = length - 1; i &gt;= 0; i--) {</div>
<div><span class="Apple-tab-span" style="white-space:pre">			</span>int offset = i * 8; //56, 48, 40, 32, 24, 16, 8</div>
<div><span class="Apple-tab-span" style="white-space:pre">			</span>bytes[i] = (byte) (value &gt;&gt; offset);</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>}</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>return bytes;</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>}</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span></div>
<div><br />
</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>/**</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span> * 操作符 &lt;&lt; 的优先级比 &amp; 高</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span> * intValue = (bytes[3] &amp; 0xFF) &lt;&lt; 24</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span> &nbsp; &nbsp; &nbsp; &nbsp;| (bytes[2] &amp; 0xFF) &lt;&lt; 16</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span> &nbsp; &nbsp; &nbsp; &nbsp;| (bytes[1] &amp; 0xFF) &lt;&lt; &nbsp;8</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span> &nbsp; &nbsp; &nbsp; &nbsp;| (bytes[0] &amp; 0xFF) &lt;&lt; &nbsp;0</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span> * @param bytes</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span> * @return</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span> */</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>public static int bytesToInt (byte[] bytes){</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>int length = 4;</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>int intValue = 0;</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;for (int i = length - 1; i &gt;= 0; i--) {</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;<span class="Apple-tab-span" style="white-space:pre">	</span>int offset = i * 8; //24, 16, 8</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;<span class="Apple-tab-span" style="white-space:pre">	</span>intValue |= (bytes[i] &amp; 0xFF) &lt;&lt; offset;</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; return intValue;</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>}</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span></div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>/**</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span> * 操作符 &lt;&lt; 的优先级比 &amp; 高</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span> * longValue = (long)(bytes[7] &amp; 0xFF) &lt;&lt; 56</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span> &nbsp; &nbsp; &nbsp; &nbsp; | (long)(bytes[6] &amp; 0xFF) &lt;&lt; 48</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span> &nbsp; &nbsp; &nbsp; &nbsp; | (long)(bytes[5] &amp; 0xFF) &lt;&lt; 40</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span> &nbsp; &nbsp; &nbsp; &nbsp; | (long)(bytes[4] &amp; 0xFF) &lt;&lt; 32</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span> &nbsp; &nbsp; &nbsp; &nbsp; | (long)(bytes[3] &amp; 0xFF) &lt;&lt; 24</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span> &nbsp; &nbsp; &nbsp; &nbsp; | (long)(bytes[2] &amp; 0xFF) &lt;&lt; 16</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span> &nbsp; &nbsp; &nbsp; &nbsp; | (long)(bytes[1] &amp; 0xFF) &lt;&lt; &nbsp;8</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span> &nbsp; &nbsp; &nbsp; &nbsp; | (long)(bytes[0] &amp; 0xFF) &lt;&lt; &nbsp;0</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span> * @param bytes</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span> * @return</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span> */</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>public static long bytesToLong (byte[] bytes){</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>int length = 8;</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>long longValue = 0;</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;for (int i = length - 1; i &gt;= 0; i--) {</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;<span class="Apple-tab-span" style="white-space:pre">	</span>int offset = i * 8; //56, 48, 40, 32, 24, 16, 8</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;<span class="Apple-tab-span" style="white-space:pre">	</span>longValue |= (long)(bytes[i] &amp; 0xFF) &lt;&lt; offset; //一定要先强制转换成long型再移位, 因为0xFF为int型</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; return longValue;</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>}</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span></div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>public static float bytesToFloat(byte[] bytes) {</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>return Float.intBitsToFloat(bytesToInt(bytes));</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>}</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span></div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>public static double bytesToDouble(byte[] bytes) {</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>return Double.longBitsToDouble(bytesToLong(bytes));</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>}</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span></div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>public static byte[] floatToBytes(float value){</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>return intToBytes(Float.floatToIntBits(value));</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>}</div>
<div><br />
</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>public static byte[] doubleToBytes(double value){</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>return longToBytes(Double.doubleToLongBits(value));</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>}</div>
<div>}</div>
<div>====================================================================================</div>
</div>
<div>/**</div>
<div>
<div>public static String bytes2HexString(byte[] b) {&nbsp;</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>String ret = "";&nbsp;</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>for (int i = 0; i &lt; b.length; i++) {&nbsp;</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>String hex = Integer.toHexString(b[ i ] 0xFF);&nbsp;</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>if (hex.length() == 1) {</div>
<div>&nbsp;<span class="Apple-tab-span" style="white-space:pre">			</span>hex = '0' + hex;&nbsp;</div>
<div>&nbsp;<span class="Apple-tab-span" style="white-space:pre">		</span>}&nbsp;</div>
<div>&nbsp;<span class="Apple-tab-span" style="white-space:pre">		</span>ret += hex.toUpperCase();&nbsp;</div>
<div>&nbsp;<span class="Apple-tab-span" style="white-space:pre">	</span>}&nbsp;</div>
<div>&nbsp;<span class="Apple-tab-span" style="white-space:pre">	</span>return ret;&nbsp;</div>
<div>}&nbsp;</div>
<div>&nbsp;</div>
<div>&nbsp;上面是将byte[]转化十六进制的字符串,注意这里b[ i ] &amp; 0xFF将一个byte和 0xFF进行了与运算,</div>
<div>&nbsp;然后使用Integer.toHexString取得了十六进制字符串,可以看出 b[ i ] &amp; 0xFF运算后得出的仍然</div>
<div>&nbsp;是个int,那么为何要和 0xFF进行与运算呢?</div>
<div>&nbsp;直接 Integer.toHexString(b[ i ]);,将byte强转为int不行吗?答案是不行的.&nbsp;</div>
<div>&nbsp;其原因在于:&nbsp;</div>
<div>&nbsp;1.byte的大小为8bits而int的大小为32bits&nbsp;</div>
<div>&nbsp;2.java的二进制采用的是补码形式&nbsp;</div>
<div>&nbsp;</div>
<div>&nbsp;在这里先温习下计算机基础理论 byte是一个字节保存的，有8个位，即8个0、1。&nbsp;</div>
<div>&nbsp;8位的第一个位是符号位， 也就是说</div>
<div>&nbsp;0000 0001代表的是数字1&nbsp;</div>
<div>&nbsp;1000 0000代表的就是-1&nbsp;</div>
<div>&nbsp;所以</div>
<div>&nbsp;正数最大为0111 1111，也就是数字127&nbsp;</div>
<div>&nbsp;负数最大为1111 1111，也就是数字-128&nbsp;</div>
<div>&nbsp;上面说的是二进制原码，</div>
<div>&nbsp;但是在java中采用的是补码的形式，而不是原码，</div>
<div>&nbsp;</div>
<div>&nbsp;下面介绍下什么是补码&nbsp;</div>
<div>&nbsp;1、反码：一个数如果是正，则它的反码与原码相同； 一个数如果是负，则符号位为1，其余各位是对原码取反；&nbsp;</div>
<div>&nbsp;2、补码：利用溢出，我们可以将减法变成加法，</div>
<div>&nbsp;<span class="Apple-tab-span" style="white-space:pre">		</span>对于十进制数，从9得到5可用减法： 9－4＝5。</div>
<div>&nbsp;<span class="Apple-tab-span" style="white-space:pre">			</span>因为4+6＝10，我们可以将6作为4的补数，改写为加法： 9+6＝15（去掉高位1，也就是减10）得到5.&nbsp;</div>
<div>&nbsp;<span class="Apple-tab-span" style="white-space:pre">		</span>对于十六进制数，从c到5可用减法： c－7＝5。</div>
<div>&nbsp;<span class="Apple-tab-span" style="white-space:pre">			</span>因为7+9＝16 将9作为7的补数，改写为加法： c+9＝15（去掉高位1，也就是减16）得到5.&nbsp;</div>
<div>&nbsp;<span class="Apple-tab-span" style="white-space:pre">			</span></div>
<div>&nbsp;在计算机中，如果我们用1个字节表示一个数，一个字节有8位，超过8位就进1，在内存中情况为（1 0000 0000），进位1被丢弃。</div>
<div>&nbsp;所以补码是这样运算的：</div>
<div>&nbsp;&nbsp;⑴一个数为正，则它的原码、反码、补码相同</div>
<div>&nbsp;&nbsp;⑵一个数为负，高符号位为1，其余各位是对原码取反，然后整个数加1，(符号位不变，其余为取反再加1)</div>
<div>&nbsp;&nbsp;-1的原码为 10000001&nbsp;</div>
<div>&nbsp;&nbsp;-1的反码为 11111110 再 + 1&nbsp;</div>
<div>&nbsp;&nbsp;-1的补码为 11111111&nbsp;</div>
<div>&nbsp;&nbsp;</div>
<div>&nbsp;&nbsp;0的原码为 &nbsp;00000000&nbsp;</div>
<div>&nbsp;&nbsp;0的反码为 &nbsp;11111111 (正零和负零的反码相同) 再 + 1</div>
<div>&nbsp;&nbsp;0的补码为 100000000（舍掉打头的1，正零和负零的补码相同）&nbsp;</div>
<div>&nbsp;&nbsp;</div>
<div>&nbsp;&nbsp;Integer.toHexString的参数是int，如果不进行&amp;0xff，那么当一个byte转换成int时，</div>
<div>&nbsp;&nbsp;由于int是32位，而byte只有8位，这时会进行补位，补位补的是1</div>
<div>&nbsp;&nbsp;例如：补码11111111的十进制数为-1，转换为int时变为11111111 11111111 11111111 11111111</div>
<div>&nbsp;&nbsp;好多1啊，呵呵！即 0xff ff ff ff&nbsp;，但是这个数是不对的，</div>
<div>&nbsp;&nbsp;这种补位就会造成误差。和0xff相与后，高24bits就会被清0了，结果就对了。(任是补码11111111)</div>
</div>
<div>*/</div>
<img src ="http://www.blogjava.net/AstroQi/aggbug/337898.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/AstroQi/" target="_blank">Astro.Qi</a> 2010-11-12 12:09 <a href="http://www.blogjava.net/AstroQi/archive/2010/11/12/337898.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java 中 byte与char、String互转原理</title><link>http://www.blogjava.net/AstroQi/archive/2010/11/12/337897.html</link><dc:creator>Astro.Qi</dc:creator><author>Astro.Qi</author><pubDate>Fri, 12 Nov 2010 04:08:00 GMT</pubDate><guid>http://www.blogjava.net/AstroQi/archive/2010/11/12/337897.html</guid><wfw:comment>http://www.blogjava.net/AstroQi/comments/337897.html</wfw:comment><comments>http://www.blogjava.net/AstroQi/archive/2010/11/12/337897.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/AstroQi/comments/commentRss/337897.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/AstroQi/services/trackbacks/337897.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 一、字节和unicode&nbsp;Java内核是unicode的，就连class文件也是，但是很多媒体，包括文件/流的保存方式是使用字节流的。因此Java要对这些字节流经行转化。 char是unicode的，而byte是字节。Java中&nbsp;byte/char互转的函数在sun.io的包中间有。其中ByteToCharConverter类是中调度，可以用来告诉你，你用的 conve...&nbsp;&nbsp;<a href='http://www.blogjava.net/AstroQi/archive/2010/11/12/337897.html'>阅读全文</a><img src ="http://www.blogjava.net/AstroQi/aggbug/337897.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/AstroQi/" target="_blank">Astro.Qi</a> 2010-11-12 12:08 <a href="http://www.blogjava.net/AstroQi/archive/2010/11/12/337897.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java Stack栈和Heap堆的区别</title><link>http://www.blogjava.net/AstroQi/archive/2009/01/20/252025.html</link><dc:creator>Astro.Qi</dc:creator><author>Astro.Qi</author><pubDate>Tue, 20 Jan 2009 03:59:00 GMT</pubDate><guid>http://www.blogjava.net/AstroQi/archive/2009/01/20/252025.html</guid><wfw:comment>http://www.blogjava.net/AstroQi/comments/252025.html</wfw:comment><comments>http://www.blogjava.net/AstroQi/archive/2009/01/20/252025.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/AstroQi/comments/commentRss/252025.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/AstroQi/services/trackbacks/252025.html</trackback:ping><description><![CDATA[&nbsp;在中文里，Stack可以翻译为&#8220;堆栈&#8221;，计算机术语里面堆和栈开头的词语有：
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>堆存储： heapstorage&nbsp;&nbsp;&nbsp; 堆存储分配： heapstorage allocation&nbsp; 堆存储管理： heap storage management</strong></div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong> 栈编址： stack addressing&nbsp; &nbsp;栈变换：stack transformation&nbsp; 栈存储器：stack memory&nbsp; 栈单元： stack cell</strong> </div>
<div>&nbsp;</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;接着，总结在Java里面Heap和Stack分别存储数据的不同。</div>
<div>&nbsp;</div>
<div>
<table style="width: 482px; height: 100px;" border="1" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </td>
            <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Heap(堆)</td>
            <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Stack(栈)</td>
        </tr>
        <tr>
            <td>&nbsp;JVM中的功能</td>
            <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;内存数据区&nbsp;&nbsp;&nbsp;&nbsp; </td>
            <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 内存指令区</td>
        </tr>
        <tr>
            <td>&nbsp;存储数据</td>
            <td>&nbsp;&nbsp;&nbsp;&nbsp; 对象实例(1)</td>
            <td>&nbsp;基本数据类型, 指令代码,常量,对象的引用地址(2)</td>
        </tr>
    </tbody>
</table>
</div>
<div>1. 保存对象实例，实际上是保存对象实例的属性值，属性的类型和对象本身的类型标记等，并不保存对象的方法（方法是指令，保存在stack中）。<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; 对象实例在heap中分配好以后，需要在stack中保存一个4字节的heap内存地址，用来定位该对象实例在heap中的位置，便于找到该对象实例。</div>
<div>&nbsp;</div>
<div>2. 基本数据类型包括byte、int、char、long、float、double、boolean和short。<br />
&nbsp;&nbsp;&nbsp; 函数方法属于指令.</div>
<div>&nbsp;</div>
<div>&nbsp;=======================&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div>
<div>&nbsp; 引用网上广泛流传的&#8220;Java堆和栈的区别&#8221;里面对堆和栈的介绍；</div>
<div><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "Java
的堆是一个运行时数据区,类的(对象从中分配空间。这些对象通过new、newarray、anewarray和multianewarray等指令建
立，它们不需要程序代码来显式的释放。堆是由垃圾回收来负责的，堆的优势是可以动态地分配内存大小，生存期也不必事先告诉编译器，因为它是在运行时动态分
配内存的，Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是，由于要在运行时动态分配内存，存取速度较慢。"</strong></div>
<div><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&#8220;栈的优势是，存取速度比堆要快，仅次于寄存器，栈数据可以共享。但缺点是，存在栈中的数据大小与生存期必须是确定的，缺乏灵活性。栈中主要存放一些基本
类型的变量（,int, short, long, byte, float, double, boolean, char）和对象句柄。</strong> <strong>&#8221;</strong></div>
<div><strong>&nbsp;&nbsp;&nbsp; </strong></div>
<div><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;</strong>可见，垃圾回收GC是针对堆Heap的，而栈因为本身是FILO - first in, last out. 先进后出，能够自动释放。 这样就能明白到new创建的，都是放到堆Heap！</div>
<img src ="http://www.blogjava.net/AstroQi/aggbug/252025.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/AstroQi/" target="_blank">Astro.Qi</a> 2009-01-20 11:59 <a href="http://www.blogjava.net/AstroQi/archive/2009/01/20/252025.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Apache James 收发内外网邮件的配置</title><link>http://www.blogjava.net/AstroQi/archive/2008/08/25/224181.html</link><dc:creator>Astro.Qi</dc:creator><author>Astro.Qi</author><pubDate>Mon, 25 Aug 2008 07:35:00 GMT</pubDate><guid>http://www.blogjava.net/AstroQi/archive/2008/08/25/224181.html</guid><wfw:comment>http://www.blogjava.net/AstroQi/comments/224181.html</wfw:comment><comments>http://www.blogjava.net/AstroQi/archive/2008/08/25/224181.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/AstroQi/comments/commentRss/224181.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/AstroQi/services/trackbacks/224181.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 说明：1.James2.3.1部署的这台机器的域名是xizangmilin.gov.cn 对应的外网IP是202.98.244.10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.dns是202.98.224.69&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.hosts文件中的IP映射是202.98.244.10&nbsp; xizangmilin.g...&nbsp;&nbsp;<a href='http://www.blogjava.net/AstroQi/archive/2008/08/25/224181.html'>阅读全文</a><img src ="http://www.blogjava.net/AstroQi/aggbug/224181.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/AstroQi/" target="_blank">Astro.Qi</a> 2008-08-25 15:35 <a href="http://www.blogjava.net/AstroQi/archive/2008/08/25/224181.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Web Services Xfire</title><link>http://www.blogjava.net/AstroQi/archive/2008/07/18/215717.html</link><dc:creator>Astro.Qi</dc:creator><author>Astro.Qi</author><pubDate>Fri, 18 Jul 2008 03:45:00 GMT</pubDate><guid>http://www.blogjava.net/AstroQi/archive/2008/07/18/215717.html</guid><wfw:comment>http://www.blogjava.net/AstroQi/comments/215717.html</wfw:comment><comments>http://www.blogjava.net/AstroQi/archive/2008/07/18/215717.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/AstroQi/comments/commentRss/215717.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/AstroQi/services/trackbacks/215717.html</trackback:ping><description><![CDATA[<table id="content-table" width="100%" border="0" cellpadding="0" cellspacing="0">
    <tbody>
        <tr valign="top">
            <td width="100%">
            <table width="100%" border="0" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr valign="top">
                        <td width="100%">
                        <h1>Web Services ---- XFire</h1>
                        <p id="subtitle"><em>轻松将 POJO 发布成 Web 服务</em></p>
                        <img class="display-img" alt="" src="//www.ibm.com/i/c.gif" width="1" height="6" /></td>
                        <td class="no-print" width="192"><img alt="developerWorks" src="/developerworks/i/dw.gif" width="192" height="18" /></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<table width="100%" border="0" cellpadding="0" cellspacing="0">
    <tbody>
        <tr valign="top">
            <td width="10"><img alt="" src="//www.ibm.com/i/c.gif" width="10" height="1" /></td>
            <td width="100%">
            <table class="no-print" width="160" align="right" border="0" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr>
                        <td width="10"><img alt="" src="//www.ibm.com/i/c.gif" width="10" height="1" /></td>
                        <td>
                        <table width="150" border="0" cellpadding="0" cellspacing="0">
                            <tbody>
                                <tr>
                                    <td class="v14-header-1-small">文档选项</td>
                                </tr>
                            </tbody>
                        </table>
                        <table class="v14-gray-table-border" border="0" cellpadding="0" cellspacing="0">
                            <tbody>
                                <tr>
                                    <td class="no-padding" width="150">
                                    <table width="143" border="0" cellpadding="0" cellspacing="0">
                                        <img alt="" src="//www.ibm.com/i/c.gif" width="8" height="1" />
                                        <form name="email" action="https://www.ibm.com/developerworks/secure/email-it.jsp" cm1="1">
                                            <input value="Java 社区一直试图将 POJO 的作用发挥到极致，降低 Java 应用实现的难度，最近的尝试是将 EJB3.0 建立在 POJO 之上；另一方面，SOA 是目前 Java 社区炙手可热的名词，非常多的企业都在努力应用和实施 SOA；XFire 为这两方面的需求提供了一种魔术般的解决方式，我们很快能够发现使用 XFire 创建和发布 Web 服务可以直接基于 POJO，将烦人的继承关系和一大堆其他可能的约束丢在一边。" name="body" cm1="1" cm2="0" cm3="" type="hidden" /><input value="XFire 入门" name="subject" cm1="1" cm2="1" cm3="" type="hidden" /><input value="cn" name="lang" cm1="1" cm2="2" cm3="" type="hidden" />
                                            <script language="JavaScript" type="text/javascript">
                                            <!-- document.write('
                                            <tr valign="top">
                                                <td width="8"><img src="//www.ibm.com/i/c.gif" width="8" height="1" alt="" /></td>
                                                <td width="16"><img src="//www.ibm.com/i/v14/icons/em.gif" height="16" width="16" vspace="3" alt="将此页作为电子邮件发送"  /></td>
                                                <td width="122">
                                                <p><a class="smallplainlink" href="javascript:document.email.submit();"><strong>将此页作为电子邮件发送</strong></a></p>
                                                </td>
                                            </tr>
                                            ');
                                            //-->
                                            </script>
                                            <tbody>
                                                <tr valign="top">
                                                    <td width="8"><img alt="" src="//www.ibm.com/i/c.gif" width="8" height="1" /></td>
                                                    <td width="16"><img alt="将此页作为电子邮件发送" src="//www.ibm.com/i/v14/icons/em.gif" vspace="3" width="16" height="16" /></td>
                                                    <td width="122">
                                                    <p><a class="smallplainlink" href="javascript:document.email.submit();" cmimpressionsent="1"><strong>将此页作为电子邮件发送</strong></a></p>
                                                    </td>
                                                </tr>
                                                <noscript>
                                                <tr valign="top">
                                                    <td width="8"><img alt="" height="1" width="8" src="//www.ibm.com/i/c.gif" /></td>
                                                    <td width="16"><img alt="" width="16" height="16" src="//www.ibm.com/i/c.gif" /></td>
                                                    <td class="small" width="122">
                                                    <p><span class="ast">未显示需要 JavaScript 的文档选项</span></p>
                                                    </td>
                                                </tr>
                                                </noscript>
                                            </tbody>
                                            <tr valign="top">
                                                <td width="8"><img alt="" src="//www.ibm.com/i/c.gif" width="8" height="1" /></td>
                                                <td width="16"><img alt="" src="//www.ibm.com/i/v14/icons/dn.gif" vspace="3" width="16" border="0" height="16" /></td>
                                                <td width="122">
                                                <p><a class="smallplainlink" href="#download" cmimpressionsent="1"><strong>样例代码</strong></a></p>
                                                </td>
                                            </tr>
                                        </form>
                                    </table>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                        <!--start RESERVED FOR FUTURE USE INCLUDE FILES--><!-- this content will be automatically generated across all content areas --><!--end RESERVED FOR FUTURE USE INCLUDE FILES--><br />
                        </td>
                    </tr>
                </tbody>
            </table>
            <p>2007 年 5 月 16 日</p>
            <blockquote>Java 社区一直试图将 POJO 的作用发挥到极致，降低 Java 应用实现的难度，最近的尝试是将 EJB3.0 建立在 POJO
            之上；另一方面，SOA 是目前 Java 社区炙手可热的名词，非常多的企业都在努力应用和实施 SOA；XFire
            为这两方面的需求提供了一种魔术般的解决方式，我们很快能够发现使用 XFire 创建和发布 Web 服务可以直接基于
            POJO，将烦人的继承关系和一大堆其他可能的约束丢在一边。</blockquote><!--start RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --><!--end RESERVED FOR FUTURE USE INCLUDE FILES-->
            <p><a name="N10057"><span class="atitle">POJO、SOA 概述</span></a></p>
            <p><a name="N1005D"><span class="smalltitle">被重新审视的 POJO</span></a></p>
            <p>POJO（Plain Old Java Object，简单 Java 对象）是 Java 社区中最早的成员（回想您学习 Java
            时第一个兴奋的时刻，那个简单的 "Hello World！" 例子），也是最简单、最容易实现的方式。</p>
            <p>然而现实中 Java 的发展已经远远超越了 POJO 的范围，成为面向对象技术应用中最成功的编程语言，尤其是继承、多态的应用为我们造就了一大批开发框架（如
            Struts）和标准（如 EJB），随之而来的就是实现的复杂化，我们必须面对一大堆继承关系的限制。比如说：要开发一个基于 Struts 的应用，我们必须了解
            Struts 特定的继承关系如 ActionForm、ValidateActionForm；要开发一个 EJB 应用，我们必须继承
            EJBObject、SessionEJB 等。</p>
            <p>为了抛开这些限制，降低 Java 应用实现的难度，Java 社区开始重新审视 POJO 的价值，试图将 POJO 的作用发挥到极致，最新的努力是
            EJB3.0。Java 社区将 EJB3.0 设计为基于 POJO，而不是为他准备更多的继承关系等限制。</p>
            <p><a name="N1006B"><span class="smalltitle">让人爱恨交加的 SOA</span></a></p>
            <p>SOA 已经成为了目前 Java
            社区中炙手可热的名词，几乎所有的软件厂商都在讨论它，为他提供解决方案和产品支持，大部分的企业也已经在企业内部实施或者正在考虑实施 SOA。</p>
            <p>然而 SOA 在企业内的实施却不是一项简单的任务，即使抛开新建系统直接基于 SOA 架构实施的因素，要把企业已有系统纳入 SOA
            框架也不是一件容易的事情。企业必须在对当前架构深入了解的基础上，对已有系统进行大规模的改造才能满足新的要求。如何经济的从原有技术架构切换到 SOA
            架构成为很多企业的难题。</p>
            <br />
            <table width="100%" border="0" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr>
                        <td><img alt="" src="//www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" height="1" /><br />
                        <img alt="" src="//www.ibm.com/i/c.gif" width="8" border="0" height="6" /></td>
                    </tr>
                </tbody>
            </table>
            <table class="no-print" align="right" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr align="right">
                        <td><img alt="" src="//www.ibm.com/i/c.gif" width="100%" height="4" /><br />
                        <table border="0" cellpadding="0" cellspacing="0">
                            <tbody>
                                <tr>
                                    <td valign="middle"><img alt="" src="//www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" height="16" /><br />
                                    </td>
                                    <td valign="top" align="right"><a class="fbox" href="#main" cmimpressionsent="1"><strong>回页首</strong></a></td>
                                </tr>
                            </tbody>
                        </table>
                        </td>
                    </tr>
                </tbody>
            </table>
            <br />
            <br />
            <p><a name="N10076"><span class="atitle">XFire 概述</span></a></p>
            <p>XFire 是 codeHaus 组织提供的一个开源框架，它构建了 POJO 和 SOA 之间的桥梁，主要特性就是支持将 POJO
            通过非常简单的方式发布成 Web 服务，这种处理方式不仅充分发挥了 POJO 的作用，简化了 Java 应用转化为 Web 服务的步骤和过程，也直接降低了
            SOA 的实现难度，为企业转向 SOA 架构提供了一种简单可行的方式。</p>
            <p>XFire 目前最新的版本是 1.2.2，目前支持的特性主要包括：</p>
            <ul>
                <li>支持将 Web 服务绑定到 POJO、XMLBeans、JAXB1.1、JAXB2.0 和 Castor；
                </li>
                <li>支持基于 HTTP、JMS、XMPP 等多种协议访问 Web 服务；
                </li>
                <li>支持多种 Web 服务业界重要标准如 SOAP、WSDL、Web 服务寻址（WS-Addressing）、Web 服务安全（WS-Security）等；
                </li>
                <li>支持 JSR181，可以通过 JDK5 配置 Web 服务；
                </li>
                <li>高性能的 SOAP 实现；
                </li>
                <li>服务器端、客户端代码辅助生成；
                </li>
                <li>对 Spring、Pico、Plexus 等项目的支持等。 </li>
            </ul>
            <br />
            <table width="100%" border="0" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr>
                        <td><img alt="" src="//www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" height="1" /><br />
                        <img alt="" src="//www.ibm.com/i/c.gif" width="8" border="0" height="6" /></td>
                    </tr>
                </tbody>
            </table>
            <table class="no-print" align="right" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr align="right">
                        <td><img alt="" src="//www.ibm.com/i/c.gif" width="100%" height="4" /><br />
                        <table border="0" cellpadding="0" cellspacing="0">
                            <tbody>
                                <tr>
                                    <td valign="middle"><img alt="" src="//www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" height="16" /><br />
                                    </td>
                                    <td valign="top" align="right"><a class="fbox" href="#main" cmimpressionsent="1"><strong>回页首</strong></a></td>
                                </tr>
                            </tbody>
                        </table>
                        </td>
                    </tr>
                </tbody>
            </table>
            <br />
            <br />
            <p><a name="N1009A"><span class="atitle">XFire 安装包</span></a></p>
            <p>XFire 框架目前的最新版本是 1.2.6，可以访问 xfire.codehaus.org 下载 XFire
            框架的安装包，下载时请选择&#8220;全部二进制发布包（Binary Distribution in zip package）&#8221;，而不仅仅是&#8220;XFire jar
            文件（Jar of all XFire modules）&#8221;。</p>
            <p>下载完成后，我们可以将下载的 .zip 文件解压缩到任意的文件夹中（后面的章节中使用 % XFIRE_HOME % 表示 XFire
            框架的安装目录），解压缩后形成的文件目录结构如下：</p>
            <ul>
                <li><strong>api（目录）</strong>
                <p>api 目录中是 XFire 框架中所有类（class）对应的 API 文档，为开发者使用 XFire 完成应用开发提供帮助。</p>
                </li>
                <li><strong>examples（目录）</strong>
                <p>examples 目录中包含了所有随 XFire 二进制包发布的实例，包括这些实例的源代码和相关 Web 应用配置内容。</p>
                </li>
                <li><strong>lib（目录）</strong>
                <p>lib 目录中包含 XFire 运行所需要的外部支持类包（.jar文件），可以根据不同项目所需的 XFire 特性选择所需要的支持类包。保守的方法是在
                Web 项目中包含所有的外部支持类包（.jar文件）。</p>
                </li>
                <li><strong>manual（目录）</strong>
                <p>manual 目录中包含有 XFire 框架的帮助文档，开发者可以从这些帮助文档中学习更多运用 XFire 框架实现 SOA 的知识和技巧。</p>
                </li>
                <li><strong>modules（目录）</strong>
                <p>modules 目录中包含了 XFire 框架根据不同特性分别编译的二进制包文件。发布基于 XFire 框架的 Web 项目时，可以选择使用该目录下的所有
                .jar 文件，也可以选择 XFire-all-1.2.6.jar 文件。</p>
                </li>
                <li><strong>XFire-all-1.2.6.jar</strong>
                <p>XFire 框架的二进制包文件，包含了全部的模块（modules）。</p>
                </li>
                <li><strong>LICENSE.txt</strong>
                <p>LICENSE.txt 文件中包含了 XFire 框架的授权协议。</p>
                </li>
                <li><strong>NOTICE.txt</strong>
                </li>
                <li><strong>README.txt</strong>
                <p>这两个文件中包含了 XFire 发布时的一些有用的信息。</p>
                </li>
            </ul>
            <br />
            <table width="100%" border="0" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr>
                        <td><img alt="" src="//www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" height="1" /><br />
                        <img alt="" src="//www.ibm.com/i/c.gif" width="8" border="0" height="6" /></td>
                    </tr>
                </tbody>
            </table>
            <table class="no-print" align="right" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr align="right">
                        <td><img alt="" src="//www.ibm.com/i/c.gif" width="100%" height="4" /><br />
                        <table border="0" cellpadding="0" cellspacing="0">
                            <tbody>
                                <tr>
                                    <td valign="middle"><img alt="" src="//www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" height="16" /><br />
                                    </td>
                                    <td valign="top" align="right"><a class="fbox" href="#main" cmimpressionsent="1"><strong>回页首</strong></a></td>
                                </tr>
                            </tbody>
                        </table>
                        </td>
                    </tr>
                </tbody>
            </table>
            <br />
            <br />
            <p><a name="N100F7"><span class="atitle">XFire 框架支撑环境</span></a></p>
            <p>XFire框架是一种基于Servlet技术的SOA应用开发框架，要正常运行基于XFire应用框架开发的企业应用，除了XFire框架本身之外，还需要JDK和Servlet容器的支持。</p>
            <p><a name="N10100"><span class="smalltitle">1．JDK 版本选择、下载和安装</span></a></p>
            <p>XFire 支持非常多的特性，其中不同的特性对 JDK 版本的要求有所不同，比如如果项目中选择基于 JSR181 标准发布 Web 服务，我们就需要选择
            JDK5 或者以上版本，如果仅仅选择将 Web 服务绑定到最简单的 POJO，我们只需要选择 JDK1.4 版本即可。</p>
            <p>JDK 各版本均可以在 <a href="http://java.sun.com/" target="new" cmimpressionsent="1">java.sun.com</a> 网站上下载，如何安装 JDK 请参考 SUN 公司的相关技术文档和 JDK
            的帮助文档。</p>
            <p><a name="N10110"><span class="smalltitle">2．Servlet 容器下载和安装</span></a></p>
            <p>XFire 是一种基于 Servlet 技术的 SOA 应用开发框架，需要 Servlet 容器的支持。XFire 支持在多种 Servlet
            容器中运行，包括 Websphere、Weblogic、TOMCAT 等。为了说明的简单，我们选择使用 TOMCAT（版本5.0.30）作为 XFire
            的运行容器，所有配置过程和发布步骤的说明也均是针对 TOMCAT，如果读者使用 TOMCAT 之外的其它 Servlet 容器或者选择了 TOMCAT
            的其它版本，下面的配置过程和步骤可能需要做出调整，请读者根据实际 Servlet 容器的帮助文档进行相应调整。</p>
            <p>TOMCAT 各版本均可以在 <a href="http://tomcat.apache.org/" target="new" cmimpressionsent="1">tomcat.apache.org</a> 网站上下载，如何正确安装 TOMCAT 服务器请参考 TOMCAT
            服务器的帮助文档。</p>
            <p><a name="N10120"><span class="smalltitle">3．xalan</span></a></p>
            <p>XFire 需要 xalan 项目的支持，然而 1.2.6 版本中并没有带有相应的 jar 文件，因此请访问 <a href="http://xml.apache.org/" target="new" cmimpressionsent="1">xml.apache.org</a>，下载 xalan 项目的二进制包。</p>
            <br />
            <table width="100%" border="0" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr>
                        <td><img alt="" src="//www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" height="1" /><br />
                        <img alt="" src="//www.ibm.com/i/c.gif" width="8" border="0" height="6" /></td>
                    </tr>
                </tbody>
            </table>
            <table class="no-print" align="right" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr align="right">
                        <td><img alt="" src="//www.ibm.com/i/c.gif" width="100%" height="4" /><br />
                        <table border="0" cellpadding="0" cellspacing="0">
                            <tbody>
                                <tr>
                                    <td valign="middle"><img alt="" src="//www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" height="16" /><br />
                                    </td>
                                    <td valign="top" align="right"><a class="fbox" href="#main" cmimpressionsent="1"><strong>回页首</strong></a></td>
                                </tr>
                            </tbody>
                        </table>
                        </td>
                    </tr>
                </tbody>
            </table>
            <br />
            <br />
            <p><a name="N1012D"><span class="atitle">XFire 应用配置</span></a></p>
            <p>前面的章节中我们下载和安装了 XFire 安装包和所需要的支持环境，现在我们开始学习如何从零开始创建 XFire
            应用开发环境。下面的所有配置过程和发布步骤均针对 TOMCAT（版本5.0.30）服务器，如果选择其它的 Servlet
            容器，下面的配置过程和步骤可能需要做出调整，请读者根据实际 Servlet 容器的帮助文档进行相应调整。</p>
            <p><a name="h1"><span class="smalltitle">1、创建 Web 应用目录和基本元素</span></a></p>
            <ol type="a">
                <li>在 %TOMCAT_HOME%/webapps 目录下创建新的 Web 应用目录 &#8220;XFire&#8221;
                <p><em>[注] 其中的 %TOMCAT_HOME% 指向 TOMCAT 的安装目录。</em> </p>
                </li>
                <li>在 &#8221;XFire&#8221;目录下创建 &#8221;WEB-INF&#8221;目录、
                </li>
                <li>在 &#8221; WEB-INF&#8221;目录下创建 &#8221;lib&#8221;目录和 &#8221;classes&#8221;目录
                </li>
                <li>在 &#8221; WEB-INF&#8221;目录下创建 Web 应用描述文件 &#8221;web.xml&#8221;， &#8221;web.xml&#8221;文件的内容见 <a href="#code11" cmimpressionsent="1">清单 1-1</a>。 </li>
            </ol>
            <br />
            <a name="code11"><strong>清单 1-1
            WEB-INF\web.xml</strong></a><br />
            <table width="100%" border="0" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr>
                        <td class="code-outline">
                        <pre class="displaycode">                <br />
                        1、	&lt;?xml version="1.0" encoding="ISO-8859-1"?&gt;<br />
                        2、	&lt;web-app xmlns="http://java.sun.com/xml/ns/j2ee"<br />
                        3、	    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"<br />
                        4、	    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee   <br />
                        http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"<br />
                        5、	    version="2.4"&gt;<br />
                        6、	<br />
                        7、	    &lt;display-name&gt;XFire实例&lt;/display-name&gt;<br />
                        8、	    &lt;description&gt;<br />
                        9、	         基于XFire框架发布Web服务的例子<br />
                        10、	    &lt;/description&gt;<br />
                        11、	<br />
                        12、	&lt;/web-app&gt;<br />
                        </pre>
                        </td>
                    </tr>
                </tbody>
            </table>
            <br />
            <p><a name="N1015E"><span class="smalltitle">2、拷贝 XFire 所需的支持类包文件</span></a></p>
            <p>拷贝 %XFIRE_HOME%/lib 目录下所有文件到 <a href="#h1" cmimpressionsent="1">&#8220;1、创建 Web
            应用目录和基本元素&#8221;</a> 中所创建的 &#8221;lib&#8221;目录下，将 %XFIRE_HOME%/XFire-all-1.2.6.jar 文件也拷贝到 <a href="#h1" cmimpressionsent="1">&#8220;1、创建 Web 应用目录和基本元素&#8221;</a> 中所创建的 &#8221;lib&#8221;目录下。将 xalan
            安装包中的所有 jar 文件和所需要的支持 jar 文件拷贝到相同的 &#8221;lib&#8221;目录下。</p>
            <p><strong>[注] </strong>为了减少拷贝的 jar 文件的数目，开发者可以根据项目的需要选择需要拷贝的 jar
            文件，而不是全部拷贝，如何根据需要选择拷贝合适的类包文件请访问 <a href="http://xfire.codehaus.org/Dependency+Guide" cmimpressionsent="1">XFire
            站点</a>。 </p>
            <p><a name="N10178"><span class="smalltitle">3、配置 XFire 框架运行所需的
            Servlet</span></a></p>
            <p>修改 web.xml 文件，在其中增加如下 Servlet 定义内容。</p>
            <table width="100%" border="0" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr>
                        <td class="code-outline">
                        <pre class="displaycode">1、	&lt;servlet&gt;<br />
                        2、	    &lt;servlet-name&gt;XFireServlet&lt;/servlet-name&gt;<br />
                        3、	    &lt;display-name&gt;XFire Servlet&lt;/display-name&gt;<br />
                        4、	    &lt;servlet-class&gt;<br />
                        5、	        org.codehaus.xfire.transport.http.XFireConfigurableServlet<br />
                        6、	    &lt;/servlet-class&gt;<br />
                        7、	  &lt;/servlet&gt;<br />
                        8、	<br />
                        9、	  &lt;servlet-mapping&gt;<br />
                        10、	    &lt;servlet-name&gt;XFireServlet&lt;/servlet-name&gt;<br />
                        11、	    &lt;url-pattern&gt;/servlet/XFireServlet/*&lt;/url-pattern&gt;<br />
                        12、	  &lt;/servlet-mapping&gt;<br />
                        13、	<br />
                        14、	  &lt;servlet-mapping&gt;<br />
                        15、	    &lt;servlet-name&gt;XFireServlet&lt;/servlet-name&gt;<br />
                        16、	    &lt;url-pattern&gt;/services/*&lt;/url-pattern&gt;<br />
                        17、	&lt;/servlet-mapping&gt;<br />
                        </pre>
                        </td>
                    </tr>
                </tbody>
            </table>
            <br />
            <p><a name="N10184"><span class="smalltitle">4、创建 XFire 框架的服务发布文件
            services.xml</span></a></p>
            <ol type="a">
                <li>在 <a href="#h1" cmimpressionsent="1">&#8220;1、创建 Web 应用目录和基本元素&#8221;</a> 中创建的 classes
                目录下新建目录 &#8221;META-INF\xfire&#8221;；
                </li>
                <li>在步骤 a) 中新建的 &#8221;xfire&#8221;文件目录下创建新文件 services.xml，文件的默认内容如 <a href="#code12" cmimpressionsent="1">清单1-2</a> 。 </li>
            </ol>
            <br />
            <a name="code12"><strong>清单 1-2
            WEB-INF\classes\META-INF\xfire\services.xml</strong></a><br />
            <table width="100%" border="0" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr>
                        <td class="code-outline">
                        <pre class="displaycode">                <br />
                        1、	&lt;beans xmlns="http://XFire.codehaus.org/config/1.0"&gt;<br />
                        2、	&lt;/beans&gt;<br />
                        </pre>
                        </td>
                    </tr>
                </tbody>
            </table>
            <br />
            <br />
            <table width="100%" border="0" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr>
                        <td><img alt="" src="//www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" height="1" /><br />
                        <img alt="" src="//www.ibm.com/i/c.gif" width="8" border="0" height="6" /></td>
                    </tr>
                </tbody>
            </table>
            <table class="no-print" align="right" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr align="right">
                        <td><img alt="" src="//www.ibm.com/i/c.gif" width="100%" height="4" /><br />
                        <table border="0" cellpadding="0" cellspacing="0">
                            <tbody>
                                <tr>
                                    <td valign="middle"><img alt="" src="//www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" height="16" /><br />
                                    </td>
                                    <td valign="top" align="right"><a class="fbox" href="#main" cmimpressionsent="1"><strong>回页首</strong></a></td>
                                </tr>
                            </tbody>
                        </table>
                        </td>
                    </tr>
                </tbody>
            </table>
            <br />
            <br />
            <p><a name="N101A4"><span class="atitle">将 POJO 发布成 Web 服务</span></a></p>
            <p>XFire 框架中，我们有两种方式将 POJO 发布成 Web 服务：</p>
            <ul>
                <li>一种方式是直接使用 Web 服务接口和 Web 服务实现类（POJO）来发布；
                </li>
                <li>另一种方式是基于 JSR181 标准和注释技术将被注释的 POJO 发布成 Web 服务； </li>
            </ul>
            <p>下面的章节中我们将学习使用第一种方式来完成 POJO 的 Web 服务发布。我们将使用经典的 &#8221;Hello World!&#8221;例子来演示将 POJO 发布成
            Web 服务所需要的步骤，不过我们不再是简单的访问一个 Java 方法来输出 &#8221;Hello World!&#8221;字符串，而是转为在 SOA 环境下实现：Web
            服务客户端通过访问服务器端发布成 Web 服务的 POJO 获得返回的 &#8221;Hello World!&#8221;字符串后输出到客户端的控制台上。</p>
            <p>将 POJO 发布成 Web 服务的基本步骤如下：</p>
            <ol>
                <li>创建 Web 服务接口，声明该 Web 服务对外暴露的接口；
                </li>
                <li>创建 Web 服务实现类，为 Web 服务接口提供实现；
                </li>
                <li>修改 XFire 框架的服务发布文件 ---- services.xml，将 POJO 发布成 Web 服务。 </li>
            </ol>
            <p>下面我们通过创建 &#8221;Hello World!&#8221;例子来具体说明如何实现这三个步骤。</p>
            <p><a name="N101CB"><span class="smalltitle">1．创建 Web 服务接口 ----
            HelloWorldService</span></a></p>
            <p>要将 POJO 发布成 Web 服务，首先需要创建 Web 服务接口，在接口中声明该 Web 服务需要对外暴露的接口。</p>
            <p>我们根据需要创建 Web 服务接口 &#8221; HelloWorldService&#8221;，在其中声明一个 &#8221;sayHello&#8221;方法，该方法返回 &#8221;String
            &#8221;类型的内容。&#8221; HelloWorldService&#8221;接口对应的 Java 文件代码如 <a href="#code13" cmimpressionsent="1">清单 1-3</a>。</p>
            <br />
            <a name="code13"><strong>清单 1-3
            WEB-INF\classes\org\vivianj\xfire\pojo\HelloWorldService.java</strong></a><br />
            <table width="100%" border="0" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr>
                        <td class="code-outline">
                        <pre class="displaycode">                <br />
                        1．package org.vivianj.xfire.pojo;<br />
                        2．<br />
                        3． /**<br />
                        4． * HelloWorldService 中声明需要发布成 Web 服务的所有 Java 方法 <br />
                        5． * HelloWorldService 作为Web服务接口<br />
                        6． */<br />
                        7． public interface HelloWorldService {<br />
                        8．	/**<br />
                        9．	     * sayHello 方法声明了 Web 服务对外暴露的接口<br />
                        10．	 * <br />
                        11．	 * @return 返回给客户端的字符串<br />
                        12．	 */<br />
                        13．	public String sayHello();<br />
                        14．}<br />
                        </pre>
                        </td>
                    </tr>
                </tbody>
            </table>
            <br />
            <p><a name="N101E3"><span class="smalltitle">2．创建 Web 服务实现类
            &#8221;HelloWorldServiceImpl&#8221;</span></a></p>
            <p>创建 Web 服务实现类 &#8221;HelloWorldServiceImpl&#8221;，它继承 <a href="#h1" cmimpressionsent="1">&#8221;1、创建Web服务接口 ---- HelloWorldService&#8221;</a> 中创建的
            HelloWorldService 接口，并且为它声明的 &#8221;sayHello&#8221;方法提供具体实现： 返回字符串&#8221;Hello World!&#8221;。
            &#8221;HelloWorldServiceImpl&#8221;类对应的 Java 文件代码如 <a href="#code14" cmimpressionsent="1">清单
            1-4</a>。</p>
            <br />
            <a name="code14"><strong>清单 1-4
            WEB-INF\classes\org\vivianj\xfire\pojo\HelloWorldServiceImpl.java</strong></a><br />
            <table width="100%" border="0" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr>
                        <td class="code-outline">
                        <pre class="displaycode">                <br />
                        1．package org.vivianj.xfire.pojo;<br />
                        2．<br />
                        3．/**<br />
                        4． * HelloWorldServiceImpl 中为 Web 服务接口中声明的所有 Java 方法提供具体实现 <br />
                        5． * HelloWorldServiceImpl 作为 Web 服务的实现类<br />
                        6． */<br />
                        7．public class HelloWorldServiceImpl implements HelloWorldService {<br />
                        8．<br />
                        9．	/*<br />
                        10．	 * sayHello 方法为 HelloWorldService 服务接口定义的 sayHello 方法提供具体实现<br />
                        11．	 *  <br />
                        12．	 * @see org.vivianj.XFire.pojo.HelloWorldService#sayHelloToXFire()<br />
                        13．	 */<br />
                        14．	public String sayHello() {<br />
                        15．		return "Hello World!";<br />
                        16．	}<br />
                        17．<br />
                        18．}<br />
                        </pre>
                        </td>
                    </tr>
                </tbody>
            </table>
            <br />
            <p><a name="N101FC"><span class="smalltitle">3．修改 services.xml，将 POJO 发布成 Web
            服务</span></a></p>
            <p>我们可以在 WEB-INF\classes\META-INF\XFire\services.xml 文件中的 &lt;beans &#8230;&gt; 和
            &lt;/beans&gt; 元素中间加入如下的 xml 内容将上面创建的 HelloWorldService 发布成 Web 服务。</p>
            <table width="100%" border="0" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr>
                        <td class="code-outline">
                        <pre class="displaycode">1．&lt;service&gt;<br />
                        2．	&lt;name&gt;HelloWorldService&lt;/name&gt;<br />
                        3．	&lt;namespace&gt;http://vivianj.org/HelloWorldService&lt;/namespace&gt;<br />
                        4．	&lt;serviceClass&gt;<br />
                        5．		org.vivianj.xfire.pojo.HelloWorldService<br />
                        6．	&lt;/serviceClass&gt;<br />
                        7．	&lt;implementationClass&gt;<br />
                        8．		org.vivianj.xfire.pojo.HelloWorldServiceImpl<br />
                        9．	&lt;/implementationClass&gt;<br />
                        10．&lt;/service&gt;<br />
                        </pre>
                        </td>
                    </tr>
                </tbody>
            </table>
            <br />
            <p>其中各元素的功能如下：</p>
            <ul>
                <li><strong>service</strong>
                <p>service 标签和它所包含的 xml 内容为发布成 Web 服务的 POJO 提供完整的描述。</p>
                </li>
                <li><strong>name</strong>
                <p>Web 服务被发布时所采用的唯一名称。</p>
                </li>
                <li><strong>namespace</strong>
                <p>Web 服务发布时所使用的命名空间。</p>
                </li>
                <li><strong>serviceClass</strong>
                <p>Web 服务接口类的全名，包括包名和类名。</p>
                </li>
                <li><strong>implemetationClass</strong>
                <p>Web 服务实现类的全名，包括包名和类名。</p>
                </li>
            </ul>
            <p>更多 service 元素的子元素和它们的用法请参考 <a href="http://xfire.codehaus.org/services.xml+Reference" cmimpressionsent="1">XFire 站点</a>。</p>
            <p>通过上面的三个步骤，我们已经将新创建的HelloWorldService发布成了Web服务，我们可以使用下面的步骤测试一下创建的Web服务是否能够正常运行：</p>
            <ol>
                <li>编译上面的步骤中创建的 Java 接口和类；
                </li>
                <li>启动 TOMCAT 服务器。
                </li>
                <li>等 TOMCAT 服务器完全启动后，打开浏览器，在地址栏中输入
                http://localhost:8080/XFire/services/HelloWorldService?wsdl。 </li>
            </ol>
            <p>其中 HelloWorldServcie 是配置文件中 service\name 元素所定义的内容，&#8221;wsdl&#8221;参数表示查看该 Web 服务的
            WSDL（Web服务描述语言）文件。</p>
            <p>如果浏览器中出现如下图所示类似的内容，表示 Web 服务发布成功，我们可以编写客户端访问该 Web
            服务从服务器获取返回字符串，本文下载资源中提供的下载文件中包含有可供参考的客户端类
            org.vivianj.xfire.pojo.client.HelloWorldServiceClient。</p>
            <br />
            <a name="N10259"><strong>图：浏览器中访问效果</strong></a><br />
            <img alt="" src="fig001.jpg" /> <br />
            <p>如果浏览器中出现错误提示，请按照上面的步骤和说明检查已经完成的开发、配置过程是否完全正确。</p>
            <br />
            <table width="100%" border="0" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr>
                        <td><img alt="" src="//www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" height="1" /><br />
                        <img alt="" src="//www.ibm.com/i/c.gif" width="8" border="0" height="6" /></td>
                    </tr>
                </tbody>
            </table>
            <table class="no-print" align="right" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr align="right">
                        <td><img alt="" src="//www.ibm.com/i/c.gif" width="100%" height="4" /><br />
                        <table border="0" cellpadding="0" cellspacing="0">
                            <tbody>
                                <tr>
                                    <td valign="middle"><img alt="" src="//www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" height="16" /><br />
                                    </td>
                                    <td valign="top" align="right"><a class="fbox" href="#main" cmimpressionsent="1"><strong>回页首</strong></a></td>
                                </tr>
                            </tbody>
                        </table>
                        </td>
                    </tr>
                </tbody>
            </table>
            <br />
            <br />
            <p><a name="N10266"><span class="atitle">结束语</span></a></p>
            <p>本文中作者首先讲解了 XFire 框架的主要特性，XFire 框架的运行环境以及基于 XFire 框架开发 SOA 应用的基本步骤，并且借助于 SOA
            环境下的 &#8221;Hello World!&#8221;例子，详细的讲解和演示了如何基于 XFire 框架、经过简单的开发、配置步骤就将一个 POJO
            类中包含的方法发布成Web服务。从 &#8221;Hello World!&#8221;例子实现的过程中，我们可以发现 XFire 框架最大化的发挥了 POJO 的作用，减少了 SOA
            实施时对框架本身的依赖，降低了 SOA 实施的难度，企业实施 SOA 时并不需要增加太多的投入就可以实现目标。</p>
            <br />
            <br />
            <table width="100%" border="0" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr>
                        <td><img alt="" src="//www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" height="1" /><br />
                        <img alt="" src="//www.ibm.com/i/c.gif" width="8" border="0" height="6" /></td>
                    </tr>
                </tbody>
            </table>
            <table class="no-print" align="right" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr align="right">
                        <td><img alt="" src="//www.ibm.com/i/c.gif" width="100%" height="4" /><br />
                        <table border="0" cellpadding="0" cellspacing="0">
                            <tbody>
                                <tr>
                                    <td valign="middle"><img alt="" src="//www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" height="16" /><br />
                                    </td>
                                    <td valign="top" align="right"><a class="fbox" href="#main" cmimpressionsent="1"><strong>回页首</strong></a></td>
                                </tr>
                            </tbody>
                        </table>
                        </td>
                    </tr>
                </tbody>
            </table>
            <br />
            <br />
            <p><span class="atitle"><a name="download">下载</a></span></p>
            <table class="data-table-1" width="100%" border="0" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr>
                        <th scope="col">名字</th>
                        <th scope="col" align="right">大小</th>
                        <th scope="col">下载方法</th>
                    </tr>
                    <tr>
                        <td nowrap="nowrap">xfire.war</td>
                        <td align="right" nowrap="nowrap">6 KB</td>
                        <td nowrap="nowrap"><a class="fbox" href="" cmimpressionsent="1"><strong>HTTP</strong></a></td>
                    </tr>
                </tbody>
            </table>
            <table border="0" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr valign="top">
                        <td colspan="5"><img alt="" src="//www.ibm.com/i/c.gif" width="12" border="0" height="12" /></td>
                    </tr>
                    <tr>
                        <td><img alt="" src="//www.ibm.com/i/v14/icons/fw.gif" width="16" height="16" /></td>
                        <td><a class="fbox" href="/developerworks/cn/whichmethod.html" cmimpressionsent="1">关于下载方法的信息</a></td>
                        <td><img alt="" src="//www.ibm.com/i/c.gif" width="50" height="1" /></td>
                    </tr>
                </tbody>
            </table>
            <br />
            <br />
            <p><a name="resources"><span class="atitle">参考资料 </span></a></p>
            <strong>学习</strong><br />
            <ul>
                <li>访问 <a href="http://xfire.codehaus.org/User%27s+Guide" cmimpressionsent="1">XFire 框架用户指南</a> 可以获得更多关于 XFire 的使用帮助。<br />
                <br />
                </li>
                <li>访问 <a href="http://xfire.codehaus.org/Eclipse+Plugin" cmimpressionsent="1">XFire 的 Eclipse 插件</a> 可以获得关于 XFire 提供的 Eclipse
                插件的更多信息。<br />
                <br />
                </li>
            </ul>
            <br />
            <strong>获得产品和技术</strong><br />
            <ul>
                <li>访问 <a href="http://java.sun.com/" cmimpressionsent="1">java.sun.com</a> 获得
                JDK 各种版本二进制安装包。<br />
                <br />
                </li>
                <li>访问 <a href="http://tomcat.apache.org/" cmimpressionsent="1">tomcat.apache.org</a> 获得 TOMCAT 服务器各种版本二进制安装包。<br />
                <br />
                </li>
                <li>访问 <a href="http://xml.apache.org/" cmimpressionsent="1">xml.apache.org</a>
                获得 xalan 框架各种版本二进制安装包。<br />
                <br />
                </li>
                <li>访问 <a href="http://http//xfire.codehaus.org/" cmimpressionsent="1">XFire.codehaus.org</a> 获得 XFire 框架的二进制安装包。</li>
            </ul>
            </td>
        </tr>
    </tbody>
</table>
<img src ="http://www.blogjava.net/AstroQi/aggbug/215717.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/AstroQi/" target="_blank">Astro.Qi</a> 2008-07-18 11:45 <a href="http://www.blogjava.net/AstroQi/archive/2008/07/18/215717.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JDBC ORACLE CLOB (用分页思想解决兆级以上的字符流操作问题)</title><link>http://www.blogjava.net/AstroQi/archive/2008/07/10/214025.html</link><dc:creator>Astro.Qi</dc:creator><author>Astro.Qi</author><pubDate>Thu, 10 Jul 2008 09:05:00 GMT</pubDate><guid>http://www.blogjava.net/AstroQi/archive/2008/07/10/214025.html</guid><wfw:comment>http://www.blogjava.net/AstroQi/comments/214025.html</wfw:comment><comments>http://www.blogjava.net/AstroQi/archive/2008/07/10/214025.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/AstroQi/comments/commentRss/214025.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/AstroQi/services/trackbacks/214025.html</trackback:ping><description><![CDATA[<br />
import java.io.*;<br />
import java.util.*;<br />
import java.sql.*;<br />
&nbsp; <br />
public class ClobTest {<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp; private static final String DRIVER = "oracle.jdbc.driver.OracleDriver";<br />
&nbsp;&nbsp;&nbsp; private static final String URL = "jdbc:oracle:thin:@127.0.0.1:1521:ora10g";<br />
&nbsp;&nbsp;&nbsp; private static final String USER = "sc";<br />
&nbsp;&nbsp;&nbsp; private static final String PASSWORD = "sc";<br />
&nbsp;&nbsp;&nbsp; private static Connection conn = null;<br />
&nbsp;&nbsp;&nbsp; private static Statement stmt = null;<br />
<br />
&nbsp; <br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * 往数据库中插入一个新的CLOB对象<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; public static void save(BO obj) throws Exception {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* <span style="color: red;">一定要</span>设定不自动提交，否则抛出<span style="color: red;">ORA-01002: 读取违反顺序</span> */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; boolean defaultCommit = conn.getAutoCommit();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn.setAutoCommit(false);<br />
&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; stmt = conn.createStatement();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 插入一个空的CLOB对象 */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; stmt.executeUpdate("INSERT INTO TEST_CLOB VALUES ('1000', EMPTY_CLOB())");//<span style="color: red;">一定要</span>使用Oracle中的EMPTY_CLOB()函数<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; stmt.close();//记得关掉我哦 :-)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; stmt= null;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 查询此CLOB对象并锁定 */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //stmt = conn.prepareStatement();//如果是PrepareStatement接口,<span style="color: red;">一定要</span>重新创建该对象,否则抛出<span style="color: red;">ORA-01006: 赋值变量不存</span><span style="color: red;">在</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ResultSet rs = stmt.executeQuery("SELECT CLOBCOL FROM TEST_CLOB WHERE ID='1000' FOR UPDATE");//<span style="color: red;">一定要</span>for update锁定该记录，否则抛出<span style="color: red;">ORA-22920: 未锁定含有 LOB 值的行</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (rs.next()) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 取出此CLOB对象 */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oracle.sql.CLOB clob = (oracle.sql.CLOB)rs.getClob("CLOBCOL");<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 向CLOB对象中写入数据 */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Writer out = clob.getCharacterOutputStream();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //out.write(new String(obj.getEmail()));//obj.getEmail()返回byte[]类型,但是当obj.getEmail()绝对大时,执行new String(byte[])时,JVM会抛出<span style="color: red;">内存</span><span style="color: red;">溢出</span>异常<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; byte[] emails = obj.getEmail();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ClobStreamHandler csh = new ClobStreamHandler(emails);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String[] arrx = csh.pagedClobStream();//要解决内存溢出异常，必须把绝对大的byte[]进行<span style="color: red;">分页</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (arrx != null){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; arrx.length; i++) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.write(arrx[i]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.flush();//要解决内存溢出异常,必须<span style="color: red;">一页一页</span>的flush()到数据库<br />
&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; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else out.write("");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 正式提交 */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn.commit();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 恢复原提交状态 */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn.setAutoCommit(defaultCommit);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (Exception ex) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 出错回滚 */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn.rollback();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw ex;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }  finally {相关关闭操作}<br />
&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp; <br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * 修改CLOB对象（是在原CLOB对象基础上进行覆盖式的修改）<br />
&nbsp;&nbsp;&nbsp;&nbsp; *<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @param obj - 数据对象<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @throws java.lang.Exception<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @roseuid 3EDA04B60367<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; public static void modify(BO obj) throws Exception {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 设定不自动提交 */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; boolean defaultCommit = conn.getAutoCommit();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn.setAutoCommit(false);<br />
&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 查询CLOB对象并锁定 */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ResultSet rs = stmt.executeQuery("SELECT CLOBCOL FROM TEST_CLOB WHERE ID='1000' FOR UPDATE");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (rs.next()) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 获取此CLOB对象 */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oracle.sql.CLOB clob = (oracle.sql.CLOB)rs.getClob("CLOBCOL"); &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; /* 进行覆盖式修改 */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Writer out = clob.getCharacterOutputStream();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; byte[] emails = obj.getEmail();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ClobStreamHandler csh = new ClobStreamHandler(emails);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String[] arrx = csh.pagedClobStream();//要解决内存溢出异常，必须把绝对大的byte[]进行<span style="color: red;">分页</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (arrx != null){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; arrx.length; i++) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.write(arrx[i]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.flush();//要解决内存溢出异常,必须<span style="color: red;">一页一页</span>的flush()到数据库<br />
&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; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else out.write("");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 正式提交 */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn.commit();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 恢复原提交状态 */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn.setAutoCommit(defaultCommit);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (Exception ex) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 出错回滚 */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn.rollback();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw ex;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }  finally {相关关闭操作}<br />
&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 恢复原提交状态 */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn.setAutoCommit(defaultCommit);<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp; <br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * 替换CLOB对象（将原CLOB对象清除，换成一个全新的CLOB对象）<br />
&nbsp;&nbsp;&nbsp;&nbsp; *<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @param obj - 数据对象<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @throws java.lang.Exception<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @roseuid 3EDA04BF01E1<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; public static void replace(BO obj) throws Exception {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 设定不自动提交 */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; boolean defaultCommit = conn.getAutoCommit();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn.setAutoCommit(false);<br />
&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 清空原CLOB对象 */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; stmt.executeUpdate("UPDATE TEST_CLOB SET CLOBCOL=EMPTY_CLOB() WHERE ID='1000'");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 查询CLOB对象并锁定 */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ResultSet rs = stmt.executeQuery("SELECT CLOBCOL FROM TEST_CLOB WHERE ID='1000' FOR UPDATE");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (rs.next()) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 获取此CLOB对象 */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oracle.sql.CLOB clob = (oracle.sql.CLOB)rs.getClob("CLOBCOL");<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; Writer out = clob.getCharacterOutputStream();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; byte[] emails = item.getEmail();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ClobStreamHandler csh = new ClobStreamHandler(emails);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String[] arrx = csh.pagedClobStream();//要解决内存溢出异常，必须把绝对大的byte[]进行<span style="color: red;">分页</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (arrx != null){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; arrx.length; i++) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.write(arrx[i]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.flush();//要解决内存溢出异常,必须<span style="color: red;">一页一页</span>的flush()到数据库<br />
&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; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else out.write("");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 正式提交 */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn.commit();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 恢复原提交状态 */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn.setAutoCommit(defaultCommit);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (Exception ex) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 出错回滚 */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn.rollback();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw ex;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } finally {相关关闭操作}<br />
&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp; <br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * 读取CLOB对象<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; public static byte[] read() throws Exception {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 设定不自动提交 */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; boolean defaultCommit = conn.getAutoCommit();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn.setAutoCommit(false);<br />
&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 查询CLOB对象 */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ResultSet rs = stmt.executeQuery("SELECT * FROM TEST_CLOB WHERE ID='1000'");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (rs.next()) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 获取CLOB对象 */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oracle.sql.CLOB c= (oracle.sql.CLOB)rs.getClob("CLOBCOL");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (c != null){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oracle.jdbc.driver.OracleClobInputStream is = (OracleClobInputStream) c.getAsciiStream();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();<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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; byte[] by = new byte[1024 * 200];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while(is.read(by, 0, by.length) != -1){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; baos.write(by, 0, by.length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; baos.flush();//<span style="color: red;">把数据写入内存</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; baos.close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; is.close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return baos.toByteArray();//<span style="color: red;">不会内存溢出了</span>,呵呵. 原因是把数据写入了内存,而不是JVM的内存管理区域<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (SQLException e) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //e.printStackTrace();<br />
&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; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else return new byte[0];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (Exception ex) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn.rollback();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw ex;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } finally {相关关闭操作}<br />
&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 恢复原提交状态 */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn.setAutoCommit(defaultCommit);<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp; <br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * 建立测试用表格<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @throws Exception<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; public static void createTables() throws Exception {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; stmt.executeUpdate("CREATE TABLE TEST_CLOB (ID VARCHAR2(4), CLOBCOL CLOB)");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; stmt.executeUpdate("CREATE TABLE TEST_BLOB (ID VARCHAR2(4), BLOBCOL BLOB)");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (Exception ex) {<br />
&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp; <br />
&nbsp;&nbsp;&nbsp; public static void main(String[] args) throws Exception {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 装载驱动,建立数据库连接 */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Class.forName(DRIVER);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn = DriverManager.getConnection(URL, USER, PASSWORD);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; stmt = conn.createStatement();<br />
&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 建立测试表格 */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; createTables();<br />
&nbsp;&nbsp;&nbsp; }<br />
} <br />
<br />
<br />
&nbsp;&nbsp;&nbsp; 对Clob字符流进行分页的算法：<br />
&nbsp;&nbsp;&nbsp; <br />
<div style="border-left-color: #cccccc; padding-top: 4px; padding-right: 5px; padding-bottom: 4px; padding-left: 4px; background-color: #eeeeee; font-size: 13px; width: 98%; "><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #008080;">&nbsp;1</span>&nbsp;<span style="color: #0000ff;">package</span><span style="color: #000000;">&nbsp;privy.astroqi.oracle.db.handler;<br />
</span><span style="color: #008080;">&nbsp;2</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">&nbsp;3</span>&nbsp;<span style="color: #008000;">/**</span><span style="color: #008000;"><br />
</span><span style="color: #008080;">&nbsp;4</span>&nbsp;<span style="color: #008000;">&nbsp;*&nbsp;<br />
</span><span style="color: #008080;">&nbsp;5</span>&nbsp;<span style="color: #008000;">&nbsp;*&nbsp;</span><span style="color: #808080;">@author</span><span style="color: #008000;">&nbsp;Astro&nbsp;Qi<br />
</span><span style="color: #008080;">&nbsp;6</span>&nbsp;<span style="color: #008000;">&nbsp;*&nbsp;</span><span style="color: #808080;">@since</span><span style="color: #008000;">&nbsp;&nbsp;2008-07-23&nbsp;00:05<br />
</span><span style="color: #008080;">&nbsp;7</span>&nbsp;<span style="color: #008000;">&nbsp;*<br />
</span><span style="color: #008080;">&nbsp;8</span>&nbsp;<span style="color: #008000;">&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">&nbsp;9</span>&nbsp;<span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;ClobStreamHandler&nbsp;{<br />
</span><span style="color: #008080;">10</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">11</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;PAGE_SIZE&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1024</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">200</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">;<br />
</span><span style="color: #008080;">12</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;<br />
</span><span style="color: #008080;">13</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">byte</span><span style="color: #000000;">[]&nbsp;dataes;<br />
</span><span style="color: #008080;">14</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;<br />
</span><span style="color: #008080;">15</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;length;<br />
</span><span style="color: #008080;">16</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;<br />
</span><span style="color: #008080;">17</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;pageCount;<br />
</span><span style="color: #008080;">18</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;<br />
</span><span style="color: #008080;">19</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;ClobStreamHandler(</span><span style="color: #0000ff;">byte</span><span style="color: #000000;">[]&nbsp;data){<br />
</span><span style="color: #008080;">20</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(data&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">null</span><span style="color: #000000;">){<br />
</span><span style="color: #008080;">21</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">throw</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;java.lang.IllegalArgumentException(</span><span style="color: #000000;">"</span><span style="color: #000000;">参数byte[]不能为空,否则无法处理接下来的操作.</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
</span><span style="color: #008080;">22</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
</span><span style="color: #008080;">23</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
</span><span style="color: #008080;">24</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dataes&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;data;<br />
</span><span style="color: #008080;">25</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;length&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;dataes.length;<br />
</span><span style="color: #008080;">26</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pageCount&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;(length&nbsp;</span><span style="color: #000000;">%</span><span style="color: #000000;">&nbsp;PAGE_SIZE&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">)&nbsp;</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;(length&nbsp;</span><span style="color: #000000;">/</span><span style="color: #000000;">&nbsp;PAGE_SIZE)&nbsp;:&nbsp;(length&nbsp;</span><span style="color: #000000;">/</span><span style="color: #000000;">&nbsp;PAGE_SIZE)&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">;<br />
</span><span style="color: #008080;">27</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
</span><span style="color: #008080;">28</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;}<br />
</span><span style="color: #008080;">29</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;<br />
</span><span style="color: #008080;">30</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;String[]&nbsp;pagedClobStream(){<br />
</span><span style="color: #008080;">31</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
</span><span style="color: #008080;">32</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String[]&nbsp;arr&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;String[pageCount];<br />
</span><span style="color: #008080;">33</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
</span><span style="color: #008080;">34</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;(</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;i&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">;&nbsp;i&nbsp;</span><span style="color: #000000;">&lt;=</span><span style="color: #000000;">&nbsp;pageCount;&nbsp;i</span><span style="color: #000000;">++</span><span style="color: #000000;">)&nbsp;{<br />
</span><span style="color: #008080;">35</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;sheYuByte&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;length&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;(PAGE_SIZE&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;(i&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">));<br />
</span><span style="color: #008080;">36</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">byte</span><span style="color: #000000;">[]&nbsp;b&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">null</span><span style="color: #000000;">;<br />
</span><span style="color: #008080;">37</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(sheYuByte&nbsp;</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;PAGE_SIZE){<br />
</span><span style="color: #008080;">38</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">byte</span><span style="color: #000000;">[PAGE_SIZE];<br />
</span><span style="color: #008080;">39</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<br />
</span><span style="color: #008080;">40</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">else</span><span style="color: #000000;">&nbsp;{<br />
</span><span style="color: #008080;">41</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">byte</span><span style="color: #000000;">[sheYuByte];<br />
</span><span style="color: #008080;">42</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
</span><span style="color: #008080;">43</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;(</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;j&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;&nbsp;j&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">&nbsp;b.length;&nbsp;j</span><span style="color: #000000;">++</span><span style="color: #000000;">){<br />
</span><span style="color: #008080;">44</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b[j]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;dataes[(i&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">)&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;PAGE_SIZE&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;j];<br />
</span><span style="color: #008080;">45</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
</span><span style="color: #008080;">46</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arr[i&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;String(b);<br />
</span><span style="color: #008080;">47</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
</span><span style="color: #008080;">48</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
</span><span style="color: #008080;">49</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;arr;<br />
</span><span style="color: #008080;">50</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;}<br />
</span><span style="color: #008080;">51</span>&nbsp;<span style="color: #000000;">}</span></div>
<img src ="http://www.blogjava.net/AstroQi/aggbug/214025.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/AstroQi/" target="_blank">Astro.Qi</a> 2008-07-10 17:05 <a href="http://www.blogjava.net/AstroQi/archive/2008/07/10/214025.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JavaMail API 简介</title><link>http://www.blogjava.net/AstroQi/archive/2008/07/01/211873.html</link><dc:creator>Astro.Qi</dc:creator><author>Astro.Qi</author><pubDate>Tue, 01 Jul 2008 05:42:00 GMT</pubDate><guid>http://www.blogjava.net/AstroQi/archive/2008/07/01/211873.html</guid><wfw:comment>http://www.blogjava.net/AstroQi/comments/211873.html</wfw:comment><comments>http://www.blogjava.net/AstroQi/archive/2008/07/01/211873.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/AstroQi/comments/commentRss/211873.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/AstroQi/services/trackbacks/211873.html</trackback:ping><description><![CDATA[<span style="color: #ff0000">1.</span>介绍:<br />
<br />
Java Mail API的开发是SUN为Java开发者提供公用API框架的持续努力的良好例证。提倡公用框架，反对受限于供应商的解决方案，充分预示着一个日益开放的开发环境的建立。<br />
Java Mail API的结构本身证明了它的开发者的基本目标之一--软件开发的工作量应该取决于应用程序本身的复杂程度以及开发者所要求的控制程度。换句话说，Java Mail API尽可能地保持简单。乍看起来，JavaMail API所拥有的类总数以及类之间的关系可能让人误解为要花费漫长的学习时间。实际上，一旦正式开始使用，你就会发现该API不失为在应用程序中加入健壮的邮件/通讯支持的简单工具。 <br />
<br />
在我们步入JavaMail API之前，先看一下API所涉及的协议。以下便是大家日常所知、所乐于使用的4大信息传输协议：SMTP POP IMAP MIME NNTP。<br />
当然，上面的4个协议，并不是全部，还有NNTP和其它一些协议可用于传输信息，但是由于不常用到，所以本文便不提及了。理解这4个基本的协议有助于我们更好的使用JavaMail API。然而JavaMail API是被设计为与协议无关的，目前我们并不能克服这些协议的束缚。确切的说，如果我们使用的功能并不被我们选择的协议支持，那么JavaMail API并不可能如魔术师一样神奇的赋予我们这种能力。<br />
<br />
<span style="color: blue">1．SMTP</span><br />
简单邮件传输协议定义了递送邮件的机制。在下文中，我们将使用基于Java-Mail的程序与公司或者ISP的SMTP服务器进行通讯。这个SMTP服务器将邮件转发到接收者的SMTP服务器，直至最后被接收者通过POP或者IMAP协议获取。这并不需要SMTP服务器使用支持授权的邮件转发，但是却的确要注意SMTP服务器的正确设置（SMTP服务器的设置与JavaMail API无关）。<br />
<br />
<span style="color: blue">2．POP</span><br />
POP 是一种邮局协议，目前为第3个版本，即众所周知的POP3。POP定义了一种用户如何获得邮件的机制。它规定了每个用户使用一个单独的邮箱。大多数人在使用POP时所熟悉的功能并非都被支持，例如查看邮箱中的新邮件数量。而这个功能是微软的Outlook内建的，那么就说明微软Outlook之类的邮件客户端软件是通过查询最近收到的邮件来计算新邮件的数量来实现前面所说的功能。因此在我们使用JavaMail API时需要注意，当需要获得如前面所讲的新邮件数量之类的信息时，我们不得不自己进行计算。<br />
<br />
<span style="color: blue">3．IMAP</span><br />
IMAP 使用在接收信息的高级协议，目前版本为第4版，所以也被称为IMAP4。需要注意的是在使用IMAP时，邮件服务器必须支持该协议。从这个方面讲，我们并不能完全使用IMAP来替代POP，不能期待IMAP在任何地方都被支持。假如邮件服务器支持IMAP，那么我们的邮件程序将能够具有以下被IMAP所支持的特性：每个用户在服务器上可具有多个目录，这些目录能在多个用户之间共享。<br />
其与POP相比高级之处显而易见，但是在尝试采取IMAP时，我们认识到它并不是十分完美的：由于IMAP需要从其它服务器上接收新信息，将这些信息递送给用户，维护每个用户的多个目录，这都为邮件服务器带来了高负载。并且IMAP与POP的一个不同之处是POP用户在接收邮件时将从邮件服务器上下载邮件，而IMAP允许用户直接访问邮件目录，所以在邮件服务器进行备份作业时，由于每个长期使用此邮件系统的用户所用的邮件目录会占有很大的空间，这将直接导致邮件服务器上磁盘空间暴涨。<br />
<br />
<span style="color: blue">4．MIME</span><br />
MIME 并不是用于传送邮件的协议，它作为多用途邮件的扩展定义了邮件内容的格式：信息格式、附件格式等等。一些RFC标准都涉及了MIME：RFC 822, RFC 2045, RFC 2046, RFC 2047，有兴趣的Matrixer可以阅读一下。而作为JavaMail API的开发者，我们并不需关心这些格式定义，但是这些格式被用在了程序中。<br />
<br />
<span style="color: blue">5．NNTP和其它的第三方协议</span><br />
正因为JavaMail API在设计时考虑到与第三方协议实现提供商之间的分离，故我们可以很容易的添加一些第三方协议。SUN维护着一个第三方协议实现提供商的列表：<a href="http://java.sun.com/products/javamail/Third_Party.html" target="_new">http://java.sun.com/products/javamail/Third_Party.html</a>，通过此列表我们可以找到所需要的而又不被SUN提供支持的第三方协议：比如NNTP这个新闻组协议和S/MIME这个安全的MIME协议。<br />
<br />
<br />
<span style="color: #ff0000">2.</span>安装:<br />
<br />
安装前要确保你的机子上安装得有标准版的JDK和Web服务器,并且已配置好,有关它们的安装方法,请参考其它文章(网上到处都有).<br />
<br />
(1).安装JavaMail API。现在最常用的 JavaMail API 版本是1.3.<br />
要使用 JavaMail 1.3 API，请下载 JavaMail 1.3 实现，解开Javamail-1_3.zip 文件，并将 mail.jar 文件添加到 CLASSPATH 中。除了核心类，随版本 1.3 实现一起提供的还有 SMTP、IMAP4 和 POP3 供应商。<br />
<br />
(2).JavaBeans Activation Framework(1.0.2版) 的安装<br />
JavaMail API 的所有版本都需要 JavaBeans Activation Framework 来<span style="color: #4853ff"><span style="color: #5862ff">支持任意数据块的输入及相应处理</span></span>。功能似乎不多，但目前许多浏览器和邮件工具中都能找到这种基本的 MIME 型支持。下载完框架后，解开 jaf1_0_2.zip 文件，并将 activation.jar 文件添加到 CLASSPATH 中。<br />
<br />
注: 如果您使用的JDK是J2EE，就没有什么特定的事非要用基本 JavaMail API来做不可；J2EE 的类就能处理了,因为它本身就包含有JavaMail API和JAF,您只需要确将 j2ee.jar 文件添加到您的CLASSPATH 中并已全部设置好。<br />
<br />
<br />
<span style="color: #ff0000"><span style="color: #ff0000"><span style="color: #ff0000">3</span>.</span></span>JavaMail的常用类介绍<br />
<br />
(1) <a class="Channel_KeyLink" href="http://www.enadd.com/JAVA/Index.html">java</a>x.mail.Properties类<br />
JavaMail需要Properties来创建一个session对象。它将寻找字符串"mail.smtp.host"，属性值就是发送邮件的主机.<br />
<br />
用法:<br />
Properties props = new Properties ();<br />
props.put("mail.smtp.host", "smtp.163.com");//可以换上你的smtp主机名。<br />
<br />
<br />
(2) <a class="Channel_KeyLink" href="http://www.enadd.com/JAVA/Index.html">java</a>x.mail.Session类<br />
这个Session类代表JavaMail 中的一个邮件session. 每一个基于 JavaMail的应用程序至少有一个session但是可以有任意多的session。 在这个例子中, Session对象需要知道用来处理邮件的SMTP 服务器。<br />
<br />
用法:<br />
Session sendMailSession;<br />
sendMailSession = Session.getInstance(props, null);<br />
<br />
<br />
(3) <a class="Channel_KeyLink" href="http://www.enadd.com/JAVA/Index.html">java</a>x.mail.Transport类<br />
邮件是既可以被发送也可以被受到。JavaMail使用了两个不同的类来完成这两个功能：Transport 和Store. Transport 是用来发送信息的，而Store用来收信。对于这的教程我们只需要用到Transport对象。<br />
<br />
用法：<br />
Transport transport;<br />
transport = sendMailSession.getTransport("smtp");<br />
<br />
用JavaMail Session对象的getTransport 方法来初始化Transport。传过去的字符串申明了对象所要使用的协议，如"smtp"。这将为我们省了很多时间。因为JavaMail以境内置了很多协议的实现方法。<br />
<br />
注意: JavaMail并不是绝对支持每一个协议，目前支持IMAP、 SMTP和 POP3. <br />
<br />
<br />
(4) <a class="Channel_KeyLink" href="http://www.enadd.com/JAVA/Index.html">java</a>x.mail.MimeMessage类<br />
Message对象将存储我们实际发送的电子邮件信息，Message对象被作为一个MimeMessage对象来创建并且需要知道应当选择哪一个JavaMail session。<br />
<br />
用法：<br />
Message newMessage = new MimeMessage(sendMailSession);<br />
<br />
<br />
(5) <a class="Channel_KeyLink" href="http://www.enadd.com/JAVA/Index.html">java</a>x.mail.InternetAddress类<br />
一旦您创建了 Session 和 Message，并将内容填入消息后，就可以用Address确定信件地址了。和 Message 一样，Address 也是个抽象类。您用的是Javax.mail.internet.InternetAddress 类.<br />
<br />
用法:<br />
InternetAddress from=new InternetAddress("xxf@cafe.com");<br />
<br />
<br />
(6) <a class="Channel_KeyLink" href="http://www.enadd.com/JAVA/Index.html">java</a>x.mail.Store类<br />
Store类实现特定邮件协议上的读、写、监视、查找等操作。通过Javax.mail.Store类可以访问Javax.mail.Folder类。<br />
<br />
用法:<br />
Store store=session.getSorte("pop3");//session为一个邮件会话<br />
store.connect(pop3server,username,password);//通过你提供的pop3地址,用户名和密码登录你的邮箱<br />
<br />
<br />
(7) <a class="Channel_KeyLink" href="http://www.enadd.com/JAVA/Index.html">java</a>x.mail.Folder类<br />
Folder类用于分级组织邮件，并提供照Javax.mail.Message格式访问email的能力。 <br />
<br />
用法:<br />
Folder folder=store.getFolder("INBOX");<br />
folder.open(Folder.READ_ONLY);<br />
<br />
<br />
(8) <a class="Channel_KeyLink" href="http://www.enadd.com/JAVA/Index.html">java</a>x.mail.Internet.MimeMultpart<br />
一般保存电子邮件内容的容器是Multipart抽象类,它定义了增加和删除及获得电子邮件不同部分内容的方法.由于Multipart是抽象类,我们必须为它使用一个具体的子类,JavaMail API提供<a class="Channel_KeyLink" href="http://www.enadd.com/JAVA/Index.html">java</a>x.mail.Internet.MimeMultpart类来使用MimeMessage对象.<br />
<br />
用法:<br />
MimeMultipart multipart=new MimeMultipart();<br />
<br />
注:我们使用MimeMultipart对象的一个方法是addBodyPart(),它在我们的电子邮件内容里添加BodyPart(BodyPart类在下面紧接着要介绍)对象.消息可以有很多部分,一个BodyPart可以代表一个部分.<br />
<br />
<br />
(9) <a class="Channel_KeyLink" href="http://www.enadd.com/JAVA/Index.html">java</a>x.mail.Internet.MimeBodyPart类<br />
<br />
MimeBodyPart是BodyPart具体用于mimeMessage的一个子类.<br />
MimeBodyPart对象代表一个MimeMessage对象内容的一部分.每个MimeBodyPart被认为有两部分:<br />
⊙一个MIME类型 <br />
⊙匹配这个类型的内容<br />
<br />
用法:<br />
MimeBodyPart mdp=new MimeBodyPart();<br />
String text="Hello JavaMail!";<br />
mdp.setContent(text,"text/plain");//定义MIME类型为text/plain,并设置MimeBodyPart的内容.<br />
<br />
<br />
(10) <a class="Channel_KeyLink" href="http://www.enadd.com/JAVA/Index.html">java</a>x.activation.DataHandler类(包含在JAF中)<br />
JavaMail API不限制信息只为文本,任何形式的信息都可能作茧自缚MimeMessage的一部分.除了文本信息,作为文件附件包含在电子邮件信息的一部分是很普遍的.JavaMail API通过使用DataHandler对象,提供一个允许我们包含非文本BodyPart对象的简便方法.<br />
<br />
用法:<br />
DataHandler dh=new DataHandler(text,type);<br />
mdp.setDatahandler(dh);//mdp是一个MimeBodyPart对象<br />
<br />
<br />
(11) <a class="Channel_KeyLink" href="http://www.enadd.com/JAVA/Index.html">java</a>x.activation.FileDataSource类(包含在JAF中)<br />
一个FileDataSource对象可以表示本地文件和服务器可以直接访问的资源.一个本地文件可以通过创建一个新的MimeBodyPart对象附在一个mimeMessage对象上.<br />
<br />
用法:<br />
MimeMultipart mm=new MimeMultipart();<br />
MimeBodyPart mdp=new MimeBodyPart();<br />
FileDataSource fds=new FileDataSource("c:/exam.txt");<br />
mdp.setDataHandler(new DataHandler(fds)); //设置数据源<br />
mm.addBodyPart(mdp); //为当前消息MimeMultipart对象增加MimeBodyPart<br />
<br />
<br />
(12) <a class="Channel_KeyLink" href="http://www.enadd.com/JAVA/Index.html">java</a>x.activation.URLDataSource类(包含在JAF中)<br />
远程资源,URL不会指向它们,由一个URLDataSource对象表示.一个远程资源可以通过创建一个新mimeBodyPart对象附在一个mimeMessage对象上(同FileDataSource差不多).<br />
<br />
用法:<br />
与FileDataSource唯一不同的是数据源的设置:<br />
URLDataSource uds=new URLDataSource("/JAVA/UploadFiles_6441/200703/20070320105128501.gif"); <br />
<br />
<br />
<span style="color: blue"><span style="color: red">4.</span>使用JavaMail API</span><br />
<br />
在明确了JavaMail API的核心部分如何工作后，本人将带领大家学习一些使用Java Mail API任务案例。<br />
1．发送邮件<br />
在获得了Session后，建立并填入邮件信息，然后发送它到邮件服务器。这便是使用Java&nbsp;Mail&nbsp;API发送邮件的过程，在发送邮件之前，我们需要设置SMTP服务器：通过设置Properties的mail.smtp.host属性。<br />
<br />
String&nbsp;host&nbsp;=&nbsp;...;<br />
String&nbsp;from&nbsp;=&nbsp;...;<br />
String&nbsp;to&nbsp;=&nbsp;...;<br />
<br />
//&nbsp;Get&nbsp;system&nbsp;properties<br />
Properties&nbsp;props&nbsp;=&nbsp;System.getProperties();<br />
<br />
//&nbsp;Setup&nbsp;mail&nbsp;server<br />
props.put("mail.smtp.host",&nbsp;host);<br />
<br />
//&nbsp;Get&nbsp;session<br />
Session&nbsp;session&nbsp;=&nbsp;Session.getDefaultInstance(props,&nbsp;null);<br />
<br />
//&nbsp;Define&nbsp;message<br />
MimeMessage&nbsp;message&nbsp;=&nbsp;new&nbsp;MimeMessage(session);<br />
message.setFrom(new&nbsp;InternetAddress(from));<br />
message.addRecipient(Message.RecipientType.TO, new&nbsp;InternetAddress(to));<br />
message.setSubject("Hello&nbsp;JavaMail");<br />
message.setText("Welcome&nbsp;to&nbsp;JavaMail");<br />
<br />
//&nbsp;Send&nbsp;message<br />
Transport.send(message);<br />
由于建立邮件信息和发送邮件的过程中可能会抛出异常，所以我们需要将上面的代码放入到try-catch结构块中。<br />
<br />
2．接收邮件<br />
为了在读取邮件，我们获得了session，并且连接到了邮箱的相应store，打开相应的Folder，然后得到我们想要的邮件，当然别忘记了在结束时关闭连接。<br />
<br />
String&nbsp;host&nbsp;=&nbsp;...;<br />
String&nbsp;username&nbsp;=&nbsp;...;<br />
String&nbsp;password&nbsp;=&nbsp;...;<br />
<br />
//&nbsp;Create&nbsp;empty&nbsp;properties<br />
Properties&nbsp;props&nbsp;=&nbsp;new&nbsp;Properties();<br />
<br />
//&nbsp;Get&nbsp;session<br />
Session&nbsp;session&nbsp;=&nbsp;Session.getDefaultInstance(props,&nbsp;null);<br />
<br />
//&nbsp;Get&nbsp;the&nbsp;store<br />
Store&nbsp;store&nbsp;=&nbsp;session.getStore("pop3");<br />
store.connect(host,&nbsp;username,&nbsp;password);<br />
<br />
//&nbsp;Get&nbsp;folder<br />
Folder&nbsp;folder&nbsp;=&nbsp;store.getFolder("INBOX");<br />
folder.open(Folder.READ_ONLY);<br />
<br />
//&nbsp;Get&nbsp;directory<br />
Message&nbsp;message[]&nbsp;=&nbsp;folder.getMessages();<br />
for&nbsp;(int&nbsp;i=0,&nbsp;n=message.length;&nbsp;i&lt;n;&nbsp;i++)&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp; System.out.println(i&nbsp;+&nbsp;":&nbsp;"&nbsp;+ <br />
&nbsp; message[i].getFrom()[0] +&nbsp;"\t"&nbsp;+&nbsp;message[i].getSubject());<br />
}<br />
<br />
//&nbsp;Close&nbsp;connection <br />
folder.close(false);store.close();<br />
<br />
上面的代码所作的是从邮箱中读取每个邮件，并且显示邮件的发信人地址和主题。从技术角度讲，这里存在着一个异常的可能：当发信人地址为空时，getFrom()[0]将抛出异常。<br />
<br />
下面的代码片断有效的说明了如何读取邮件内容，在显示每个邮件发信人和主题后，将出现用户提示从而得到用户是否读取该邮件的确认，如果输入YES的话，我们可用Message.writeTo(java.io.OutputStream&nbsp;os)方法将邮件内容输出到控制台上，关于 Message.writeTo()的具体用法请看JavaMail&nbsp;API。<br />
<br />
BufferedReader&nbsp;reader&nbsp;=&nbsp;new&nbsp;BufferedReader&nbsp;(new&nbsp;InputStreamReader(System.in));<br />
<br />
//&nbsp;Get&nbsp;directory<br />
Message&nbsp;message[]&nbsp;=&nbsp;folder.getMessages();<br />
for&nbsp;(int&nbsp;i=0,&nbsp;n=message.length;&nbsp;i&lt;n;&nbsp;i++)&nbsp;{<br />
&nbsp; System.out.println(i&nbsp;+&nbsp;":&nbsp;"&nbsp;+&nbsp;message[i].getFrom()[0] +&nbsp;"\t"&nbsp;+&nbsp;message[i].getSubject());<br />
&nbsp; System.out.println("Do&nbsp;you&nbsp;want&nbsp;to&nbsp;read&nbsp;message?&nbsp;"&nbsp;+ "[YES&nbsp;to&nbsp;read/QUIT&nbsp;to&nbsp;end]");&nbsp; <br />
&nbsp; String&nbsp;line&nbsp;=&nbsp;reader.readLine();<br />
&nbsp; if&nbsp;("YES".equals(line))&nbsp;{<br />
&nbsp;&nbsp;&nbsp; message[i].writeTo(System.out);&nbsp; <br />
&nbsp; }&nbsp;else&nbsp;if&nbsp;("QUIT".equals(line))&nbsp;{<br />
&nbsp;&nbsp;&nbsp; break;&nbsp; <br />
&nbsp; }<br />
}<br />
<br />
3．删除邮件和标志<br />
设置与message相关的Flags是删除邮件的常用方法。这些Flags表示了一些系统定义和用户定义的不同状态。在Flags类的内部类Flag中预定义了一些标志：<br />
Flags.Flag.ANSWERED<br />
Flags.Flag.DELETED<br />
Flags.Flag.DRAFT<br />
Flags.Flag.FLAGGED<br />
Flags.Flag.RECENT<br />
Flags.Flag.SEEN<br />
Flags.Flag.USER<br />
但需要在使用时注意的：标志存在并非意味着这个标志被所有的邮件服务器所支持。例如，对于删除邮件的操作，POP协议不支持上面的任何一个。所以要确定哪些标志是被支持的??通过访问一个已经打开的Folder对象的getPermanetFlags()方法，它将返回当前被支持的Flags类对象。<br />
<br />
删除邮件时，我们可以设置邮件的DELETED标志：&nbsp;<br />
message.setFlag(Flags.Flag.DELETED,&nbsp;true);<br />
<br />
但是首先要采用READ_WRITE的方式打开Folder：<br />
folder.open(Folder.READ_WRITE);<br />
<br />
在对邮件进行删除操作后关闭Folder时，需要传递一个true作为对删除邮件的擦除确认。<br />
folder.close(true);<br />
<br />
Folder类中另一种用于删除邮件的方法expunge()也同样可删除邮件，但是它并不为sun提供的POP3实现支持，而其它第三方提供的POP3实现支持或者并不支持这种方法。<br />
另外，介绍一种检查某个标志是否被设置的方法：Message.isSet(Flags.Flag&nbsp;flag)方法，其中参数为被检查的标志。<br />
<br />
4．邮件认证<br />
我们在前面已经学会了如何使用Authenticator类来代替直接使用用户名和密码这两字符串作为 Session.getDefaultInstance()或者Session.getInstance()方法的参数。在前面的小试牛刀后，现在我们将 <br />
<br />
了解到全面认识一下邮件认证。<br />
我们在此取代了直接使用邮件服务器主机名、用户名、密码这三个字符串作为连接到POP3&nbsp;Store的方式，使用存储了邮件服务器主机名信息的属性文件，并在获得Session时传入自定义的Authenticator实例：<br />
<br />
//&nbsp;Setup&nbsp;properties<br />
Properties&nbsp;props&nbsp;=&nbsp;System.getProperties();<br />
props.put("mail.pop3.host",&nbsp;host);<br />
<br />
//&nbsp;Setup&nbsp;authentication,&nbsp;get&nbsp;session<br />
Authenticator&nbsp;auth&nbsp;=&nbsp;new&nbsp;PopupAuthenticator();<br />
Session&nbsp;session&nbsp;=&nbsp;Session.getDefaultInstance(props,&nbsp;auth);<br />
<br />
//&nbsp;Get&nbsp;the&nbsp;storeStore&nbsp;store&nbsp;=&nbsp;session.getStore("pop3");<br />
store.connect();<br />
<br />
PopupAuthenticator 类继承了抽象类Authenticator，并且通过重载Authenticator类的getPasswordAuthentication()方法返回PasswordAuthentication类对象。而getPasswordAuthentication()方法的参数param是以逗号分割的用户名、密码组成的字符串。<br />
<br />
import&nbsp;javax.mail.*;<br />
import&nbsp;java.util.*;<br />
public&nbsp;class&nbsp;PopupAuthenticator&nbsp;extends&nbsp;Authenticator&nbsp;{&nbsp; <br />
public&nbsp;PasswordAuthentication&nbsp;getPasswordAuthentication(String&nbsp;param)&nbsp;{<br />
&nbsp;&nbsp;&nbsp; String&nbsp;username,&nbsp;password;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; StringTokenizer&nbsp;st&nbsp;=&nbsp;new&nbsp;StringTokenizer(param,&nbsp;",");<br />
&nbsp;&nbsp;&nbsp; username&nbsp;=&nbsp;st.nextToken();<br />
&nbsp;&nbsp;&nbsp; password&nbsp;=&nbsp;st.nextToken();<br />
&nbsp;&nbsp;&nbsp; return&nbsp;new&nbsp;PasswordAuthentication(username,&nbsp;password);<br />
&nbsp; }<br />
}<br />
<br />
5．回复邮件<br />
回复邮件的方法很简单：使用Message类的reply()方法，通过配置回复邮件的收件人地址和主题（如果没有提供主题的话，系统将默认将&#8220;Re：&#8221;作为邮件的主体），这里不需要设置任何的邮件内容，只要复制发信人或者reply-to到新的收件人。而reply()方法中的boolean参数表示是否将邮件回复给发送者（参数值为false），或是恢复给所有人（参数值为true）。<br />
补充一下，reply-to地址需要在发信时使用setReplyTo()方法设置。<br />
<br />
MimeMessage&nbsp;reply&nbsp;=&nbsp;(MimeMessage)message.reply(false);<br />
reply.setFrom(new&nbsp;InternetAddress("president@whitehouse.gov"));<br />
reply.setText("Thanks");<br />
Transport.send(reply);<br />
<br />
6．转发邮件<br />
转发邮件的过程不如前面的回复邮件那样简单，它将建立一个转发邮件，这并非一个方法就能做到。<br />
每个邮件是由多个部分组成，每个部分称为一个邮件体部分，是一个BodyPart类对象，对于MIME类型邮件来讲就是MimeBodyPart类对象。这些邮件体包含在成为Multipart的容器中对于MIME类型邮件来讲就是MimeMultiPart类对象。在转发邮件时，我们建立一个文字邮件体部分和一个被转发的文字邮件体部分，然后将这两个邮件体放到一个Multipart中。说明一下，复制一个邮件内容到另一个邮件的方法是仅复制它的 DataHandler（数据处理者）即可。这是由JavaBeans&nbsp;Activation&nbsp;Framework定义的一个类，它提供了对邮件内容的操作命令的访问、管理了邮件内容操作，是不同的数据源和数据格式之间的一致性接口。<br />
<br />
//&nbsp;Create&nbsp;the&nbsp;message&nbsp;to&nbsp;forward<br />
Message&nbsp;forward&nbsp;=&nbsp;new&nbsp;MimeMessage(session);<br />
<br />
//&nbsp;Fill&nbsp;in&nbsp;headerforward.setSubject("Fwd:&nbsp;"&nbsp;+&nbsp;message.getSubject());<br />
forward.setFrom(new&nbsp;InternetAddress(from));<br />
forward.addRecipient(Message.RecipientType.TO,&nbsp;&nbsp;&nbsp;new&nbsp;InternetAddress(to));<br />
<br />
//&nbsp;Create&nbsp;your&nbsp;new&nbsp;message&nbsp;part<br />
BodyPart&nbsp;messageBodyPart&nbsp;=&nbsp;new&nbsp;MimeBodyPart();<br />
messageBodyPart.setText(&nbsp;&nbsp;"Here&nbsp;you&nbsp;go&nbsp;with&nbsp;the&nbsp;original&nbsp;message:\n\n");<br />
<br />
//&nbsp;Create&nbsp;a&nbsp;multi-part&nbsp;to&nbsp;combine&nbsp;the&nbsp;parts<br />
Multipart&nbsp;multipart&nbsp;=&nbsp;new&nbsp;MimeMultipart();<br />
multipart.addBodyPart(messageBodyPart);<br />
<br />
//&nbsp;Create&nbsp;and&nbsp;fill&nbsp;part&nbsp;for&nbsp;the&nbsp;forwarded&nbsp;contentmessage<br />
BodyPart&nbsp;=&nbsp;new&nbsp;MimeBodyPart();<br />
messageBodyPart.setDataHandler(message.getDataHandler());<br />
<br />
//&nbsp;Add&nbsp;part&nbsp;to&nbsp;multi&nbsp;part<br />
multipart.addBodyPart(messageBodyPart);<br />
<br />
//&nbsp;Associate&nbsp;multi-part&nbsp;with&nbsp;message<br />
forward.setContent(multipart);<br />
<br />
//&nbsp;Send&nbsp;message<br />
Transport.send(forward);<br />
<br />
7．使用附件<br />
附件作为与邮件相关的资源经常以文本、表格、图片等格式出现，如流行的邮件客户端一样，我们可以用JavaMail&nbsp;API从邮件中获取附件或是发送带有附件的邮件。<br />
<br />
A．发送带有附件的邮件<br />
发送带有附件的邮件的过程有些类似转发邮件，我们需要建立一个完整邮件的各个邮件体部分，在第一个部分（即我们的邮件内容文字）后，增加一个具有DataHandler的附件而不是在转发邮件时那样复制第一个部分的DataHandler。<br />
<br />
如果我们将文件作为附件发送，那么要建立FileDataSource类型的对象作为附件数据源；如果从URL读取数据作为附件发送，那么将要建立URLDataSource类型的对象作为附件数据源。<br />
<br />
然后将这个数据源（FileDataSource或是URLDataSource）对象作为DataHandler类构造方法的参数传入，从而建立一个DataHandler对象作为数据源的DataHandler。<br />
<br />
接着将这个DataHandler设置为邮件体部分的DataHandler。这样就完成了邮件体与附件之间的关联工作，下面的工作就是BodyPart的setFileName()方法设置附件名为原文件名。<br />
<br />
最后将两个邮件体放入到Multipart中，设置邮件内容为这个容器Multipart，发送邮件。<br />
<br />
//&nbsp;Define&nbsp;message<br />
Message&nbsp;message&nbsp;=&nbsp;new&nbsp;MimeMessage(session);<br />
message.setFrom(new&nbsp;InternetAddress(from));<br />
message.addRecipient(Message.RecipientType.TO, new&nbsp;InternetAddress(to));<br />
message.setSubject("Hello&nbsp;JavaMail&nbsp;Attachment");<br />
<br />
//&nbsp;Create&nbsp;the&nbsp;message&nbsp;part&nbsp;BodyPart&nbsp;message<br />
BodyPart&nbsp;=&nbsp;new&nbsp;MimeBodyPart();<br />
<br />
//&nbsp;Fill&nbsp;the&nbsp;message<br />
messageBodyPart.setText("Pardon&nbsp;Ideas");<br />
Multipart&nbsp;multipart&nbsp;=&nbsp;new&nbsp;MimeMultipart();<br />
multipart.addBodyPart(messageBodyPart);<br />
<br />
//&nbsp;Part&nbsp;two&nbsp;is&nbsp;attachment<br />
messageBodyPart&nbsp;=&nbsp;new&nbsp;MimeBodyPart();<br />
DataSource&nbsp;source&nbsp;=&nbsp;new&nbsp;FileDataSource(filename);<br />
messageBodyPart.setDataHandler(new&nbsp;DataHandler(source));<br />
messageBodyPart.setFileName(filename);<br />
multipart.addBodyPart(messageBodyPart);<br />
<br />
//&nbsp;Put&nbsp;parts&nbsp;in&nbsp;message<br />
message.setContent(multipart);<br />
<br />
//&nbsp;Send&nbsp;the&nbsp;message<br />
Transport.send(message);<br />
<br />
如果我们使用servlet实现发送带有附件的邮件，则必须上传附件给servlet，这时需要注意提交页面form中对编码类型的设置应为multipart/form-data。<br />
<br />
&lt;FORM&nbsp;ENCTYPE="multipart/form-data" method="post" action="/myservlet"&gt;<br />
&nbsp;&nbsp; &lt;INPUT&nbsp;TYPE="file"&nbsp;NAME="thefile"&gt;<br />
&nbsp; &lt;INPUT&nbsp;TYPE="submit"&nbsp;VALUE="Upload"&gt;<br />
&lt;/FORM&gt;<br />
<br />
B．读取邮件中的附件<br />
读取邮件中的附件的过程要比发送它的过程复杂一点。因为带有附件的邮件是多部分组成的，我们必须处理每一个部分获得邮件的内容和附件。<br />
但是如何辨别邮件信息内容和附件呢？Sun在Part类（BodyPart类实现的接口类）中提供了getDisposition()方法让开发者获得邮件体部分的部署类型，当该部分是附件时，其返回之将是Part.ATTACHMENT。但附件也可以没有部署类型的方式存在或者部署类型为 Part.INLINE，无论部署类型为Part.ATTACHMENT还是Part.INLINE，我们都能把该邮件体部分导出保存。<br />
<br />
Multipart&nbsp;mp&nbsp;=&nbsp;(Multipart)message.getContent();<br />
for&nbsp;(int&nbsp;i=0,&nbsp;n=multipart.getCount();&nbsp;i&lt;n;&nbsp;i++)&nbsp;{<br />
&nbsp; Part&nbsp;part&nbsp;=&nbsp;multipart.getBodyPart(i));<br />
&nbsp; String&nbsp;disposition&nbsp;=&nbsp;part.getDisposition();<br />
&nbsp; if&nbsp;((disposition&nbsp;!=&nbsp;null)&nbsp;&amp;&amp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ((disposition.equals(Part.ATTACHMENT)&nbsp;||<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (disposition.equals(Part.INLINE)))&nbsp;{<br />
&nbsp;&nbsp;&nbsp; saveFile(part.getFileName(),&nbsp;part.getInputStream());<br />
&nbsp; }<br />
}<br />
<br />
下列代码中使用了saveFile方法是自定义的方法，它根据附件的文件名建立一个文件，如果本地磁盘上存在名为附件的文件，那么将在文件名后增加数字表示区别。然后从邮件体中读取数据写入到本地文件中（代码省略）。<br />
<br />
//&nbsp;from&nbsp;saveFile()<br />
File&nbsp;file&nbsp;=&nbsp;new&nbsp;File(filename);<br />
for&nbsp;(int&nbsp;i=0;&nbsp;file.exists();&nbsp;i++)&nbsp;{<br />
&nbsp; file&nbsp;=&nbsp;new&nbsp;File(filename+i);<br />
}<br />
<br />
以上是邮件体部分被正确设置的简单例子，如果邮件体部分的部署类型为null，那么我们通过获得邮件体部分的MIME类型来判断其类型作相应的处理，代码结构框架如下：<br />
<br />
if&nbsp;(disposition&nbsp;==&nbsp;null)&nbsp;{<br />
&nbsp; //&nbsp;Check&nbsp;if&nbsp;plain&nbsp; <br />
&nbsp; MimeBodyPart&nbsp;mbp&nbsp;=&nbsp;(MimeBodyPart)part;<br />
&nbsp; if&nbsp;(mbp.isMimeType("text/plain"))&nbsp;{<br />
&nbsp;&nbsp;&nbsp; //&nbsp;Handle&nbsp;plain<br />
&nbsp; }&nbsp;else&nbsp;{<br />
&nbsp;&nbsp;&nbsp; //&nbsp;Special&nbsp;non-attachment&nbsp;cases&nbsp;here&nbsp;of<br />
&nbsp;&nbsp;&nbsp; //&nbsp;image/gif,&nbsp;text/html<br />
&nbsp;&nbsp;&nbsp; ...<br />
&nbsp; }<br />
&nbsp; ...<br />
}<br />
<br />
8．处理HTML邮件<br />
前面的例子中发送的邮件都是以文本为内容的（除了附件），下面将介绍如何接收和发送基于HTML的邮件。<br />
A．发送HTML邮件<br />
假如我们需要发送一个HTML文件作为邮件内容，并使邮件客户端在读取邮件时获取相关的图片或者文字的话，只要设置邮件内容为html代码，并设置内容类型为text/html即可：<br />
<br />
String&nbsp;htmlText&nbsp;=&nbsp;"&lt;H1&gt;Hello&lt;/H1&gt;" + "&lt;img&nbsp;src=\"http://www.jguru.com/images/logo.gif\"&gt;";<br />
message.setContent(htmlText,&nbsp;"text/html"));<br />
<br />
请注意：这里的图片并不是在邮件中内嵌的，而是在URL中定义的。邮件接收者只有在线时才能看到。<br />
在接收邮件时，如果我们使用JavaMail&nbsp;API接收邮件的话是无法实现以HTML方式显示邮件内容的。因为JavaMail&nbsp;API邮件内容视为二进制流。所以要显示HTML内容的邮件，我们必须使用JEditorPane或者第三方HTML展现组件。<br />
<br />
以下代码显示了如何使用JEditorPane显示邮件内容：<br />
if&nbsp;(message.getContentType().equals("text/html"))&nbsp;{<br />
&nbsp; String&nbsp;content&nbsp;=&nbsp;(String)message.getContent();<br />
&nbsp; JFrame&nbsp;frame&nbsp;=&nbsp;new&nbsp;JFrame();<br />
&nbsp; JEditorPane&nbsp;text&nbsp;=&nbsp;new&nbsp;JEditorPane("text/html",&nbsp;content);<br />
&nbsp; text.setEditable(false);<br />
&nbsp; JScrollPane&nbsp;pane&nbsp;=&nbsp;new&nbsp;JScrollPane(text);<br />
&nbsp; frame.getContentPane().add(pane);<br />
&nbsp; frame.setSize(300,&nbsp;300);<br />
&nbsp; frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);<br />
&nbsp; frame.show();<br />
}<br />
<br />
B．在邮件中包含图片<br />
如果我们在邮件中使用HTML作为内容，那么最好将HTML中使用的图片作为邮件的一部分，这样无论是否在线都会正确的显示HTML中的图片。处理方法就是将HTML中用到的图片作为邮件附件并使用特殊的cid&nbsp;URL作为图片的引用，这个cid就是对图片附件的Content-ID头的引用。<br />
处理内嵌图片就像向邮件中添加附件一样，不同之处在于我们必须通过设置图片附件所在的邮件体部分的header中Content-ID为一个随机字符串，并在HTML中img的src标记中设置为该字符串。这样就完成了图片附件与HTML的关联。<br />
<br />
String&nbsp;file&nbsp;=&nbsp;...;<br />
//&nbsp;Create&nbsp;the&nbsp;message<br />
Message&nbsp;message&nbsp;=&nbsp;new&nbsp;MimeMessage(session);<br />
<br />
//&nbsp;Fill&nbsp;its&nbsp;headers<br />
message.setSubject("Embedded&nbsp;Image");<br />
message.setFrom(new&nbsp;InternetAddress(from));<br />
message.addRecipient(Message.RecipientType.TO, new&nbsp;InternetAddress(to));<br />
<br />
//&nbsp;Create&nbsp;your&nbsp;new&nbsp;message&nbsp;part<br />
BodyPart&nbsp;messageBodyPart&nbsp;=&nbsp;new&nbsp;MimeBodyPart();<br />
String&nbsp;htmlText&nbsp;=&nbsp;"&lt;H1&gt;Hello&lt;/H1&gt;"&nbsp;+ "&lt;img&nbsp;src=\"cid:memememe\"&gt;";<br />
messageBodyPart.setContent(htmlText,&nbsp;"text/html");<br />
<br />
//&nbsp;Create&nbsp;a&nbsp;related&nbsp;multi-part&nbsp;to&nbsp;combine&nbsp;the&nbsp;parts<br />
MimeMultipart&nbsp;multipart&nbsp;=&nbsp;new&nbsp;MimeMultipart("related");<br />
multipart.addBodyPart(messageBodyPart);<br />
<br />
//&nbsp;Create&nbsp;part&nbsp;for&nbsp;the&nbsp;image<br />
messageBodyPart&nbsp;=&nbsp;new&nbsp;MimeBodyPart();<br />
<br />
//&nbsp;Fetch&nbsp;the&nbsp;image&nbsp;and&nbsp;associate&nbsp;to&nbsp;part<br />
DataSource&nbsp;fds&nbsp;=&nbsp;new&nbsp;FileDataSource(file);<br />
messageBodyPart.setDataHandler(new&nbsp;DataHandler(fds));<br />
messageBodyPart.setHeader("Content-ID","&lt;memememe&gt;");<br />
<br />
//&nbsp;Add&nbsp;part&nbsp;to&nbsp;multi-part<br />
multipart.addBodyPart(messageBodyPart);<br />
<br />
//&nbsp;Associate&nbsp;multi-part&nbsp;with <br />
messagemessage.setContent(multipart);<br />
<br />
9．在邮件中搜索短语<br />
JavaMail&nbsp;API提供了过滤器机制，它被用来建立搜索短语。这个短语由javax.mail.search包中的SearchTerm抽象类来定义，在定义后我们便可以使用Folder的Search()方法在Folder中查找邮件：<br />
SearchTerm&nbsp;st&nbsp;=&nbsp;...;Message[]&nbsp;msgs&nbsp;=&nbsp;folder.search(st);<br />
下面有22个不同的类（继承了SearchTerm类）供我们使用：<br />
AND&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; terms&nbsp;(class&nbsp;AndTerm)<br />
OR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; terms&nbsp;(class&nbsp;OrTerm)<br />
NOT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; terms&nbsp;(class&nbsp;NotTerm)<br />
SENT&nbsp;DATE&nbsp;terms&nbsp;(class&nbsp;SentDateTerm)<br />
CONTENT&nbsp;&nbsp; terms&nbsp;(class&nbsp;BodyTerm)<br />
HEADER&nbsp;&nbsp;&nbsp; terms&nbsp;(FromTerm&nbsp;/&nbsp;FromStringTerm, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RecipientTerm&nbsp;/&nbsp;RecipientStringTerm,&nbsp;SubjectTerm,&nbsp;etc.)<br />
使用这些类定义的断语集合，我们可以构造一个逻辑表达式，并在Folder中进行搜索。下面是一个实例：在Folder中搜索邮件主题含有&#8220;ADV&#8221;字符串或者发信人地址为friend@public.com的邮件。<br />
<br />
SearchTerm&nbsp;st&nbsp;= new&nbsp;OrTerm(new&nbsp;SubjectTerm("ADV:"), new&nbsp;FromStringTerm("friend@public.com"));<br />
Message[]&nbsp;msgs&nbsp;=&nbsp;folder.search(st);<br />
<img src ="http://www.blogjava.net/AstroQi/aggbug/211873.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/AstroQi/" target="_blank">Astro.Qi</a> 2008-07-01 13:42 <a href="http://www.blogjava.net/AstroQi/archive/2008/07/01/211873.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Apache James 用户信息的数据库存储和密码问题</title><link>http://www.blogjava.net/AstroQi/archive/2008/06/26/210784.html</link><dc:creator>Astro.Qi</dc:creator><author>Astro.Qi</author><pubDate>Thu, 26 Jun 2008 03:55:00 GMT</pubDate><guid>http://www.blogjava.net/AstroQi/archive/2008/06/26/210784.html</guid><wfw:comment>http://www.blogjava.net/AstroQi/comments/210784.html</wfw:comment><comments>http://www.blogjava.net/AstroQi/archive/2008/06/26/210784.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/AstroQi/comments/commentRss/210784.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/AstroQi/services/trackbacks/210784.html</trackback:ping><description><![CDATA[<div id="blog_text" class="cnt">
<h5>一、James简介</h5>
<p>Apache James（Java Apache Mail Enterprise Server）是Apache组织的子项目之一，完全采用纯Java技术开发，实现了SMTP、POP3与NNTP等多种邮件相关协议。</p>
<p>James也是一个邮件应用平台，可以通过Mailet扩充其功能，如Mail2SMS、Mail2Fax等。James提供了比较完善的配置方案，尤其是关于邮件内容存储和用户信息存储部分，可以选择在文件、数据库或其他介质中保存。</p>
<p>James性能稳定、可配置性强，还是开源项目，所有源代码不存在版权问题，因此，James在项目中的应用日益广泛，现在常用版本为2.1，但最新版本2.3已经推出，在本文中，我们将仍以James2.1作为介绍蓝本。</p>
<h5>二、一个假设的项目</h5>
<p>假设我要以James为邮件服务器，开发一套基于Web的邮件系统，就像263.net，163.net一样，要求实现在线注册、在线收发邮件等功能。</p>
<p>默认情况下，James的用户信息存储在文本中，虽然加了密，但由于文本存档不足，不便于查询及相应处理，幸好James提供了多种用户信息存储方案，如数据库存储，LDAP存储等。</p>
<p>这里我们将以数据库存储为例，讲解用户信息的管理，数据库采用MySQL。当然你也可以采用LDAP，比如免费的OpenLDAP，功能非常强大。</p>
<h5>三、用户信息的数据库存储</h5>
<p><span style="color: red;">James邮件用户的用户信息默认保存在apps\james\var\users目录下，通过修改配置文件apps\james\SAR-INF\config.xml，可以把用户信息保存到数据库中，配置方法如下：</span></p>
<p>第一步：在MySQL中新建一个数据库mail，用户名root，密码为空；</p>
<p>第二步：打开config.xml，找到&lt;users-store&gt;这一项，此面默认的内容为：</p>
<p>
<table bgcolor="#d9d9d9" border="1" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td class="text1" valign="top" width="537">&lt;repository name="LocalUsers" class="org.apache.james.userrepository.UsersFileRepository"&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;destination URL="file://var/users/"/&gt;<br />
            &lt;/repository&gt;</td>
        </tr>
    </tbody>
</table>
</p>
<p>需要修改为：</p>
<p>
<table class="text1" bgcolor="#d9d9d9" border="1" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td valign="top" width="537">&lt;repository
            name="LocalUsers"
            class="org.apache.james.userrepository.JamesUsersJdbcRepository"
            destinationURL="db://maildb/users"&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   &lt;sqlFile&gt;file://conf/sqlResources.xml&lt;/sqlFile&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;/repository&gt;</td>
        </tr>
    </tbody>
</table>
</p>
<p>通过修改，我们就把用户信息的存储介质从file改成了db，&lt;sqlFile&gt;是指明了在db中的数据表结构及相关数据库信息。</p>
<p>第三步：仍然是config.xml，找到&lt;data-sources&gt;项，默认内容为空，把此项内容修改为：</p>
<p>
<table class="text1" bgcolor="#d9d9d9" border="1" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td valign="top" width="537">&lt;data-source name="maildb" class="org.apache.james.util.mordred.JdbcDataSource"&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;driver&gt;org.gjt.mm.mysql.Driver&lt;/driver&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;dburl&gt;jdbc:mysql://127.0.0.1/mail&lt;/dburl&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;user&gt;root&lt;/user&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;password&gt;&lt;/password&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;max&gt;20&lt;/max&gt;<br />
            &lt;/data-source&gt;</td>
        </tr>
    </tbody>
</table>
</p>
<p>&lt;driver&gt;是指MySQL的JDBC驱动，&lt;dburl&gt;指数据库的访问路径，IP后的mail即MySQL中新建数据库名，接下来是用户名、密码及最大连接数。</p>
<p>至此，数据库配置完成，启动James，若正常无误，请通过telnet添加一个新用户，比如adduser holen
123456，然后检查MySQL中的mail数据库，下面将有一个表users，这是James根据james_home\apps\james\conf的内容创建的。</p>
<p>通过以上配置，James的用户信息就可以保存在数据库中了。</p>
<h5>四、密码问题<br />
</h5>
<p>当你通过telnet添加新用户时，比如adduser holen
123456，你可以查看数据库中的记录，第一个字段是holen，第二字段是密码，但密码并非123456，而一串&#8220;乱码
&#8221;（zhwQUMTwdMqWfm/h0biB51Gf）——这是加密码后的密码内容，再看后面的字段是&#8220;SHA&#8221;，显然用的是SHA加密方式。</p>
<p>通过telnet方式添加新用户，用户密码将自动加密，然后插入数据库中。但通过telnet方式进行用户管理有着诸多不便，尽管你可以借助James的一个RMI工具包，提高效率，但仍然没有本质改变，当需要用作商业用途时，你更不能要求你的客户熟记那一堆命令符。</p>
<p>一般我们可以做一个Web前端，通过网页形式，添加修改用户，界面友好，傻瓜化使用，如263或163一样。若这样做，我们就需要直接操作数据库，
添加用户记录或修改删除用户记录了。但别忘了，James默认对用户密码是加密的，既然我们要直接操作数据库，那么我们只有两个选择：要么我们研究其密码
机制，添加记录时，我们对新增用户的密码进行同样加密，要么我们去掉James的加密机制，使其明码保存。</p>
<p>幸好，这两种选择都是可行的。我们从Apache网站下载James的源码包，下载后的文件为james-2.1-src.zip，接近8M，通过分析源码，我们发现，<span style="color: red;">与用户密码相关的文件是DefaultUser.java</span>，部分源码如下：</p>
<p>
<table class="text1" bgcolor="#d9d9d9" border="1" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td valign="top" width="537">package org.apache.james.userrepository;<br />
            &#8230;&#8230;<br />
            /**<br />
            &nbsp;&nbsp;&nbsp;&nbsp;  *  Method to verify passwords. <br />
            &nbsp;&nbsp;&nbsp;&nbsp;  *<br />
            &nbsp;&nbsp;&nbsp;&nbsp;  * @param pass the String that is claimed to be the password for this user<br />
            &nbsp;&nbsp;&nbsp;&nbsp;  * @return true if the hash of pass with the current algorithm matches<br />
            &nbsp;&nbsp;&nbsp;&nbsp;  * the stored hash.<br />
            &nbsp;&nbsp;&nbsp;&nbsp;  */<br />
            &nbsp;&nbsp;&nbsp;  public boolean verifyPassword(String pass) {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  try {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  String hashGuess = DigestUtil.digestString(pass, algorithm);<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return hashedPassword.equals(hashGuess);<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  } catch (NoSuchAlgorithmException nsae) {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  throw new RuntimeException("Security error: " + nsae);<br />
            &nbsp;&nbsp;&nbsp;  }<br />
            &nbsp;&nbsp;&nbsp;  }<br />
            <br />
            &nbsp;&nbsp;&nbsp;  /**<br />
            &nbsp;&nbsp;&nbsp;&nbsp;  * Sets new password from String. No checks made on guessability of<br />
            &nbsp;&nbsp;&nbsp;&nbsp;  * password.<br />
            &nbsp;&nbsp;&nbsp;&nbsp;  *<br />
            &nbsp;&nbsp;&nbsp;&nbsp;  * @param newPass the String that is the new password.<br />
            &nbsp;&nbsp;&nbsp;&nbsp;  * @return true if newPass successfuly hashed<br />
            &nbsp;&nbsp;&nbsp;&nbsp;  */<br />
            &nbsp;&nbsp;&nbsp;  public boolean setPassword(String newPass) {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  try {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  hashedPassword = DigestUtil.digestString(newPass, algorithm);<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return true;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  } catch (NoSuchAlgorithmException nsae) {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  throw new RuntimeException("Security error: " + nsae);<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }<br />
            }<br />
            &#8230;&#8230;</td>
        </tr>
    </tbody>
</table>
</p>
<p> </p>
<p>第一个方法verifyPassword()是用来做密码认证，传入的参数是明文密码，通过DigestUtil.digestString()方
法，转换成密文密码，然后与数据库中密码作比较，返回比较结果。请注意这里的DigestUtil.digestString()方法，在后面还在提到。</p>
<p>第二个方法setPassword()是用于密码转换的，把明文转成密文，用的同样是DigestUtil.digestString()方法。</p>
<p>谈到这里，相信你应该知道怎么在自己的程序中进行密码转换和密码认证了吧！其实并不是要你自己去写一个SHA的加密算法，既然James已经提供了此功能，你调用便是了。</p>
<p>还有一种情况，开发者需要在数据库中必须用明文保存密码，这样就不必在自己写的程序中进行密码转换了，而且当多个应用系统采用统一用户模型时，最好
只有一个用户实例。要实现这个需求，就只能修改James源代码了，把verifyPassword()方法和setPassword()改成：</p>
<p> </p>
<p>
<table class="text1" bgcolor="#d9d9d9" border="1" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td valign="top" width="537">public boolean verifyPassword(String pass) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  <br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return hashedPassword.equals(pass);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  <br />
            }&nbsp;&nbsp;  <br />
            public boolean setPassword(String newPass) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  <br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  hashedPassword = newPass;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return true;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  <br />
            }</td>
        </tr>
    </tbody>
</table>
</p>
<p>其实就是把转换过程去掉，保存和认证就都采用明文进行了。</p>
<p>你要是觉得SHA方式不妥，也可以挂接别的加密方式，同样是修改这两个方法。</p>
<p>注意，当你修改了James的源码后，你需要用Ant重新build
James项目，build后将在james-2.1-src\dist\james-2.1\apps下面找到新生成的james.sar文件。把该文
件覆盖James原来james.sar，并删除与james.sar同级的james目录，重启动james即可。建议保留原来的
config.xml，免得又配一次。</p>
<p>通过以上探讨，我们明白了如何通过Web方式进行用户注册和用户登记等。需要说明一点是，James自动生成的users表中只有7个字段，而且都
是系统需要使用的。一般注册时需要输入的信息项比较多，这时建议开发者自己再建一个新表USERINFO，用username把两个表关联起来，不建议修
改users表的内容（如果想试试，请参考<a href="file://conf/sqlResources.xml">james_home\apps\james\conf</a>）。</p>
<h5>五、基于James的邮件系统开发方案简述</h5>
<p><br />
</p>
<p>James运行在Win2000上，客户端采用Web界面（仿263风格）、Foxmail或OutLook Express，该系统主要面向1000人以下的中小企业。</p>
<p>基于James的邮件开发，主要包括两个方面：一是邮件系统的后台管理，另一个是客户端应用系统。</p>
<p>后台管理的功能主要包括用户的添加、删除、修改、用户使用空间指配、邮件备份等。</p>
<p>Web客户端功能包括收件箱、发邮件、发件箱、草稿箱、回收站、地址本、自定义文件夹、配置等。</p>
<p>用户信息存储在MySQL数据库中，邮件内容默认存储在文档中。</p>
<p>系统采用Struts架构，运行环境为Apache1.3+Tomcat4.1，数据库连接池采用Tomcat自带的DBCP。</p>
<p>系统开发预计需60人天完成，开发人员需要掌握Struts和JavaMail。</p>
<p>压力测试超过50个并发。</p>
<h5>六、参考资料</h5>
<p>James 2.1 Documentation</p>
</div>
<img src ="http://www.blogjava.net/AstroQi/aggbug/210784.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/AstroQi/" target="_blank">Astro.Qi</a> 2008-06-26 11:55 <a href="http://www.blogjava.net/AstroQi/archive/2008/06/26/210784.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Apache james 使用入门</title><link>http://www.blogjava.net/AstroQi/archive/2008/06/26/210781.html</link><dc:creator>Astro.Qi</dc:creator><author>Astro.Qi</author><pubDate>Thu, 26 Jun 2008 03:52:00 GMT</pubDate><guid>http://www.blogjava.net/AstroQi/archive/2008/06/26/210781.html</guid><wfw:comment>http://www.blogjava.net/AstroQi/comments/210781.html</wfw:comment><comments>http://www.blogjava.net/AstroQi/archive/2008/06/26/210781.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/AstroQi/comments/commentRss/210781.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/AstroQi/services/trackbacks/210781.html</trackback:ping><description><![CDATA[<div id="blog_text" class="cnt"><span class="t18">
<h5>一、简介</h5>
<p>Apache James（Java Apache Mail Enterprise Server）是Apache组织的子项目之一，完全采用纯Java技术开发，实现了SMTP、POP3与NNTP等多种邮件相关协议。</p>
<p>James也是一个邮件应用平台，可以通过Mailet扩充其功能，如Mail2SMS、Mail2Fax等。James提供了比较完善的配置方案，尤其是关于邮件内容存储和用户信息存储部分，可以选择在文件、数据库或其他介质中保存。</p>
<p>James性能稳定、可配置性强，还是开源项目，所有源代码不存在版权问题，因此，James在项目中的应用日益广泛，现在常用版本为2.1，但最新版本2.3已经推出，在本文中，我们将仍以James2.1作为介绍蓝本。</p>
<h5>二、安装与配置</h5>
<p>James的安装配置过程非常简单。</p>
<p><strong>第一步：安装JDK</strong></p>
<p>请使用JDK1.3以上版本（推荐使用JDK1.4），假设安装在c:\jdk1.3。</p>
<p><strong>第二步：下载James，并解压</strong></p>
<p>可以到Apache网站上下载James2.1，下载将得到一个压缩文件james-2.1.zip，大小为4.45M，将此包解压到c:\james。</p>
<p><strong>第三步：直接运行或需要配置JAVA_HOME</strong></p>
<p>这时，可以尝试直接双击c:\james\bin\run.bat，若启动无误，将提示如下：</p>
<table class="text1" bgcolor="#d9d9d9" border="1" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td valign="top" width="537">Using PHOENIX_HOME: C:\james<br />
            Using PHOENIX_TMPDIR: C:\james\temp<br />
            Using JAVA_HOME:<br />
            <br />
            Phoenix 4.0.1<br />
            <br />
            James 2.1<br />
            Remote Manager Service started plain:4555<br />
            POP3 Service started plain:110<br />
            SMTP Service started plain:25<br />
            NNTP Service Disabled<br />
            Fetch POP Disabled</td>
        </tr>
    </tbody>
</table>
<p> </p>
<p>也有可能启动不了，并报JAVA_HOME找不到，这时，需要指定JAVA_HOME，比较简单的方法是在c:\james\bin\run.bat中指定JAVA_HOME，修改后的run.bat如下：</p>
<table class="text1" bgcolor="#d9d9d9" border="1" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td valign="top" width="537">&#8230;&#8230;<br />
            rem<br />
            rem Determine if JAVA_HOME is set and if so then use it<br />
            rem<br />
            set JAVA_HOME= c:\jdk1.3<br />
            if not "%JAVA_HOME%"=="" goto found_java<br />
            &#8230;&#8230;</td>
        </tr>
    </tbody>
</table>
<p>修改完后再运行run.bat，应该就可以正常启动了，若还有什么问题，请参见本文的FAQ部分。</p>
<h5>三、项目应用</h5>
<p><strong>1、 项目需求</strong></p>
<p>某单位，有16个职能处室，共78台电脑（操作系统为Win98/2000/xp），其中有1台为专用服务器（Win2000），已连成局域网。为使单位内部的信息交流，尤其是文件交互更加便捷，单位决定在局域网内部架设一套E-mail系统。</p>
<p><strong>2、 解决方案</strong></p>
<p>在专用服务器上安装James2.1，客户端使用操作系统自带的Outlook Express。</p>
<p><strong>3、 服务器端配置</strong></p>
<p>首先找出专用服务器的名字，假设叫unitname。</p>
<p>然后打开文件c:\james\apps\james\SAR-INF\config.xml。</p>
<p>在config.xml文件中，找到
<postmaster></postmaster>
Postmaster@localhost，把此项改为
<postmaster></postmaster>
Postmaster@unitname，同理，找到<servername></servername>localhost，把此项改为<servername></servername>unitname。其实，改这两项就是把默认的localhost改为机器名，这样做是为了让其它机器也能访问邮件系统，当然，前提是在局域网上没有与服务器重名的机器。</p>
<p><strong>4、 客户端配置</strong></p>
<p>假设有一个账号，用户名为holen，密码为123456，如何在Outlook中配置呢？</p>
<p>首先，根据用户名，可以得出该用户邮箱地址为<font color="#0000ff">holen@unitname</font> ，然后在输入POP3和SMTP服务器时，直接使用服务器机器名unitname即可。</p>
<p><strong>5、 帐号管理</strong></p>
<p>James的账号管理是通过telnet完成的，登录命令为：</p>
<p>
<table class="text1" bgcolor="#d9d9d9" border="1" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td valign="top" width="568">telnet unitname 4555</td>
        </tr>
    </tbody>
</table>
</p>
<p>其中unitname也可以换成IP，4555是端口号。登录时需要用户名和密码，初始的用户名和密码均为root。若登录成功，提示如下：</p>
<p>
<table class="text1" bgcolor="#d9d9d9" border="1" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td valign="top" width="568">JAMES Remote Administration Tool 2.1<br />
            Please enter your login and password<br />
            Login id:<br />
            Password:<br />
            Welcome root. HELP for a list of commands</td>
        </tr>
    </tbody>
</table>
</p>
<p>需要注意的是，所有敲入的命令都不显示在屏幕上。</p>
<p>输入help，将出现命令的帮助，信息如下：</p>
<p>
<table class="text1" bgcolor="#d9d9d9" border="1" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td valign="top" width="568">JAMES Remote Administration Tool 2.1<br />
            Please enter your login and password<br />
            Login id:<br />
            Password:<br />
            Welcome root. HELP for a list of commands<br />
            Currently implemented commands:<br />
            help display this help<br />
            listusers display existing accounts<br />
            countusers display the number of existing accounts<br />
            adduser [username] [password] add a new user<br />
            verify [username] verify if specified user exist<br />
            deluser [username] delete existing user<br />
            setpassword [username] [password] sets a users password<br />
            setalias [alias] [user] locally forwards all email for alias t<br />
            o user<br />
            unsetalias [alias] unsets an alias<br />
            setforwarding [username] [emailaddress] forwards a users email to another email<br />
            address<br />
            unsetforwarding [username] removes a forward<br />
            user [repositoryname] change to another user repository<br />
            shutdown kills the current JVM (convenient when J<br />
            ames is run as a daemon)<br />
            quit close connection</td>
        </tr>
    </tbody>
</table>
</p>
<p>常用的命令有listusers、countusers、adduser、deluser、setpassword等。</p>
<p>其中添加用户为adduser，例如：adduser holen 123456。</p>
<p>通过这个后台管理界面，管理员就可以实现账号管理及其他相应的管理功能。</p>
<p><strong>6、 应用情况</strong></p>
<p>这套系统在该单位经过一周的试运行后，已正式运行两个月，用户数约百人，一直很稳定，期间，因操作系统故障，服务器重启两次，其他时间，一直处于运行状态，性能稳定，响应速度快。</p>
<h5>四、FAQ</h5>
<p><strong>1、 在启动james时，提示POP3或SMTP不能使用？</strong></p>
<p>请检查一下，看&#8220;管理工具—&gt;服务&#8221;里面，是不是启动了别的邮件服务器，已将110或25端口占用了。</p>
<p><strong>2、 JAVA_HOME找不到？</strong></p>
<p>请在run.bat中指定JAVA_HOME，若还不行，请在&#8220;我的电脑—&gt;系统—&gt;高级—&gt;环境变量&#8221;中添加一项JAVA_HOME（一般不推荐这么做）。</p>
<p><strong>3、 服务器启动正常，但客户端不能收发邮件？</strong></p>
<p>请检查客户端配置是否正常，参照前面所讲，另外，请检查james下的config.xml，是否把localhost改成了机器名。</p>
<h5>五、总结</h5>
<p>总体而言，James是一款十分优秀的邮件服务器，具有性能稳定、扩展性好、可配置性强、响应速度快、源码公开等优点。同时，由于James的后台管理不够方便、缺少必要的技术支持等原因，限制了james的高端企业级应用。</p>
<p>就目前情况而言，James主要用于1000用户量以内的邮件系统，而且当James用于商业性项目时，开发商一般需要对James进行相应的包装，主要是后台管理这一块。</p>
</span></div>
<img src ="http://www.blogjava.net/AstroQi/aggbug/210781.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/AstroQi/" target="_blank">Astro.Qi</a> 2008-06-26 11:52 <a href="http://www.blogjava.net/AstroQi/archive/2008/06/26/210781.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Apache james mailserver + Claros inTouch webmail</title><link>http://www.blogjava.net/AstroQi/archive/2008/06/26/210764.html</link><dc:creator>Astro.Qi</dc:creator><author>Astro.Qi</author><pubDate>Thu, 26 Jun 2008 02:44:00 GMT</pubDate><guid>http://www.blogjava.net/AstroQi/archive/2008/06/26/210764.html</guid><wfw:comment>http://www.blogjava.net/AstroQi/comments/210764.html</wfw:comment><comments>http://www.blogjava.net/AstroQi/archive/2008/06/26/210764.html#Feedback</comments><slash:comments>30</slash:comments><wfw:commentRss>http://www.blogjava.net/AstroQi/comments/commentRss/210764.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/AstroQi/services/trackbacks/210764.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 准备：&nbsp;&nbsp;&nbsp; 环境winxp + jdk1.6 + tomcat6.0.16&nbsp;&nbsp;&nbsp; apache james2.3 (邮件服务器)&nbsp;&nbsp;&nbsp; Claros inTouch2.1.war (WebMail界面程序)function StorePage(){d=document;t=d.selecti...&nbsp;&nbsp;<a href='http://www.blogjava.net/AstroQi/archive/2008/06/26/210764.html'>阅读全文</a><img src ="http://www.blogjava.net/AstroQi/aggbug/210764.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/AstroQi/" target="_blank">Astro.Qi</a> 2008-06-26 10:44 <a href="http://www.blogjava.net/AstroQi/archive/2008/06/26/210764.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>FCKeditor2.6 for JSP 配置方法</title><link>http://www.blogjava.net/AstroQi/archive/2008/06/24/210344.html</link><dc:creator>Astro.Qi</dc:creator><author>Astro.Qi</author><pubDate>Tue, 24 Jun 2008 08:55:00 GMT</pubDate><guid>http://www.blogjava.net/AstroQi/archive/2008/06/24/210344.html</guid><wfw:comment>http://www.blogjava.net/AstroQi/comments/210344.html</wfw:comment><comments>http://www.blogjava.net/AstroQi/archive/2008/06/24/210344.html#Feedback</comments><slash:comments>10</slash:comments><wfw:commentRss>http://www.blogjava.net/AstroQi/comments/commentRss/210344.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/AstroQi/services/trackbacks/210344.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 1、首先登陆www.fckeditor.net/download下载FCKeditor的最新版本，需要下载2个压缩包，一个是基本应用，另一个是在为在jsp下所准备的配置。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FCKeditor 2.6 下载地址：sourceforge.net/project/downloading.php&nbsp;&nbsp;&nbsp;&nbs...&nbsp;&nbsp;<a href='http://www.blogjava.net/AstroQi/archive/2008/06/24/210344.html'>阅读全文</a><img src ="http://www.blogjava.net/AstroQi/aggbug/210344.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/AstroQi/" target="_blank">Astro.Qi</a> 2008-06-24 16:55 <a href="http://www.blogjava.net/AstroQi/archive/2008/06/24/210344.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>