??xml version="1.0" encoding="utf-8" standalone="yes"?>在线观看亚洲精品国产,亚洲AV永久精品爱情岛论坛,亚洲男人电影天堂http://www.tkk7.com/AstroQi/category/32540.htmlI'm Astro Qi. If call me, please send email to closoastroqi@126.comzh-cnThu, 09 Jun 2011 10:01:28 GMTThu, 09 Jun 2011 10:01:28 GMT60?java.nio.ByteBuffer 的理?/title><link>http://www.tkk7.com/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.tkk7.com/AstroQi/archive/2011/05/18/350457.html</guid><wfw:comment>http://www.tkk7.com/AstroQi/comments/350457.html</wfw:comment><comments>http://www.tkk7.com/AstroQi/archive/2011/05/18/350457.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/AstroQi/comments/commentRss/350457.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/AstroQi/services/trackbacks/350457.html</trackback:ping><description><![CDATA[<div><div class="c4aaiwa" 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 id="aoaiyuy" class="Apple-style-span" style="line-height: 1.8em; "><strong style="word-break: break-all; line-height: normal; "><br />今晚用到 ByteBuffer, 我跟 joy 都是初学 <a 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>, 文档里的中文译实在是看他母亲不? 晕了(jin)半天, 作了(jin)几个试, l于把这个类的用法搞清楚? Z臆想?jin)哈其工作原?<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>先列点代码片D?<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; " />// 此段代码功能Z 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 的说明ؓ(f):<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 <ByteBuffer><br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " />q说?ByteBuffer 是承于 Buffer 的抽象类, 实现?jin)两个接?<br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " />? 通过 allocate() 分配?jin)一?1024 字节的缓冲区, q返回一?ByteBuffer 对象. (抽象cM能直?new)<br style="word-break: break-all; line-height: normal; " />? fcin.read() 数据读入到 buff. 此处?read() ?FileChannel cȝ一个虚函数.<br style="word-break: break-all; line-height: normal; " />? buff.flip() q个调用是开头一直无法理解的部分.<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; ">Q然后将该位|设|ؓ(f)零。如果已定义?jin)标讎ͼ则丢弃该标记?br style="word-break: break-all; line-height: normal; " />当将数据从一个地方传输到另一个地Ҏ(gu)Q经常将此方法与 compact Ҏ(gu)一起用?br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " />我最l的理解? 文档译得太差了(jin), 把不应该译的内容也译成?jin)中? 所以反而不Ҏ(gu)理解.<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; ">: q个可以直观地理解ؓ(f)~冲Z的当前数据指? 或是 <a 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> 中的游标, Cؓ(f) curPointer.<br style="word-break: break-all; line-height: normal; " />限制<wbr style="word-break: break-all; line-height: normal; ">: q个可以理解成实际操作的~冲区段的结束标? Cؓ(f) endPointer.<br style="word-break: break-all; line-height: normal; " />反{<wbr style="word-break: break-all; line-height: normal; ">: q个完全是对 flip q个词不负责的翻? 如果参照 DirectX 里的 flip() 而译为翻?页, 那就好理解得? 像写信/看信, ?看完一后, d下一? 眼睛/W从底重新Ud首.<br style="word-break: break-all; line-height: normal; " />q个{背后的操作其实就?"?endPointer 定位?curPointer ? q把 curPointer 设ؓ(f) 0".<br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " />关于标记, 在这里不涉及(qing). 下一句说到常?compact Ҏ(gu)一起? 是可以想像的, 因ؓ(f) compact Ҏ(gu)Ҏ(gu)据进<br style="word-break: break-all; line-height: normal; " />行了(jin)压羃, 有效数据的真实长度发生了(jin)变化, 肯定需要用 flip 重新定位l束标记.<br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " />在填? 压羃{数据操作时, curPointer 估计都是自动更新?jin)位|的, L指向最后一个有效数? 所以每ơ调<br style="word-break: break-all; line-height: normal; " />?flip() ? endPointer 指向了(jin)有效数据的结? ?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           c<br style="word-break: break-all; line-height: normal; " />此时, endPointer 在 0 ? curPointer Ud?jin)数据结?<br style="word-break: break-all; line-height: normal; " />l测? 此时若取数据, 得?5 个字? 内容通常?0 (也有可能是未?, 因ؓ(f)实际上取到的是从 c 处到~冲</span><span id="uemieec" class="Apple-style-span" style="line-height: 1.8em;">区实际结束处?5 个未初始化的字节.</span><span id="8quq4qq" 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 id="igymwoa" class="Apple-style-span" style="line-height: 1.8em;">* 调用一?flip() ?/span><br style="word-break: break-all; line-height: normal; " /><span id="qowkmqe" class="Apple-style-span" style="line-height: 1.8em;">-------------------</span><br style="word-break: break-all; line-height: normal; " /><span id="8ugaeka" 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 id="iyysmg4" class="Apple-style-span" style="line-height: 1.8em;">-------------------</span><br style="word-break: break-all; line-height: normal; " /><span id="mmqcssw" class="Apple-style-span" style="line-height: 1.8em;">c           e</span><br style="word-break: break-all; line-height: normal; " /><span id="oiciwoi" class="Apple-style-span" style="line-height: 1.8em;">此时, endPointer 先被Ud curPointer, 然后 curPointer Ud 0.</span><br style="word-break: break-all; line-height: normal; " /><span id="cekwqeu" class="Apple-style-span" style="line-height: 1.8em;">通过试可见, ByteBuffer 取数据时, 是从 curPointer ? ?endPointer ? ?curPointer > endPointer, 则取到缓冲区l束.</span><br style="word-break: break-all; line-height: normal; " /><span id="akiuao8" 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 id="iimskyu" class="Apple-style-span" style="line-height: 1.8em;">再看上面代码的关键片D? ?8 处调?flip() x两个作用, 一是将 curPointer Ud 0, 二是?endPointer Ud有效数据l尾.</span><br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " /><span id="mq4wswm" class="Apple-style-span" style="line-height: 1.8em;">此行可由以下两行代替:</span><br style="word-break: break-all; line-height: normal; " /><span id="0a44ayq" class="Apple-style-span" style="line-height: 1.8em;">buff.limit( buff.position());</span><br style="word-break: break-all; line-height: normal; " /><span id="8uumcim" 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 id="yaqicsi" 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 id="kyqoegw" class="Apple-style-span" style="line-height: 1.8em;">----------------------------</span><wbr style="word-break: break-all; line-height: normal; "><span id="smgo4cy" 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 id="ammqwym" class="Apple-style-span" style="line-height: 1.8em;">1. put 数据? 不会(x)自动清除~冲Z现有的数?</span><br style="word-break: break-all; line-height: normal; " /><span id="ywwqggk" class="Apple-style-span" style="line-height: 1.8em;">2. 每一?get ?put ? curPointer 都将向缓冲区NUd, Ud?操作的数据量.</span><br style="word-break: break-all; line-height: normal; " /><span id="keaeawy" 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 id="qcqmecg" 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 id="6u4wwac" class="Apple-style-span" style="line-height: 1.8em;">? curPointer ?endPointer 只是为文中方便描q命名的, 实际分别对应?ByteBuffer.position() ?ByteBuffer.limit() 两个Ҏ(gu).</span><br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " /><span id="suqwegu" 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 id="siomuoe" class="Apple-style-span" style="line-height: 1.8em;">curPointer 是用 ByteBuffer.position() 取? ?ByteBuffer.position( int ) 赋? 不知?JDK Z么要用多态来实现q两个功? 按我的想? </span><a 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 id="8emsuwy" 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 id="eeuasmc" 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 id="eyuywou" class="Apple-style-span" style="line-height: 1.8em;">C++ 里面没有cM ByteBuffer 的现成实? 实现上述cM的文件复制功? 通常要自己创?/span><a 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 id="omsay44" class="Apple-style-span" style="line-height: 1.8em;">~冲? C++ 里读写文仉常?FileRead(), FileWrite() 函数, 在读/写的时? 可以直接指定?写的数据长度, 相比下显?/span><br style="word-break: break-all; line-height: normal; " /><span id="g4k4cik" class="Apple-style-span" style="line-height: 1.8em;">直观方便? ?JDK q个 ByteBuffer 的方? 实更方便好?</span><br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " /><span id="2smogmo" class="Apple-style-span" style="line-height: 1.8em;">ByteBuffer 作ؓ(f)l承?Buffer 的抽象类, 实现?jin)?Byte 型缓冲的理, 同时 JDK 里还有对应其他数据类型的</span><br style="word-break: break-all; line-height: normal; " /><span id="ssuegwa" class="Apple-style-span" style="line-height: 1.8em;">l承?Buffer 的抽象类, 分别实现对应cd的缓冲管? q种设计减少?jin)编E时的工? 如果?C++ ? 调用</span><br style="word-break: break-all; line-height: normal; " /><span id="6sgywkk" class="Apple-style-span" style="line-height: 1.8em;">?写函数时, q需要考虑传入数据的类? 通常用传?sizeof(数据cd) 的方式指? 除了(jin)函数调用时增加?/span><br style="word-break: break-all; line-height: normal; " /><span id="sauoeum" 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 id="w4caosu" class="Apple-style-span" style="line-height: 1.8em;">反过来再? Z?C 要用q种方式? 个h认ؓ(f), q是 C 标准库的实现方式, 因ؓ(f)在不?OS q_? Ҏ(gu)件和</span><br style="word-break: break-all; line-height: normal; " /><span id="sioswae" class="Apple-style-span" style="line-height: 1.8em;">讑֤的访问方法在pȝ层不一定相? 同时gq_(主要?CPU)上基本数据类型宽度也有可能不? 标准库通过</span><br style="word-break: break-all; line-height: normal; " /><span id="eecweci" class="Apple-style-span" style="line-height: 1.8em;">sizeof q个宏在~译时才能确定数据宽? 所以标?C 代码通常可以在不同^C重新~译.</span><br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " /><span id="couq4ac" class="Apple-style-span" style="line-height: 1.8em;">再想 C++ Z么要用这U方? 首先, C++ 里沿?C 标准库的模式是可以理解的, 其次, 也许只是 C++ 标准?/span><br style="word-break: break-all; line-height: normal; " /><span id="s8iwsgw" class="Apple-style-span" style="line-height: 1.8em;">里没有类似的设计, 说不定早有W三斚w过模板实现的了(jin).</span><br style="word-break: break-all; line-height: normal; " /><br style="word-break: break-all; line-height: normal; " /><span id="couquwy" class="Apple-style-span" style="line-height: 1.8em;">个h认ؓ(f), ByteBuffer 在实C, 可以是一U数据结? 在类设计? 可以是一U设计模式了(jin).</span></div></div><img src ="http://www.tkk7.com/AstroQi/aggbug/350457.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/AstroQi/" target="_blank">Astro.Qi</a> 2011-05-18 10:53 <a href="http://www.tkk7.com/AstroQi/archive/2011/05/18/350457.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>字符~码详解?qing)由?UNICODE,UTF-8,GBK)http://www.tkk7.com/AstroQi/archive/2010/11/18/338412.htmlAstro.QiAstro.QiThu, 18 Nov 2010 09:51:00 GMThttp://www.tkk7.com/AstroQi/archive/2010/11/18/338412.htmlhttp://www.tkk7.com/AstroQi/comments/338412.htmlhttp://www.tkk7.com/AstroQi/archive/2010/11/18/338412.html#Feedback0http://www.tkk7.com/AstroQi/comments/commentRss/338412.htmlhttp://www.tkk7.com/AstroQi/services/trackbacks/338412.html一直对字符的各U编码方式懵應|懂,什么ANSI、UNICODE、UTF-8、GB2312、GBK、DBCS、UCS……是不是看的很晕,假如(zhn)细l的阅读本文你一定可以清晰的理解他们?br />           
    很久很久以前Q有一hQ他们决定用8个可以开合的晶体来l合成不同的状态,以表CZ界上的万物。他们看?个开关状态是好的Q于是他们把q称?字节"?/p>

    再后来,他们又做?jin)一些可以处理这些字节的机器Q机器开动了(jin)Q可以用字节来组合出很多状态,状态开始变来变厅R他们看到这h好的Q于是它们就q机器称?计算??br />     开始计机只在国用。八位的字节一共可以组合出256(2?ơ方)U不同的状态?nbsp;
    他们把其中的~号?开始的32U状态分别规定了(jin)Ҏ(gu)的用途,一但终端、打印机遇上U定好的q些字节被传q来Ӟp做一些约定的动作。遇?0x10, l端换行,遇上0x07, l端向Z嘟嘟叫,例如遇上0x1b, 打印机就打印反白的字Q或者终端就用彩色显C字母。他们看到这样很好,于是把q些0x20以下的字节状态称?控制??nbsp;
    他们又把所有的I格、标点符受数字、大写字母分别用连l的字节状态表C,一直编C(jin)W?27Pq样计算机就可以用不同字节来存储p的文字了(jin)。大?看到q样Q都感觉很好Q于是大安把这个方案叫?ANSI ?Ascii"~码QAmerican Standard Code for Information InterchangeQ美国信息互换标准代码)(j)。当时世界上所有的计算机都用同L(fng)ASCIIҎ(gu)来保存英文文字?nbsp;
          
    后来Q就像徏造巴比u塔一P世界各地的都开始用计机Q但是很多国家用的不是英文,他们的字母里有许多是ASCII里没有的Qؓ(f)?jin)可以在计算Z存他 们的文字Q他们决定采?27号之后的IZ来表C些新的字母、符Pq加入了(jin)很多画表格时需要用下到的横Uѝ竖Uѝ交叉等形状Q一直把序号~到?jin)最后一 个状?55。从128?55q一늚字符集被U?扩展字符?。从此之后,贪婪的hcd没有新的状态可以用?jin),帝国主义可能没有想到还有第三世界?家的Z也希望可以用到计机吧!

    {中国h们得到计机Ӟ已经没有可以利用的字节状态来表示汉字Q况且有6000多个常用汉字需要保存呢。但是这难不倒智慧的中国人民Q我们不客气地把那些127号之后的奇异W号们直接取消掉, 
    规定Q一个小?27的字W的意义与原来相同,但两个大?27的字W连在一hQ就表示一个汉字,前面的一个字节(他称之ؓ(f)高字节)(j)?xA1用到 0xF7Q后面一个字节(低字节)(j)?xA1?xFEQ这h们就可以l合出大U?000多个体汉字了(jin)。在q些~码里,我们q把数学W号、罗马希腊的 字母、日文的假名们都~进M(jin)Q连?ASCII 里本来就有的数字、标炏V字母都l统重新~了(jin)两个字节长的~码Q这是常说?全角"字符Q而原来在127号以下的那些叫"半角"字符?jin)?nbsp;
      中国人民看到q样很不错,于是把q种汉字Ҏ(gu)叫做 "GB2312"。GB2312 是对 ASCII 的中文扩展?nbsp;
      但是中国的汉字太多了(jin)Q我们很快就发现有许多人的人名没有办法在这里打出来Q特别是某些很会(x)ȝ(ch)别h的国安gh。于是我们不得不l箋?GB2312 没有用到的码位找出来老实不客气地用上?nbsp;
      后来q是不够用,于是q脆不再要求低字节一定是127号之后的内码Q只要第一个字节是大于127固定表C是一个汉字的开始,不管后面跟的是不是扩展字 W集里的内容。结果扩展之后的~码Ҏ(gu)被称?GBK 标准QGBK 包括?GB2312 的所有内容,同时又增加了(jin)q?0000个新的汉字(包括J体字)(j)和符受?nbsp;
      后来数民族也要用电(sh)脑了(jin)Q于是我们再扩展Q又加了(jin)几千个新的少数民族的字,GBK 扩成?jin)GB18030。从此之后,中华民族的文化就可以在计机时代中传承了(jin)?nbsp;
      中国的程序员们看到这一pd汉字~码的标准是好的Q于是通称他们叫做 "DBCS"QDouble Byte Charecter Set 双字节字W集Q。在DBCSpd标准里,最大的特点是两字节长的汉字字符和一字节长的英文字符q存于同一套编码方案里Q因此他们写的程序ؓ(f)?jin)支持中文?理,必须要注意字串里的每一个字节的|如果q个值是大于127的,那么pZ个双字节字符集里的字W出C(jin)。那时候凡是受q加持,?x)编E的计算机僧?们都要每天念下面q个咒语数百遍:(x)

      "一个汉字算两个英文字符Q一个汉字算两个英文字符……"
          
      因ؓ(f)当时各个国家都像中国q样搞出一套自q~码标准Q结果互怹间谁也不懂谁的编码,谁也不支持别人的~码Q连大陆和台湾这样只盔R?50里Q?着同一U语a的兄弟地区,也分别采用了(jin)不同?DBCS ~码Ҏ(gu)——当时的中国人想让电(sh)脑显C汉字,必装上一?汉字pȝ"Q专门用来处理汉字的昄、输入的问题Q但是那个台湄愚昧徏人士写的命E序 必d装另一套支?BIG5  ~码的什?倚天汉字pȝ"才可以用Q装错了(jin)字符pȝQ显C就?x)ؕ了(jin)套Q这怎么办?而且世界民族之林中还有那些一时用不上?sh)脑的穷苦h民,他们的文字又?么办Q?/p>

      真是计算机的巴比伦塔命题啊! 
      正在q时Q大天加百列及(qing)时出C(jin)——一个叫 ISOQ国际标谁化l织Q的国际l织军_着手解册个问题。他们采用的Ҏ(gu)很简单:(x)废了(jin)所有的地区性编码方案,重新搞一个包括了(jin)地球上所有文化、所有字?和符L(fng)~码Q他们打叫?Universal Multiple-Octet Coded Character Set"Q简U?UCS, 俗称 "UNICODE"?nbsp;
      UNICODE 开始制订时Q计机的存储器定w极大地发展了(jin)Q空间再也不成ؓ(f)问题?jin)。于?ISO q接规定必ȝ两个字节Q也是16位来l一表示所有的字符Q对于ascii里的那些“半角”字符QUNICODE 包持其原~码不变Q只是将光度由原来?位扩展ؓ(f)16位,而其他文化和语言的字W则全部重新l一~码。由?半角"英文W号只需要用C8位,所以其?8位永q是0Q因此这U大气的Ҏ(gu)在保存英文文本时?x)多费一倍的I间?/p>

      q时候,从旧C会(x)里走q来的程序员开始发C个奇怪的现象Q他们的strlen函数靠不住了(jin)Q一个汉字不再是相当于两个字W了(jin)Q而是一个!是的Q从 UNICODE 开始,无论是半角的英文字母Q还是全角的汉字Q它们都是统一?一个字W?Q同Ӟ也都是统一?两个字节"Q请注意"字符"?字节"两个术语的不 同,“字节”是一?位的物理存贮单元Q?#8220;字符”则是一个文化相关的W号。在UNICODE 中,一个字W就是两个字节。一个汉字算两个英文字符的时代已l快q去?jin)?nbsp;
          
      从前多种字符集存在时Q那些做多语a软g的公叔R上过很大ȝ(ch)Q他们ؓ(f)?jin)在不同的国安售同一套YӞ׃得不在区域化软g时也加持那个双字节字W集?语,不仅要处处小?j)不要搞错,q要把Y件中的文字在不同的字W集中{来{厅RUNICODE 对于他们来说是一个很好的一揽子解决Ҏ(gu)Q于是从 Windows NT 开始,MS 机把它们的操作pȝ改了(jin)一遍,把所有的核心(j)代码都改成了(jin)?UNICODE 方式工作的版本,从这时开始,W(xu)INDOWS pȝl于无需要加装各U本土语apȝQ就可以昄全世界上所有文化的字符?jin)?nbsp;
    但是QUNICODE 在制订时没有考虑与Q何一U现有的~码Ҏ(gu)保持兼容Q这使得 GBK 与UNICODE 在汉字的内码~排上完全是不一L(fng)Q没有一U简单的术Ҏ(gu)可以把文本内容从UNICODE~码和另一U编码进行{换,q种转换必须通过查表来进行?nbsp;
    如前所qͼUNICODE 是用两个字节来表CZؓ(f)一个字W,他d可以l合?5535不同的字W,q大概已l可以覆盖世界上所有文化的W号。如果还不够也没有关p,ISO已经准备 ?jin)UCS-4Ҏ(gu)Q说单了(jin)是四个字节来表CZ个字W,q样我们可以组合出21亿个不同的字W出来(最高位有其他用途)(j)Q这大概可以用到银河联邦成立 那一天吧Q?br />     UNICODE 来到Ӟ一起到来的q有计算机网l的兴vQUNICODE 如何在网l上传输也是一个必考虑的问题,于是面向传输的众?UTFQUCS Transfer FormatQ标准出C(jin)Q顾名思义QUTF8是每次8个位传输数据Q而UTF16是每次16个位Q只不过Z(jin)传输时的可靠性,从UNICODE?UTF时ƈ不是直接的对应,而是要过一些算法和规则来{换?/p>

    受到q网l编E加持的计算机僧侣们都知道,在网l里传递信息时有一个很重要的问题,是对于数据高低位的解读方式Q一些计机是采用低位先发送的Ҏ(gu)Q例 如我们PC机采用的 INTEL 架构Q而另一些是采用高位先发送的方式Q在|络中交换数据时Qؓ(f)?jin)核对双方对于高低位的认识是否是一致的Q采用了(jin)一U很便的Ҏ(gu)Q就是在文本的开始时 向对方发送一个标志符——如果之后的文本是高位在位,那就发?FEFF"Q反之,则发?FFFE"。不信你可以用二q制方式打开一个UTF-X格式?文gQ看看开头两个字节是不是q两个字节?
    讲到q里Q我们再Z说说一个很著名的奇怪现象:(x)当你?windows 的记事本里新Z个文Ӟ输入"联?两个字之后,保存Q关闭,然后再次打开Q你?x)发现这两个字已l消׃(jin)Q代之的是几个ؕ码!呵呵Q有q就是联通之所以拼不过Ud的原因?/p>

    其实q是因ؓ(f)GB2312~码与UTF8~码产生?jin)编码冲撞的原因?nbsp;
    从网上引来一D从UNICODE到UTF8的{换规则:(x)
                             Unicode           UTF-8
         (0-127)          0000 - 007F     0xxxxxxx

         (128-2047)     0080 - 07FF     110xxxxx 10xxxxxx 

         (2048-65535)  0800 - FFFF     1110xxxx 10xxxxxx 10xxxxxx

    例如"?字的Unicode~码?C49?C49?800-FFFF之间Q所以要?字节模板Q?110xxxx 10xxxxxx 10xxxxxx。将6C49写成二进制是Q?110 1100 0100 1001Q将q个比特按三字节模板的分段Ҏ(gu)分ؓ(f)0110 110001 001001Q依ơ代替模板中的xQ得刎ͼ(x)1110-0110 10-110001 10-001001Q即E6 B1 89Q这是其UTF8的编码?nbsp;
    而当你新Z个文本文件时Q记事本的编码默认是ANSI,如果你在ANSI的编码输入汉字,那么他实际就是GBpd的编码方式,在这U编码下Q?联?的内码是Q?nbsp;
            c1 1100 0001 
            aa 1010 1010 
            cd 1100 1101 
            a8 1010 1000 
          
    注意C(jin)吗?W一二个字节、第三四个字节的起始部分的都?110"?10"Q正好与UTF8规则里的两字节模板是一致的Q于是再ơ打开C本时Q记?本就误认是一个UTF8~码的文Ӟ让我们把W一个字节的110和第二个字节?0LQ我们就得到?00001 101010"Q再把各位对齐,补上前导?Q就得到?0000 0000 0110 1010"Q不好意思,q是UNICODE?06AQ也是写的字?j"Q而之后的两字节用UTF8解码之后?368Q这个字W什么也不是。这?是只?联?两个字的文g没有办法在记事本里正常显C的原因?/p>

    而如果你?联?之后多输入几个字Q其他的字的~码不见得又恰好?10?0开始的字节Q这样再ơ打开ӞC本就不会(x)坚持q是一个utf8~码的文Ӟ而会(x)用ANSI的方式解MQ这时ؕ码又不出C(jin)?br />           
    好了(jin)Q终于可以回{NICO的问题了(jin)Q在数据库里Q有n前缀的字串类型就是UNICODEcdQ这U类型中Q固定用两个字节来表CZ个字W,无论q个字符是汉字还是英文字母,或是别的什么?/p>

    如果你要试"abc汉字"q个串的长度Q在没有n前缀的数据类型里Q这个字串是7个字W的长度Q因Z个汉字相当于两个字符。而在有n前缀的数据类型里Q同L(fng)试串长度的函数会(x)告诉你是5个字W,因ؓ(f)一个汉字就是一个字W?/p>

Astro.Qi 2010-11-18 17:51 发表评论
]]>
SLF4J + logBackhttp://www.tkk7.com/AstroQi/archive/2010/11/17/338255.htmlAstro.QiAstro.QiWed, 17 Nov 2010 06:33:00 GMThttp://www.tkk7.com/AstroQi/archive/2010/11/17/338255.htmlhttp://www.tkk7.com/AstroQi/comments/338255.htmlhttp://www.tkk7.com/AstroQi/archive/2010/11/17/338255.html#Feedback0http://www.tkk7.com/AstroQi/comments/commentRss/338255.htmlhttp://www.tkk7.com/AstroQi/services/trackbacks/338255.html阅读全文

Astro.Qi 2010-11-17 14:33 发表评论
]]>
byte[] to inthttp://www.tkk7.com/AstroQi/archive/2010/11/12/337898.htmlAstro.QiAstro.QiFri, 12 Nov 2010 04:09:00 GMThttp://www.tkk7.com/AstroQi/archive/2010/11/12/337898.htmlhttp://www.tkk7.com/AstroQi/comments/337898.htmlhttp://www.tkk7.com/AstroQi/archive/2010/11/12/337898.html#Feedback0http://www.tkk7.com/AstroQi/comments/commentRss/337898.htmlhttp://www.tkk7.com/AstroQi/services/trackbacks/337898.html
public class NumberBytesUtils {

public static void main(String[] args) {
byte[] bytes = new byte[4];
bytes[0] = (byte) 65;
bytes[1] = (byte) 0;
bytes[2] = (byte) 97;
bytes[3] = (byte) 0;
System.out.println("String: " + new String(bytes));
int iv = bytesToInt(bytes);
float fv = bytesToFloat(bytes);
byte[] bs = intToBytes(iv);
byte[] fs = floatToBytes(fv);
System.out.println("Int: " + iv);
System.out.println("Float: " + fv);
System.out.println("------------");
for (int i = 0; i < bs.length; i++) {
System.out.println(bs[i]);
}
System.out.println("============");
for (int i = 0; i < fs.length; i++) {
System.out.println(fs[i]);
}
System.out.println("============");
System.out.println(bytesToFloat(floatToBytes(-0.45367f)));
System.out.println("************");
// System.out.println(0xff);
// System.out.println(0xff00);
// System.out.println(0xff0000);
// System.out.println(0xff000000);
byte[] bytesL = new byte[8];
System.arraycopy(bytes, 0, bytesL, 0, bytes.length);
bytesL[4] = (byte) 0;
bytesL[5] = (byte) 0;
bytesL[6] = (byte) 0;
bytesL[7] = (byte) 0;
long lv = bytesToLong(bytesL);
double dv = bytesToDouble(bytesL);
byte[] bls = longToBytes(lv);
byte[] dls = doubleToBytes(dv);
System.out.println("Long: " + lv);
System.out.println("Double: " + dv);
System.out.println("----");
for (int i = 0; i < bls.length; i++) {
System.out.println(bls[i]);
}
System.out.println("----");
for (int i = 0; i < dls.length; i++) {
System.out.println(dls[i]);
}
System.out.println("****");
System.out.println(bytesToDouble(doubleToBytes(2.345)));
}
/**
* bytes[3] = value >> 24
* bytes[2] = value >> 16
* bytes[1] = value >>  8
* bytes[0] = value >>  0
* @param value
* @return
*/
public static byte[] intToBytes(int value){
int length = 4;
byte[] bytes = new byte[length];
for (int i = length - 1; i >= 0; i--) {
int offset = i * 8; // 24, 16, 8
bytes[i] = (byte) (value >> offset);
}
return bytes;
}
/**
* bytes[7] = value >> 56
* bytes[6] = value >> 48
* bytes[5] = value >> 40
* bytes[4] = value >> 32
* bytes[3] = value >> 24
* bytes[2] = value >> 16
* bytes[1] = value >>  8
* bytes[0] = value >>  0
* @param value
* @return
*/
public static byte[] longToBytes(long value){
int length = 8;
byte[] bytes = new byte[length];
for (int i = length - 1; i >= 0; i--) {
int offset = i * 8; //56, 48, 40, 32, 24, 16, 8
bytes[i] = (byte) (value >> offset);
}
return bytes;
}

/**
* 操作W?<< 的优先?& ?/div>
* intValue = (bytes[3] & 0xFF) << 24
       | (bytes[2] & 0xFF) << 16
       | (bytes[1] & 0xFF) <<  8
       | (bytes[0] & 0xFF) <<  0
* @param bytes
* @return
*/
public static int bytesToInt (byte[] bytes){
int length = 4;
int intValue = 0;
        for (int i = length - 1; i >= 0; i--) {
         int offset = i * 8; //24, 16, 8
         intValue |= (bytes[i] & 0xFF) << offset;
        }
       return intValue;
}
/**
* 操作W?<< 的优先?& ?/div>
* longValue = (long)(bytes[7] & 0xFF) << 56
        | (long)(bytes[6] & 0xFF) << 48
        | (long)(bytes[5] & 0xFF) << 40
        | (long)(bytes[4] & 0xFF) << 32
        | (long)(bytes[3] & 0xFF) << 24
        | (long)(bytes[2] & 0xFF) << 16
        | (long)(bytes[1] & 0xFF) <<  8
        | (long)(bytes[0] & 0xFF) <<  0
* @param bytes
* @return
*/
public static long bytesToLong (byte[] bytes){
int length = 8;
long longValue = 0;
        for (int i = length - 1; i >= 0; i--) {
         int offset = i * 8; //56, 48, 40, 32, 24, 16, 8
         longValue |= (long)(bytes[i] & 0xFF) << offset; //一定要先强制{换成long型再UM, 因ؓ(f)0xFF为int?/div>
        }
       return longValue;
}
public static float bytesToFloat(byte[] bytes) {
return Float.intBitsToFloat(bytesToInt(bytes));
}
public static double bytesToDouble(byte[] bytes) {
return Double.longBitsToDouble(bytesToLong(bytes));
}
public static byte[] floatToBytes(float value){
return intToBytes(Float.floatToIntBits(value));
}

public static byte[] doubleToBytes(double value){
return longToBytes(Double.doubleToLongBits(value));
}
}
====================================================================================
/**
public static String bytes2HexString(byte[] b) { 
String ret = ""; 
for (int i = 0; i < b.length; i++) { 
String hex = Integer.toHexString(b[ i ] 0xFF); 
if (hex.length() == 1) {
  hex = '0' + hex; 
 
  ret += hex.toUpperCase(); 
 
  return ret; 
 
 上面是将byte[]转化十六q制的字W串,注意q里b[ i ] & 0xFF一个byte?0xFFq行?jin)与q算,
 然后使用Integer.toHexString取得?jin)十六进制字W串,可以看出 b[ i ] & 0xFFq算后得出的仍然
 是个int,那么Z要和 0xFFq行与运呢?
 直接 Integer.toHexString(b[ i ]);,byte{为int不行?{案是不行的. 
 其原因在? 
 1.byte的大ؓ(f)8bits而int的大ؓ(f)32bits 
 2.java的二q制采用的是补码形式 
 
 在这里先温习(fn)下计机基础理论 byte是一个字节保存的Q有8个位Q即8???nbsp;
 8位的W一个位是符号位Q?也就是说
 0000 0001代表的是数字1 
 1000 0000代表的就?1 
 所?/div>
 正数最大ؓ(f)0111 1111Q也是数字127 
 负数最大ؓ(f)1111 1111Q也是数字-128 
 上面说的是二q制原码Q?/div>
 但是在java中采用的是补码的形式Q而不是原码,
 
 下面介绍下什么是补码 
 1、反码:(x)一个数如果是正Q则它的反码与原码相同; 一个数如果是负Q则W号位ؓ(f)1Q其余各位是对原码取反; 
 2、补码:(x)利用溢出Q我们可以将减法变成加法Q?/div>
  对于十进制数Q从9得到5可用减法Q?9Q?Q??/div>
  因ؓ(f)4+6Q?0Q我们可以将6作ؓ(f)4的补敎ͼ改写为加法:(x) 9+6Q?5Q去掉高?Q也是?0Q得?. 
  对于十六q制敎ͼ从c?可用减法Q?cQ?Q??/div>
  因ؓ(f)7+9Q?6 ?作ؓ(f)7的补敎ͼ改写为加法:(x) c+9Q?5Q去掉高?Q也是?6Q得?. 
 
 在计机中,如果我们?个字节表CZ个数Q一个字节有8位,过8位就q?Q在内存中情况ؓ(f)Q? 0000 0000Q,q位1被丢弃?/div>
 所以补码是q样q算的:(x)
  ⑴一个数为正Q则它的原码、反码、补码相?/div>
  ⑵一个数Q高W号位ؓ(f)1Q其余各位是对原码取反,然后整个数加1Q?W号位不变,其余为取反再?)
  -1的原码ؓ(f) 10000001 
  -1的反码ؓ(f) 11111110 ?+ 1 
  -1的补码ؓ(f) 11111111 
  
  0的原码ؓ(f)  00000000 
  0的反码ؓ(f)  11111111 (正零和负零的反码相同) ?+ 1
  0的补码ؓ(f) 100000000Q舍掉打头的1Q正零和负零的补码相同)(j) 
  
  Integer.toHexString的参数是intQ如果不q行&0xffQ那么当一个byte转换成intӞ
  ׃int?2位,而byte只有8位,q时?x)进行补位,补位补的?
  例如Q补?1111111的十q制Cؓ(f)-1Q{换ؓ(f)int时变?1111111 11111111 11111111 11111111
  好多1啊,呵呵Q即 0xff ff ff ff Q但是这个数是不对的Q?/div>
  q种补位׃(x)造成误差。和0xff怸后,?4bits׃(x)被清0?jin),l果对?jin)?L补码11111111)
*/


Astro.Qi 2010-11-12 12:09 发表评论
]]>Java ?byte与char、String互{原理http://www.tkk7.com/AstroQi/archive/2010/11/12/337897.htmlAstro.QiAstro.QiFri, 12 Nov 2010 04:08:00 GMThttp://www.tkk7.com/AstroQi/archive/2010/11/12/337897.htmlhttp://www.tkk7.com/AstroQi/comments/337897.htmlhttp://www.tkk7.com/AstroQi/archive/2010/11/12/337897.html#Feedback0http://www.tkk7.com/AstroQi/comments/commentRss/337897.htmlhttp://www.tkk7.com/AstroQi/services/trackbacks/337897.html阅读全文

Astro.Qi 2010-11-12 12:08 发表评论
]]>
Java Stack栈和Heap堆的区别http://www.tkk7.com/AstroQi/archive/2009/01/20/252025.htmlAstro.QiAstro.QiTue, 20 Jan 2009 03:59:00 GMThttp://www.tkk7.com/AstroQi/archive/2009/01/20/252025.htmlhttp://www.tkk7.com/AstroQi/comments/252025.htmlhttp://www.tkk7.com/AstroQi/archive/2009/01/20/252025.html#Feedback0http://www.tkk7.com/AstroQi/comments/commentRss/252025.htmlhttp://www.tkk7.com/AstroQi/services/trackbacks/252025.html       堆存储:(x) heapstorage    堆存储分配:(x) heapstorage allocation  堆存储管理:(x) heap storage management
        栈编址Q?stack addressing   栈变换:(x)stack transformation  栈存储器Qstack memory  栈单元:(x) stack cell
 
          接着Qȝ在Java里面Heap和Stack分别存储数据的不同?/div>
 
             Heap(?       Stack(?
 JVM中的功能      内存数据?nbsp;                   内存指o(h)?/td>
 存储数据      对象实例(1)  基本数据cd, 指o(h)代码,帔R,对象的引用地址(2)
1. 保存对象实例Q实际上是保存对象实例的属性|属性的cd和对象本w的cd标记{,q不保存对象的方法(Ҏ(gu)是指令,保存在stack中)(j)?br />   
   对象实例在heap中分配好以后Q需要在stack中保存一?字节的heap内存地址Q用来定位该对象实例在heap中的位置Q便于找到该对象实例?/div>
 
2. 基本数据cd包括byte、int、char、long、float、double、boolean和short?br />     函数Ҏ(gu)属于指o(h).
 
 =======================       
  引用|上q泛传?#8220;Java堆和栈的区别”里面对堆和栈的介l;
          "Java 的堆是一个运行时数据?cȝ(对象从中分配I间。这些对象通过new、newarray、anewarray和multianewarray{指令徏 立,它们不需要程序代码来昑ּ的释放。堆是由垃圾回收来负责的Q堆的优势是可以动态地分配内存大小Q生存期也不必事先告诉编译器Q因为它是在q行时动态分 配内存的QJava的垃圾收集器?x)自动收走这些不再用的数据。但~点是,׃要在q行时动态分配内存,存取速度较慢?
        “栈的优势是,存取速度比堆要快Q仅ơ于寄存器,栈数据可以共享。但~点是,存在栈中的数据大与生存期必L定的,~Z灉|性。栈中主要存放一些基? cd的变量(,int, short, long, byte, float, double, boolean, charQ和对象句柄?/strong>
   
         可见Q垃圑֛收GC是针对堆Heap的,而栈因ؓ(f)本n是FILO - first in, last out. 先进后出Q能够自动释放?q样p明白到new创徏的,都是攑ֈ堆HeapQ?/div>

Astro.Qi 2009-01-20 11:59 发表评论
]]>Apache James 收发内外|邮件的配置http://www.tkk7.com/AstroQi/archive/2008/08/25/224181.htmlAstro.QiAstro.QiMon, 25 Aug 2008 07:35:00 GMThttp://www.tkk7.com/AstroQi/archive/2008/08/25/224181.htmlhttp://www.tkk7.com/AstroQi/comments/224181.htmlhttp://www.tkk7.com/AstroQi/archive/2008/08/25/224181.html#Feedback2http://www.tkk7.com/AstroQi/comments/commentRss/224181.htmlhttp://www.tkk7.com/AstroQi/services/trackbacks/224181.html阅读全文

Astro.Qi 2008-08-25 15:35 发表评论
]]>
Web Services Xfirehttp://www.tkk7.com/AstroQi/archive/2008/07/18/215717.htmlAstro.QiAstro.QiFri, 18 Jul 2008 03:45:00 GMThttp://www.tkk7.com/AstroQi/archive/2008/07/18/215717.htmlhttp://www.tkk7.com/AstroQi/comments/215717.htmlhttp://www.tkk7.com/AstroQi/archive/2008/07/18/215717.html#Feedback0http://www.tkk7.com/AstroQi/comments/commentRss/215717.htmlhttp://www.tkk7.com/AstroQi/services/trackbacks/215717.html

Web Services ---- XFire

L?POJO 发布?Web 服务

developerWorks
文档选项
此作为电(sh)子邮件发? src=

此作为电(sh)子邮件发?/strong>

未显C需?JavaScript 的文档选项

样例代码


2007 q?5 ?16 ?/p>

Java C֌一直试囑ְ POJO 的作用发挥到极致Q降?Java 应用实现的难度,最q的试是将 EJB3.0 建立?POJO 之上Q另一斚wQSOA 是目?Java C֌炙手可热的名词,非常多的企业都在努力应用和实?SOAQXFire 两方面的需求提供了(jin)一U魔术般的解x式,我们很快能够发现使用 XFire 创徏和发?Web 服务可以直接Z POJOQ将?ch)h的承关pd一大堆其他可能的约束丢在一辏V?/blockquote>

POJO、SOA 概述

被重新审视的 POJO

POJOQPlain Old Java ObjectQ简?Java 对象Q是 Java C֌中最早的成员Q回x学习(fn) Java 时第一个兴奋的时刻Q那个简单的 "Hello WorldQ? 例子Q,也是最单、最Ҏ(gu)实现的方式?/p>

然而现实中 Java 的发展已l远q超了(jin) POJO 的范_(d)成ؓ(f)面向对象技术应用中最成功的编E语aQ尤其是l承、多态的应用为我们造就?jin)一大批开发框Ӟ? StrutsQ和标准Q如 EJBQ,随之而来的就是实现的复杂化,我们必须面对一大堆l承关系的限制。比如说Q要开发一个基?Struts 的应用,我们必须?jin)? Struts 特定的承关pd ActionForm、ValidateActionFormQ要开发一?EJB 应用Q我们必ȝ? EJBObject、SessionEJB {?/p>

Z(jin)抛开q些限制Q降?Java 应用实现的难度,Java C֌开始重新审?POJO 的h(hun)|试图?POJO 的作用发挥到极致Q最新的努力? EJB3.0。Java C֌?EJB3.0 设计为基?POJOQ而不是ؓ(f)他准备更多的l承关系{限制?/p>

让h爱恨交加?SOA

SOA 已经成ؓ(f)?jin)目?Java C֌中炙手可热的名词Q几乎所有的软g厂商都在讨论它,Z提供解决Ҏ(gu)和品支持,大部分的企业也已l在企业内部实施或者正在考虑实施 SOA?/p>

然?SOA 在企业内的实施却不是一简单的dQ即使抛开新徏pȝ直接Z SOA 架构实施的因素,要把企业已有pȝU_ SOA 框架也不是一件容易的事情。企业必d对当前架构深入了(jin)解的基础上,对已有系l进行大规模的改造才能满x的要求。如何经的从原有技术架构切换到 SOA 架构成ؓ(f)很多企业的难题?/p>



回页?/strong>


XFire 概述

XFire ?codeHaus l织提供的一个开源框Ӟ它构Z(jin) POJO ?SOA 之间的桥梁,主要Ҏ(gu)就是支持将 POJO 通过非常单的方式发布?Web 服务Q这U处理方式不仅充分发挥了(jin) POJO 的作用,化了(jin) Java 应用转化?Web 服务的步骤和q程Q也直接降低? SOA 的实现难度,Z业{?SOA 架构提供?jin)一U简单可行的方式?/p>

XFire 目前最新的版本?1.2.2Q目前支持的Ҏ(gu)主要包括:(x)

  • 支持?Web 服务l定?POJO、XMLBeans、JAXB1.1、JAXB2.0 ?CastorQ?
  • 支持Z HTTP、JMS、XMPP {多U协议访?Web 服务Q?
  • 支持多种 Web 服务业界重要标准?SOAP、WSDL、Web 服务dQWS-AddressingQ、Web 服务安全QWS-SecurityQ等Q?
  • 支持 JSR181Q可以通过 JDK5 配置 Web 服务Q?
  • 高性能?SOAP 实现Q?
  • 服务器端、客L(fng)代码辅助生成Q?
  • ?Spring、Pico、Plexus {项目的支持{?




回页?/strong>


XFire 安装?/span>

XFire 框架目前的最新版本是 1.2.6Q可以访?xfire.codehaus.org 下蝲 XFire 框架的安装包Q下载时请选择“全部二进制发布包QBinary Distribution in zip packageQ?#8221;Q而不仅仅?#8220;XFire jar 文gQJar of all XFire modulesQ?#8221;?/p>

下蝲完成后,我们可以下载的 .zip 文g解压~到L的文件夹中(后面的章节中使用 % XFIRE_HOME % 表示 XFire 框架的安装目录)(j)Q解压羃后Ş成的文g目录l构如下Q?/p>

  • apiQ目录)(j)

    api 目录中是 XFire 框架中所有类QclassQ对应的 API 文档Qؓ(f)开发者?XFire 完成应用开发提供帮助?/p>

  • examplesQ目录)(j)

    examples 目录中包含了(jin)所有随 XFire 二进制包发布的实例,包括q些实例的源代码和相?Web 应用配置内容?/p>

  • libQ目录)(j)

    lib 目录中包?XFire q行所需要的外部支持cdQ?jar文gQ,可以Ҏ(gu)不同目所需?XFire Ҏ(gu)选择所需要的支持cd。保守的Ҏ(gu)是在 Web 目中包含所有的外部支持cdQ?jar文gQ?/p>

  • manualQ目录)(j)

    manual 目录中包含有 XFire 框架的帮助文档,开发者可以从q些帮助文档中学?fn)更多运?XFire 框架实现 SOA 的知识和技巧?/p>

  • modulesQ目录)(j)

    modules 目录中包含了(jin) XFire 框架Ҏ(gu)不同Ҏ(gu)分别编译的二进制包文g。发布基?XFire 框架?Web 目Ӟ可以选择使用该目录下的所? .jar 文gQ也可以选择 XFire-all-1.2.6.jar 文g?/p>

  • XFire-all-1.2.6.jar

    XFire 框架的二q制包文Ӟ包含?jin)全部的模块QmodulesQ?/p>

  • LICENSE.txt

    LICENSE.txt 文g中包含了(jin) XFire 框架的授权协议?/p>

  • NOTICE.txt
  • README.txt

    q两个文件中包含?XFire 发布时的一些有用的信息?/p>





回页?/strong>


XFire 框架支撑环境

XFire框架是一U基于Servlet技术的SOA应用开发框Ӟ要正常运行基于XFire应用框架开发的企业应用Q除?jin)XFire框架本n之外Q还需要JDK和Servlet容器的支持?/p>

1QJDK 版本选择、下载和安装

XFire 支持非常多的Ҏ(gu),其中不同的特性对 JDK 版本的要求有所不同Q比如如果项目中选择Z JSR181 标准发布 Web 服务Q我们就需要选择 JDK5 或者以上版本,如果仅仅选择?Web 服务l定到最单的 POJOQ我们只需要选择 JDK1.4 版本卛_?/p>

JDK 各版本均可以?java.sun.com |站上下载,如何安装 JDK 请参?SUN 公司的相x术文档和 JDK 的帮助文档?/p>

2QServlet 容器下蝲和安?/span>

XFire 是一U基?Servlet 技术的 SOA 应用开发框Ӟ需?Servlet 容器的支持。XFire 支持在多U?Servlet 容器中运行,包括 Websphere、Weblogic、TOMCAT {。ؓ(f)?jin)说明的单,我们选择使用 TOMCATQ版?.0.30Q作?XFire 的运行容器,所有配|过E和发布步骤的说明也均是针对 TOMCATQ如果读者?TOMCAT 之外的其?Servlet 容器或者选择?TOMCAT 的其它版本,下面的配|过E和步骤可能需要做?gu)_(d)误者根据实?Servlet 容器的帮助文档进行相应调整?/p>

TOMCAT 各版本均可以?tomcat.apache.org |站上下载,如何正确安装 TOMCAT 服务器请参?TOMCAT 服务器的帮助文档?/p>

3Qxalan

XFire 需?xalan 目的支持,然?1.2.6 版本中ƈ没有带有相应?jar 文gQ因此请讉K xml.apache.orgQ下?xalan 目的二q制包?/p>



回页?/strong>


XFire 应用配置

前面的章节中我们下蝲和安装了(jin) XFire 安装包和所需要的支持环境Q现在我们开始学?fn)如何从零开始创?XFire 应用开发环境。下面的所有配|过E和发布步骤均针?TOMCATQ版?.0.30Q服务器Q如果选择其它?Servlet 容器Q下面的配置q程和步骤可能需要做?gu)_(d)误者根据实?Servlet 容器的帮助文档进行相应调整?/p>

1、创?Web 应用目录和基本元?/span>

  1. ?%TOMCAT_HOME%/webapps 目录下创建新?Web 应用目录 “XFire”

    [注] 其中?%TOMCAT_HOME% 指向 TOMCAT 的安装目录?/em>

  2. ?”XFire”目录下创?”WEB-INF”目录?
  3. ?” WEB-INF”目录下创?”lib”目录?”classes”目录
  4. ?” WEB-INF”目录下创?Web 应用描述文g ”web.xml”Q?”web.xml”文g的内容见 清单 1-1?

清单 1-1 WEB-INF\web.xml
                
1?<?xml version="1.0" encoding="ISO-8859-1"?>
2?<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
3? xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4? xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
5? version="2.4">
6?
7? <display-name>XFire实例</display-name>
8? <description>
9? ZXFire框架发布Web服务的例?br /> 10? </description>
11?
12?</web-app>

2、拷?XFire 所需的支持类包文?/span>

拯 %XFIRE_HOME%/lib 目录下所有文件到 “1、创?Web 应用目录和基本元?#8221; 中所创徏?”lib”目录下,?%XFIRE_HOME%/XFire-all-1.2.6.jar 文g也拷贝到 “1、创?Web 应用目录和基本元?#8221; 中所创徏?”lib”目录下。将 xalan 安装包中的所?jar 文g和所需要的支持 jar 文g拯到相同的 ”lib”目录下?/p>

[注] Z(jin)减少拯?jar 文g的数目,开发者可以根据项目的需要选择需要拷贝的 jar 文gQ而不是全部拷贝,如何Ҏ(gu)需要选择拯合适的cd文g误?XFire 站点?

3、配|?XFire 框架q行所需? Servlet

修改 web.xml 文gQ在其中增加如下 Servlet 定义内容?/p>
1?<servlet>
2? <servlet-name>XFireServlet</servlet-name>
3? <display-name>XFire Servlet</display-name>
4? <servlet-class>
5? org.codehaus.xfire.transport.http.XFireConfigurableServlet
6? </servlet-class>
7? </servlet>
8?
9? <servlet-mapping>
10? <servlet-name>XFireServlet</servlet-name>
11? <url-pattern>/servlet/XFireServlet/*</url-pattern>
12? </servlet-mapping>
13?
14? <servlet-mapping>
15? <servlet-name>XFireServlet</servlet-name>
16? <url-pattern>/services/*</url-pattern>
17?</servlet-mapping>

4、创?XFire 框架的服务发布文? services.xml

  1. ?“1、创?Web 应用目录和基本元?#8221; 中创建的 classes 目录下新建目?”META-INF\xfire”Q?
  2. 在步?a) 中新建的 ”xfire”文g目录下创建新文g services.xmlQ文件的默认内容?清单1-2 ?

清单 1-2 WEB-INF\classes\META-INF\xfire\services.xml
                
1?<beans xmlns="http://XFire.codehaus.org/config/1.0">
2?</beans>





回页?/strong>


?POJO 发布?Web 服务

XFire 框架中,我们有两U方式将 POJO 发布?Web 服务Q?/p>

  • 一U方式是直接使用 Web 服务接口?Web 服务实现c(POJOQ来发布Q?
  • 另一U方式是Z JSR181 标准和注释技术将被注释的 POJO 发布?Web 服务Q?

下面的章节中我们学?fn)用第一U方式来完成 POJO ?Web 服务发布。我们将使用l典?”Hello World!”例子来演C将 POJO 发布? Web 服务所需要的步骤Q不q我们不再是单的讉K一?Java Ҏ(gu)来输?”Hello World!”字符Ԍ而是转ؓ(f)?SOA 环境下实玎ͼ(x)Web 服务客户端通过讉K服务器端发布?Web 服务?POJO 获得q回?”Hello World!”字符串后输出到客L(fng)的控制台上?/p>

?POJO 发布?Web 服务的基本步骤如下:(x)

  1. 创徏 Web 服务接口Q声明该 Web 服务对外暴露的接口;
  2. 创徏 Web 服务实现c,?Web 服务接口提供实现Q?
  3. 修改 XFire 框架的服务发布文?---- services.xmlQ将 POJO 发布?Web 服务?

下面我们通过创徏 ”Hello World!”例子来具体说明如何实现这三个步骤?/p>

1Q创?Web 服务接口 ---- HelloWorldService

要将 POJO 发布?Web 服务Q首先需要创?Web 服务接口Q在接口中声明该 Web 服务需要对外暴露的接口?/p>

我们Ҏ(gu)需要创?Web 服务接口 ” HelloWorldService”Q在其中声明一?”sayHello”Ҏ(gu)Q该Ҏ(gu)q回 ”String ”cd的内宏V?#8221; HelloWorldService”接口对应?Java 文g代码?清单 1-3?/p>
清单 1-3 WEB-INF\classes\org\vivianj\xfire\pojo\HelloWorldService.java
                
1Qpackage org.vivianj.xfire.pojo;
2Q?br /> 3Q?/**
4Q?* HelloWorldService 中声明需要发布成 Web 服务的所?Java Ҏ(gu)
5Q?* HelloWorldService 作ؓ(f)Web服务接口
6Q?*/
7Q?public interface HelloWorldService {
8Q?/**
9Q? * sayHello Ҏ(gu)声明?Web 服务对外暴露的接?br /> 10Q? *
11Q? * @return q回l客L(fng)的字W串
12Q? */
13Q?public String sayHello();
14Q}

2Q创?Web 服务实现c? ”HelloWorldServiceImpl”

创徏 Web 服务实现c?”HelloWorldServiceImpl”Q它l承 ”1、创建Web服务接口 ---- HelloWorldService” 中创建的 HelloWorldService 接口Qƈ且ؓ(f)它声明的 ”sayHello”Ҏ(gu)提供具体实现Q?q回字符?#8221;Hello World!”? ”HelloWorldServiceImpl”cd应的 Java 文g代码?清单 1-4?/p>
清单 1-4 WEB-INF\classes\org\vivianj\xfire\pojo\HelloWorldServiceImpl.java
                
1Qpackage org.vivianj.xfire.pojo;
2Q?br /> 3Q?**
4Q?* HelloWorldServiceImpl 中ؓ(f) Web 服务接口中声明的所?Java Ҏ(gu)提供具体实现
5Q?* HelloWorldServiceImpl 作ؓ(f) Web 服务的实现类
6Q?*/
7Qpublic class HelloWorldServiceImpl implements HelloWorldService {
8Q?br /> 9Q?/*
10Q? * sayHello Ҏ(gu)?HelloWorldService 服务接口定义?sayHello Ҏ(gu)提供具体实现
11Q? *
12Q? * @see org.vivianj.XFire.pojo.HelloWorldService#sayHelloToXFire()
13Q? */
14Q?public String sayHello() {
15Q? return "Hello World!";
16Q?}
17Q?br /> 18Q}

3Q修?services.xmlQ将 POJO 发布?Web 服务

我们可以?WEB-INF\classes\META-INF\XFire\services.xml 文g中的 <beans …> ? </beans> 元素中间加入如下?xml 内容上面创建的 HelloWorldService 发布?Web 服务?/p>
1Q?lt;service>
2Q?<name>HelloWorldService</name>
3Q?<namespace>http://vivianj.org/HelloWorldService</namespace>
4Q?<serviceClass>
5Q? org.vivianj.xfire.pojo.HelloWorldService
6Q?</serviceClass>
7Q?<implementationClass>
8Q? org.vivianj.xfire.pojo.HelloWorldServiceImpl
9Q?</implementationClass>
10Q?lt;/service>

其中各元素的功能如下Q?/p>

  • service

    service 标签和它所包含?xml 内容为发布成 Web 服务?POJO 提供完整的描q?/p>

  • name

    Web 服务被发布时所采用的唯一名称?/p>

  • namespace

    Web 服务发布时所使用的命名空间?/p>

  • serviceClass

    Web 服务接口cȝ全名Q包括包名和cd?/p>

  • implemetationClass

    Web 服务实现cȝ全名Q包括包名和cd?/p>

更多 service 元素的子元素和它们的用法请参?XFire 站点?/p>

通过上面的三个步骤,我们已经新创徏的HelloWorldService发布成了(jin)Web服务Q我们可以用下面的步骤试一下创建的Web服务是否能够正常q行Q?/p>

  1. ~译上面的步骤中创徏?Java 接口和类Q?
  2. 启动 TOMCAT 服务器?
  3. {?TOMCAT 服务器完全启动后Q打开览器,在地址栏中输入 http://localhost:8080/XFire/services/HelloWorldService?wsdl?

其中 HelloWorldServcie 是配|文件中 service\name 元素所定义的内容,”wsdl”参数表示查看?Web 服务? WSDLQWeb服务描述语言Q文件?/p>

如果览器中出现如下图所C类似的内容Q表C?Web 服务发布成功Q我们可以编写客L(fng)讉K?Web 服务从服务器获取q回字符Ԍ本文下蝲资源中提供的下蝲文g中包含有可供参考的客户端类 org.vivianj.xfire.pojo.client.HelloWorldServiceClient?/p>
图:(x)览器中讉K效果

如果览器中出现错误提示Q请按照上面的步骤和说明(g)查已l完成的开发、配|过E是否完全正?/p>



回页?/strong>


l束?/span>

本文中作者首先讲解了(jin) XFire 框架的主要特性,XFire 框架的运行环境以?qing)基?XFire 框架开?SOA 应用的基本步骤,q且借助?SOA 环境下的 ”Hello World!”例子Q详l的讲解和演CZ(jin)如何Z XFire 框架、经q简单的开发、配|步骤就一?POJO cM包含的方法发布成Web服务。从 ”Hello World!”例子实现的过E中Q我们可以发?XFire 框架最大化的发挥了(jin) POJO 的作用,减少?SOA 实施时对框架本n的依赖,降低?SOA 实施的难度,企业实施 SOA 时ƈ不需要增加太多的投入可以实现目标?/p>




回页?/strong>


下蝲

名字 大小 下蝲Ҏ(gu)
xfire.war 6 KB HTTP
关于下蝲Ҏ(gu)的信?/a>


参考资?

学习(fn)

获得产品和技?/strong>


Astro.Qi 2008-07-18 11:45 发表评论
]]>
JDBC ORACLE CLOB (用分|想解决兆以上的字W流操作问题)http://www.tkk7.com/AstroQi/archive/2008/07/10/214025.htmlAstro.QiAstro.QiThu, 10 Jul 2008 09:05:00 GMThttp://www.tkk7.com/AstroQi/archive/2008/07/10/214025.htmlhttp://www.tkk7.com/AstroQi/comments/214025.htmlhttp://www.tkk7.com/AstroQi/archive/2008/07/10/214025.html#Feedback1http://www.tkk7.com/AstroQi/comments/commentRss/214025.htmlhttp://www.tkk7.com/AstroQi/services/trackbacks/214025.html import java.io.*;
import java.util.*;
import java.sql.*;
 
public class ClobTest {
 
    private static final String DRIVER = "oracle.jdbc.driver.OracleDriver";
    private static final String URL = "jdbc:oracle:thin:@127.0.0.1:1521:ora10g";
    private static final String USER = "sc";
    private static final String PASSWORD = "sc";
    private static Connection conn = null;
    private static Statement stmt = null;

 
    /**
     * 往数据库中插入一个新的CLOB对象
     */
    public static void save(BO obj) throws Exception {
        /* 一定要讑֮不自动提交,否则抛出ORA-01002: dq反序 */
        boolean defaultCommit = conn.getAutoCommit();
        conn.setAutoCommit(false);
 
        try {
            stmt = conn.createStatement();
            /* 插入一个空的CLOB对象 */
            stmt.executeUpdate("INSERT INTO TEST_CLOB VALUES ('1000', EMPTY_CLOB())");//一定要使用Oracle中的EMPTY_CLOB()函数
           
            stmt.close();//记得x我哦 :-)
            stmt= null;

            /* 查询此CLOB对象q?*/
            //stmt = conn.prepareStatement();//如果是PrepareStatement接口,一定要重新创徏该对?否则抛出ORA-01006: 赋值变量不?/span>?/span>
           
            ResultSet rs = stmt.executeQuery("SELECT CLOBCOL FROM TEST_CLOB WHERE ID='1000' FOR UPDATE");//一定要for update锁定该记录,否则抛出ORA-22920: 未锁定含?LOB 值的?/span>
            while (rs.next()) {
                /* 取出此CLOB对象 */
                oracle.sql.CLOB clob = (oracle.sql.CLOB)rs.getClob("CLOBCOL");

                /* 向CLOB对象中写入数?*/
                Writer out = clob.getCharacterOutputStream();
                //out.write(new String(obj.getEmail()));//obj.getEmail()q回byte[]cd,但是当obj.getEmail()l对大时,执行new String(byte[])?JVM?x)抛?span style="color: red;">内存
溢出异常

                byte[] emails = obj.getEmail();
                ClobStreamHandler csh = new ClobStreamHandler(emails);
                String[] arrx = csh.pagedClobStream();//要解军_存溢出异常,必须把绝对大的byte[]q行分页
                if (arrx != null){
                    for (int i = 0; i < arrx.length; i++) {
                        out.write(arrx[i]);
                        out.flush();//要解军_存溢出异?必须一一?/span>的flush()到数据库
                    }
                }
                else out.write("");
                out.close();
            }
            /* 正式提交 */
            conn.commit();

            /* 恢复原提交状?*/
            conn.setAutoCommit(defaultCommit);
        } catch (Exception ex) {
            /* 出错回滚 */
            conn.rollback();
            throw ex;
        } finally {相关关闭操作}
 
      
    }
 
    /**
     * 修改CLOB对象Q是在原CLOB对象基础上进行覆盖式的修改)(j)
     *
     * @param obj - 数据对象
     * @throws java.lang.Exception
     * @roseuid 3EDA04B60367
     */
    public static void modify(BO obj) throws Exception {
        /* 讑֮不自动提?*/
        boolean defaultCommit = conn.getAutoCommit();
        conn.setAutoCommit(false);
 
        try {
            /* 查询CLOB对象q?*/
            ResultSet rs = stmt.executeQuery("SELECT CLOBCOL FROM TEST_CLOB WHERE ID='1000' FOR UPDATE");
            while (rs.next()) {
                /* 获取此CLOB对象 */
                oracle.sql.CLOB clob = (oracle.sql.CLOB)rs.getClob("CLOBCOL");  
                
                /* q行覆盖式修?*/
                Writer out = clob.getCharacterOutputStream();
                byte[] emails = obj.getEmail();
                ClobStreamHandler csh = new ClobStreamHandler(emails);
                String[] arrx = csh.pagedClobStream();//要解军_存溢出异常,必须把绝对大的byte[]q行分页
                if (arrx != null){
                    for (int i = 0; i < arrx.length; i++) {
                        out.write(arrx[i]);
                        out.flush();//要解军_存溢出异?必须一一?/span>的flush()到数据库
                    }
                }
                else out.write("");
                out.close();
            }
            /* 正式提交 */
            conn.commit();

            /* 恢复原提交状?*/
            conn.setAutoCommit(defaultCommit);
        } catch (Exception ex) {
            /* 出错回滚 */
            conn.rollback();
            throw ex;
        } finally {相关关闭操作}
 
        /* 恢复原提交状?*/
        conn.setAutoCommit(defaultCommit);
    }
 
    /**
     * 替换CLOB对象Q将原CLOB对象清除Q换成一个全新的CLOB对象Q?br />      *
     * @param obj - 数据对象
     * @throws java.lang.Exception
     * @roseuid 3EDA04BF01E1
     */
    public static void replace(BO obj) throws Exception {
        /* 讑֮不自动提?*/
        boolean defaultCommit = conn.getAutoCommit();
        conn.setAutoCommit(false);
 
        try {
            /* 清空原CLOB对象 */
            stmt.executeUpdate("UPDATE TEST_CLOB SET CLOBCOL=EMPTY_CLOB() WHERE ID='1000'");
            
            /* 查询CLOB对象q?*/
            ResultSet rs = stmt.executeQuery("SELECT CLOBCOL FROM TEST_CLOB WHERE ID='1000' FOR UPDATE");
            
            while (rs.next()) {
                /* 获取此CLOB对象 */
                oracle.sql.CLOB clob = (oracle.sql.CLOB)rs.getClob("CLOBCOL");
                /* 更新数据 */
                Writer out = clob.getCharacterOutputStream();
                byte[] emails = item.getEmail();
                ClobStreamHandler csh = new ClobStreamHandler(emails);
                String[] arrx = csh.pagedClobStream();//要解军_存溢出异常,必须把绝对大的byte[]q行分页
                if (arrx != null){
                    for (int i = 0; i < arrx.length; i++) {
                        out.write(arrx[i]);
                        out.flush();//要解军_存溢出异?必须一一?/span>的flush()到数据库
                    }
                }
                else out.write("");
                out.close();
            }
            /* 正式提交 */
            conn.commit();

            /* 恢复原提交状?*/
            conn.setAutoCommit(defaultCommit);
        } catch (Exception ex) {
            /* 出错回滚 */
            conn.rollback();
            throw ex;
        } finally {相关关闭操作}
 
       
    }
 
    /**
     * dCLOB对象
     */
    public static byte[] read() throws Exception {
        /* 讑֮不自动提?*/
        boolean defaultCommit = conn.getAutoCommit();
        conn.setAutoCommit(false);
 
        try {
            /* 查询CLOB对象 */
            ResultSet rs = stmt.executeQuery("SELECT * FROM TEST_CLOB WHERE ID='1000'");
            while (rs.next()) {
                /* 获取CLOB对象 */
                oracle.sql.CLOB c= (oracle.sql.CLOB)rs.getClob("CLOBCOL");
               
                if (c != null){
                     try {
                          oracle.jdbc.driver.OracleClobInputStream is = (OracleClobInputStream) c.getAsciiStream();
                          java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
                   
                          byte[] by = new byte[1024 * 200];
                          while(is.read(by, 0, by.length) != -1){
                              baos.write(by, 0, by.length);
                              baos.flush();//把数据写入内?/span>
                          }
                   
                          baos.close();
                          is.close();
                          return baos.toByteArray();//不会(x)内存溢出?/span>,呵呵. 原因是把数据写入?jin)内?而不是JVM的内存管理区?br />                      } catch (SQLException e) {
                           //e.printStackTrace();
                     }
                }
                else return new byte[0];
                break;
            }
        } catch (Exception ex) {
            conn.rollback();
            throw ex;
        } finally {相关关闭操作}
 
        /* 恢复原提交状?*/
        conn.setAutoCommit(defaultCommit);
    }
 
    /**
     * 建立试用表?br />      * @throws Exception
     */
    public static void createTables() throws Exception {
        try {
            stmt.executeUpdate("CREATE TABLE TEST_CLOB (ID VARCHAR2(4), CLOBCOL CLOB)");
            stmt.executeUpdate("CREATE TABLE TEST_BLOB (ID VARCHAR2(4), BLOBCOL BLOB)");
        } catch (Exception ex) {
 
        }
    }
 
    public static void main(String[] args) throws Exception {
        /* 装蝲驱动,建立数据库连?*/
        Class.forName(DRIVER);
        conn = DriverManager.getConnection(URL, USER, PASSWORD);
        stmt = conn.createStatement();
 
        /* 建立试表格 */
        createTables();
    }
}


    对Clob字符进行分늚法Q?br />    
 1 package privy.astroqi.oracle.db.handler;
 2 
 3 /**
 4  * 
 5  * @author Astro Qi
 6  * @since  2008-07-23 00:05
 7  *
 8  */
 9 public class ClobStreamHandler {
10 
11     private static int PAGE_SIZE = 1024 * 200 * 1;
12     
13     private byte[] dataes;
14     
15     private int length;
16     
17     private int pageCount;
18     
19     public ClobStreamHandler(byte[] data){
20         if (data == null){
21             throw new java.lang.IllegalArgumentException("参数byte[]不能为空,否则无法处理接下来的操作.");
22         }
23         
24         dataes = data;
25         length = dataes.length;
26         pageCount = (length % PAGE_SIZE == 0? (length / PAGE_SIZE) : (length / PAGE_SIZE) + 1;
27         
28     }
29     
30     public String[] pagedClobStream(){
31         
32         String[] arr = new String[pageCount];
33         
34         for (int i = 1; i <= pageCount; i++) {
35             int sheYuByte = length - (PAGE_SIZE * (i - 1));
36             byte[] b = null;
37             if (sheYuByte > PAGE_SIZE){
38                 b = new byte[PAGE_SIZE];
39             } 
40             else {
41                 b = new byte[sheYuByte];
42             }
43             for (int j = 0; j < b.length; j++){
44                 b[j] = dataes[(i - 1* PAGE_SIZE + j];
45             }
46             arr[i - 1= new String(b);
47         }
48         
49         return arr;
50     }
51 }


Astro.Qi 2008-07-10 17:05 发表评论
]]>
JavaMail API ?/title><link>http://www.tkk7.com/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.tkk7.com/AstroQi/archive/2008/07/01/211873.html</guid><wfw:comment>http://www.tkk7.com/AstroQi/comments/211873.html</wfw:comment><comments>http://www.tkk7.com/AstroQi/archive/2008/07/01/211873.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.tkk7.com/AstroQi/comments/commentRss/211873.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/AstroQi/services/trackbacks/211873.html</trackback:ping><description><![CDATA[<span style="color: #ff0000">1.</span>介绍:<br /> <br /> Java Mail API的开发是SUN为Java开发者提供公用API框架的持l努力的良好例证。提倡公用框Ӟ反对受限于供应商的解x案,充分预示着一个日益开攄开发环境的建立?br /> Java Mail API的结构本w证明了(jin)它的开发者的基本目标之一--软g开发的工作量应该取决于应用E序本n的复杂程度以?qing)开发者所要求的控制程度。换句话_(d)Java Mail API可能地保持单。乍看v来,JavaMail API所拥有的类L以及(qing)cM间的关系可能让h误解p漫长的学?fn)时间。实际上Q一旦正式开始用,你就?x)发现该API不失为在应用E序中加入健壮的邮g/通讯支持的简单工兗?<br /> <br /> 在我们步入JavaMail API之前Q先看一下API所涉及(qing)的协议。以下便是大家日常所知、所乐于使用?大信息传输协议:(x)SMTP POP IMAP MIME NNTP?br /> 当然Q上面的4个协议,q不是全部,q有NNTP和其它一些协议可用于传输信息Q但是由于不常用刎ͼ所以本文便不提?qing)?jin)。理解这4个基本的协议有助于我们更好的使用JavaMail API。然而JavaMail API是被设计Z协议无关的,目前我们q不能克服这些协议的束缚(x)。确切的_(d)如果我们使用的功能ƈ不被我们选择的协议支持,那么JavaMail APIq不可能如魔术师一L(fng)奇的赋予我们q种能力?br /> <br /> <span style="color: blue">1QSMTP</span><br /> 单邮件传输协议定义了(jin)递送邮件的机制。在下文中,我们用基于Java-Mail的程序与公司或者ISP的SMTP服务器进行通讯。这个SMTP服务器将邮g转发到接收者的SMTP服务器,直至最后被接收者通过POP或者IMAP协议获取。这q不需要SMTP服务器用支持授权的邮g转发Q但是却的确要注意SMTP服务器的正确讄QSMTP服务器的讄与JavaMail API无关Q?br /> <br /> <span style="color: blue">2QPOP</span><br /> POP 是一U邮局协议Q目前ؓ(f)W?个版本,即众所周知的POP3。POP定义?jin)一U用户如何获得邮件的机制。它规定?jin)每个用户用一个单独的邮箱。大多数人在使用POP时所熟?zhn)的功能ƈ非都被支持,例如查看邮箱中的新邮件数量。而这个功能是微Y的Outlook内徏的,那么p明微软Outlook之类的邮件客L(fng)软g是通过查询最q收到的邮g来计新邮g的数量来实现前面所说的功能。因此在我们使用JavaMail API旉要注意,当需要获得如前面所讲的新邮件数量之cȝ信息Ӟ我们不得不自p行计?br /> <br /> <span style="color: blue">3QIMAP</span><br /> IMAP 使用在接收信息的高协议Q目前版本ؓ(f)W?版,所以也被称为IMAP4。需要注意的是在使用IMAPӞ邮g服务器必L持该协议。从q个斚wԌ我们q不能完全用IMAP来替代POPQ不能期待IMAP在Q何地斚w被支持。假如邮件服务器支持IMAPQ那么我们的邮gE序能够具有以下被I(xin)MAP所支持的特性:(x)每个用户在服务器上可h多个目录Q这些目录能在多个用户之间共享?br /> 其与POP相比高之处显而易见,但是在尝试采取IMAPӞ我们认识到它q不是十分完的Q由于IMAP需要从其它服务器上接收C息,这些信息递送给用户Q维护每个用L(fng)多个目录Q这都ؓ(f)邮g服务器带来了(jin)高负载。ƈ且IMAP与POP的一个不同之处是POP用户在接攉件时从邮g服务器上下蝲邮gQ而IMAP允许用户直接讉K邮g目录Q所以在邮g服务器进行备份作业时Q由于每个长期用此邮gpȝ的用h用的邮g目录?x)占有很大的I间Q这直接导致邮件服务器上磁盘空间暴涨?br /> <br /> <span style="color: blue">4QMIME</span><br /> MIME q不是用于传送邮件的协议Q它作ؓ(f)多用途邮件的扩展定义?jin)邮件内容的格式Q信息格式、附件格式等{。一些RFC标准都涉?qing)?jin)MIMEQRFC 822, RFC 2045, RFC 2046, RFC 2047Q有兴趣的Matrixer可以阅读一下。而作为JavaMail API的开发者,我们q不需兛_(j)q些格式定义Q但是这些格式被用在?jin)程序中?br /> <br /> <span style="color: blue">5QNNTP和其它的W三方协?/span><br /> 正因为JavaMail API在设计时考虑CW三方协议实现提供商之间的分,故我们可以很Ҏ(gu)的添加一些第三方协议。SUNl护着一个第三方协议实现提供商的列表Q?a target="_new">http://java.sun.com/products/javamail/Third_Party.html</a>Q通过此列表我们可以找到所需要的而又不被SUN提供支持的第三方协议Q比如NNTPq个新闻l协议和S/MIMEq个安全的MIME协议?br /> <br /> <br /> <span style="color: #ff0000">2.</span>安装:<br /> <br /> 安装前要保你的机子上安装得有标准版的JDK和W(xu)eb服务?q且已配|好,有关它们的安装方?请参考其它文?|上到处都有).<br /> <br /> (1).安装JavaMail API。现在最常用?JavaMail API 版本?.3.<br /> 要?JavaMail 1.3 APIQ请下蝲 JavaMail 1.3 实现Q解开Javamail-1_3.zip 文gQƈ?mail.jar 文gd?CLASSPATH 中。除?jin)核心(j)类Q随版本 1.3 实现一h供的q有 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">支持L数据块的输入?qing)相应处?/span></span>。功能似乎不多,但目前许多浏览器和邮件工具中都能扑ֈq种基本?MIME 型支持。下载完框架后,解开 jaf1_0_2.zip 文gQƈ?activation.jar 文gd?CLASSPATH 中?br /> <br /> ? 如果(zhn)用的JDK是J2EEQ就没有什么特定的事非要用基本 JavaMail API来做不可QJ2EE 的类p处理?因ؓ(f)它本w就包含有JavaMail API和JAF,(zhn)只需要确?j2ee.jar 文gd到?zhn)的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" >java</a>x.mail.Propertiesc?br /> JavaMail需要Properties来创Z个session对象。它?yu)寻扑֭W串"mail.smtp.host"Q属性值就是发送邮件的L.<br /> <br /> 用法:<br /> Properties props = new Properties ();<br /> props.put("mail.smtp.host", "smtp.163.com");//可以换上你的smtpL名?br /> <br /> <br /> (2) <a class="Channel_KeyLink" >java</a>x.mail.Sessionc?br /> q个SessioncM表JavaMail 中的一个邮件session. 每一个基?JavaMail的应用程序至有一个session但是可以有Q意多的session?在这个例子中, Session对象需要知道用来处理邮件的SMTP 服务器?br /> <br /> 用法:<br /> Session sendMailSession;<br /> sendMailSession = Session.getInstance(props, null);<br /> <br /> <br /> (3) <a class="Channel_KeyLink" >java</a>x.mail.Transportc?br /> 邮g是既可以被发送也可以被受到。JavaMail使用?jin)两个不同的cL完成q两个功能:(x)Transport 和Store. Transport 是用来发送信息的Q而Store用来收信。对于这的教E我们只需要用到Transport对象?br /> <br /> 用法Q?br /> Transport transport;<br /> transport = sendMailSession.getTransport("smtp");<br /> <br /> 用JavaMail Session对象的getTransport Ҏ(gu)来初始化Transport。传q去的字W串x?jin)对象所要用的协议Q如"smtp"。这ؓ(f)我们省了(jin)很多旉。因为JavaMail以境内置?jin)很多协议的实现?gu)?br /> <br /> 注意: JavaMailq不是绝Ҏ(gu)持每一个协议,目前支持IMAP?SMTP?POP3. <br /> <br /> <br /> (4) <a class="Channel_KeyLink" >java</a>x.mail.MimeMessagec?br /> Message对象存储我们实际发送的?sh)子邮g信息QMessage对象被作Z个MimeMessage对象来创建ƈ且需要知道应当选择哪一个JavaMail session?br /> <br /> 用法Q?br /> Message newMessage = new MimeMessage(sendMailSession);<br /> <br /> <br /> (5) <a class="Channel_KeyLink" >java</a>x.mail.InternetAddressc?br /> 一旦?zhn)创徏?Session ?MessageQƈ内容填入消息后Q就可以用Address定信g地址?jin)。和 Message 一PAddress 也是个抽象类。?zhn)用的是Javax.mail.internet.InternetAddress c?<br /> <br /> 用法:<br /> InternetAddress from=new InternetAddress("xxf@cafe.com");<br /> <br /> <br /> (6) <a class="Channel_KeyLink" >java</a>x.mail.Storec?br /> Storecd现特定邮件协议上的读、写、监视、查扄操作。通过Javax.mail.Storecd以访问Javax.mail.FoldercR?br /> <br /> 用法:<br /> Store store=session.getSorte("pop3");//sessionZ个邮件会(x)?br /> store.connect(pop3server,username,password);//通过你提供的pop3地址,用户名和密码d你的邮箱<br /> <br /> <br /> (7) <a class="Channel_KeyLink" >java</a>x.mail.Folderc?br /> Foldercȝ于分U组l邮Ӟq提供照Javax.mail.Message格式讉Kemail的能力?<br /> <br /> 用法:<br /> Folder folder=store.getFolder("INBOX");<br /> folder.open(Folder.READ_ONLY);<br /> <br /> <br /> (8) <a class="Channel_KeyLink" >java</a>x.mail.Internet.MimeMultpart<br /> 一般保存电(sh)子邮件内容的容器是Multipart抽象c?它定义了(jin)增加和删除及(qing)获得?sh)子邮g不同部分内容的方?׃Multipart是抽象类,我们必须为它使用一个具体的子类,JavaMail API提供<a class="Channel_KeyLink" >java</a>x.mail.Internet.MimeMultpartcL使用MimeMessage对象.<br /> <br /> 用法:<br /> MimeMultipart multipart=new MimeMultipart();<br /> <br /> ?我们使用MimeMultipart对象的一个方法是addBodyPart(),它在我们的电(sh)子邮件内定wdBodyPart(BodyPartcd下面紧接着要介l?对象.消息可以有很多部?一个BodyPart可以代表一个部?<br /> <br /> <br /> (9) <a class="Channel_KeyLink" >java</a>x.mail.Internet.MimeBodyPartc?br /> <br /> MimeBodyPart是BodyPart具体用于mimeMessage的一个子c?<br /> MimeBodyPart对象代表一个MimeMessage对象内容的一部分.每个MimeBodyPart被认为有两部?<br /> ⊙一个MIMEcd <br /> ⊙匹配这个类型的内容<br /> <br /> 用法:<br /> MimeBodyPart mdp=new MimeBodyPart();<br /> String text="Hello JavaMail!";<br /> mdp.setContent(text,"text/plain");//定义MIMEcd为text/plain,q设|MimeBodyPart的内?<br /> <br /> <br /> (10) <a class="Channel_KeyLink" >java</a>x.activation.DataHandlerc?包含在JAF?<br /> JavaMail API不限制信息只为文?M形式的信息都可能作茧(do)自缚(x)MimeMessage的一部分.除了(jin)文本信息,作ؓ(f)文g附g包含在电(sh)子邮件信息的一部分是很普遍?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" >java</a>x.activation.FileDataSourcec?包含在JAF?<br /> 一个FileDataSource对象可以表示本地文g和服务器可以直接讉K的资?一个本地文件可以通过创徏一个新的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" >java</a>x.activation.URLDataSourcec?包含在JAF?<br /> q程资源,URL不会(x)指向它们,׃个URLDataSource对象表示.一个远E资源可以通过创徏一个新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 /> 在明了(jin)JavaMail API的核?j)部分如何工作后Q本人将带领大家学习(fn)一些用Java Mail APId案例?br /> 1Q发送邮?br /> 在获得了(jin)Session后,建立q填入邮件信息,然后发送它到邮件服务器。这便是使用Java Mail API发送邮件的q程Q在发送邮件之前,我们需要设|SMTP服务器:(x)通过讄Properties的mail.smtp.host属性?br /> <br /> String host = ...;<br /> String from = ...;<br /> String to = ...;<br /> <br /> // Get system properties<br /> Properties props = System.getProperties();<br /> <br /> // Setup mail server<br /> props.put("mail.smtp.host", host);<br /> <br /> // Get session<br /> Session session = Session.getDefaultInstance(props, null);<br /> <br /> // Define message<br /> MimeMessage message = new MimeMessage(session);<br /> message.setFrom(new InternetAddress(from));<br /> message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));<br /> message.setSubject("Hello JavaMail");<br /> message.setText("Welcome to JavaMail");<br /> <br /> // Send message<br /> Transport.send(message);<br /> ׃建立邮g信息和发送邮件的q程中可能会(x)抛出异常Q所以我们需要将上面的代码放入到try-catchl构块中?br /> <br /> 2Q接攉?br /> Z(jin)在读取邮Ӟ我们获得?jin)sessionQƈ且连接到?jin)邮q相应storeQ打开相应的FolderQ然后得到我们想要的邮gQ当然别忘记?jin)在l束时关闭连接?br /> <br /> String host = ...;<br /> String username = ...;<br /> String password = ...;<br /> <br /> // Create empty properties<br /> Properties props = new Properties();<br /> <br /> // Get session<br /> Session session = Session.getDefaultInstance(props, null);<br /> <br /> // Get the store<br /> Store store = session.getStore("pop3");<br /> store.connect(host, username, password);<br /> <br /> // Get folder<br /> Folder folder = store.getFolder("INBOX");<br /> folder.open(Folder.READ_ONLY);<br /> <br /> // Get directory<br /> Message message[] = folder.getMessages();<br /> for (int i=0, n=message.length; i<n; i++) {      <br />   System.out.println(i + ": " + <br />   message[i].getFrom()[0] + "\t" + message[i].getSubject());<br /> }<br /> <br /> // Close connection <br /> folder.close(false);store.close();<br /> <br /> 上面的代码所作的是从邮箱中读取每个邮Ӟq且昄邮g的发信h地址和主题。从技术角度讲Q这里存在着一个异常的可能Q当发信人地址为空ӞgetFrom()[0]抛出异常?br /> <br /> 下面的代码片断有效的说明?jin)如何读取邮件内容,在显C每个邮件发信h和主题后Q将出现用户提示从而得到用h否读取该邮g的确认,如果输入YES的话Q我们可用Message.writeTo(java.io.OutputStream os)Ҏ(gu)邮件内容输出到控制CQ关?Message.writeTo()的具体用法请看JavaMail API?br /> <br /> BufferedReader reader = new BufferedReader (new InputStreamReader(System.in));<br /> <br /> // Get directory<br /> Message message[] = folder.getMessages();<br /> for (int i=0, n=message.length; i<n; i++) {<br />   System.out.println(i + ": " + message[i].getFrom()[0] + "\t" + message[i].getSubject());<br />   System.out.println("Do you want to read message? " + "[YES to read/QUIT to end]");  <br />   String line = reader.readLine();<br />   if ("YES".equals(line)) {<br />     message[i].writeTo(System.out);  <br />   } else if ("QUIT".equals(line)) {<br />     break;  <br />   }<br /> }<br /> <br /> 3Q删除邮件和标志<br /> 讄与message相关的Flags是删除邮件的常用Ҏ(gu)。这些Flags表示?jin)一些系l定义和用户定义的不同状态。在Flagscȝ内部cFlag中预定义?jin)一些标志:(x)<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 /> 但需要在使用时注意的Q标志存在ƈ非意味着q个标志被所有的邮g服务器所支持。例如,对于删除邮g的操作,POP协议不支持上面的M一个。所以要定哪些标志是被支持??通过讉K一个已l打开的Folder对象的getPermanetFlags()Ҏ(gu)Q它?yu)返回当前被支持的Flagscd象?br /> <br /> 删除邮gӞ我们可以讄邮g的DELETED标志Q?nbsp;<br /> message.setFlag(Flags.Flag.DELETED, true);<br /> <br /> 但是首先要采用READ_WRITE的方式打开FolderQ?br /> folder.open(Folder.READ_WRITE);<br /> <br /> 在对邮gq行删除操作后关闭FolderӞ需要传递一个true作ؓ(f)对删除邮件的擦除认?br /> folder.close(true);<br /> <br /> FoldercM另一U用于删除邮件的Ҏ(gu)expunge()也同样可删除邮gQ但是它q不为sun提供的POP3实现支持Q而其它第三方提供的POP3实现支持或者ƈ不支持这U方法?br /> 另外Q介l一U检查某个标志是否被讄的方法:(x)Message.isSet(Flags.Flag flag)Ҏ(gu)Q其中参Cؓ(f)被检查的标志?br /> <br /> 4Q邮件认?br /> 我们在前面已l学?x)?jin)如何使用AuthenticatorcL代替直接使用用户名和密码q两字符串作?Session.getDefaultInstance()或者Session.getInstance()Ҏ(gu)的参数。在前面的小试牛刀后,现在我们?<br /> <br /> ?jin)解到全面认识一下邮件认证?br /> 我们在此取代?jin)直接用邮件服务器L名、用户名、密码这三个字符串作接到POP3 Store的方式,使用存储?jin)邮件服务器L名信息的属性文Ӟq在获得Session时传入自定义的Authenticator实例Q?br /> <br /> // Setup properties<br /> Properties props = System.getProperties();<br /> props.put("mail.pop3.host", host);<br /> <br /> // Setup authentication, get session<br /> Authenticator auth = new PopupAuthenticator();<br /> Session session = Session.getDefaultInstance(props, auth);<br /> <br /> // Get the storeStore store = session.getStore("pop3");<br /> store.connect();<br /> <br /> PopupAuthenticator cȝ承了(jin)抽象cAuthenticatorQƈ且通过重蝲AuthenticatorcȝgetPasswordAuthentication()Ҏ(gu)q回PasswordAuthenticationcd象。而getPasswordAuthentication()Ҏ(gu)的参数param是以逗号分割的用户名、密码组成的字符丌Ӏ?br /> <br /> import javax.mail.*;<br /> import java.util.*;<br /> public class PopupAuthenticator extends Authenticator {  <br /> public PasswordAuthentication getPasswordAuthentication(String param) {<br />     String username, password;    <br />     StringTokenizer st = new StringTokenizer(param, ",");<br />     username = st.nextToken();<br />     password = st.nextToken();<br />     return new PasswordAuthentication(username, password);<br />   }<br /> }<br /> <br /> 5Q回复邮?br /> 回复邮g的方法很单:(x)使用Messagecȝreply()Ҏ(gu)Q通过配置回复邮g的收件h地址和主题(如果没有提供主题的话Q系l将默认?#8220;ReQ?#8221;作ؓ(f)邮g的主体)(j)Q这里不需要设|Q何的邮g内容Q只要复制发信h或者reply-to到新的收件h。而reply()Ҏ(gu)中的boolean参数表示是否邮件回复给发送者(参数gؓ(f)falseQ,或是恢复l所有hQ参数gؓ(f)trueQ?br /> 补充一下,reply-to地址需要在发信时用setReplyTo()Ҏ(gu)讄?br /> <br /> MimeMessage reply = (MimeMessage)message.reply(false);<br /> reply.setFrom(new InternetAddress("president@whitehouse.gov"));<br /> reply.setText("Thanks");<br /> Transport.send(reply);<br /> <br /> 6Q{发邮?br /> 转发邮g的过E不如前面的回复邮g那样单,它将建立一个{发邮Ӟqƈ非一个方法就能做到?br /> 每个邮g是由多个部分l成Q每个部分称Z个邮件体部分Q是一个BodyPartcd象,对于MIMEcd邮g来讲是MimeBodyPartcd象。这些邮件体包含在成为Multipart的容器中对于MIMEcd邮g来讲是MimeMultiPartcd象。在转发邮gӞ我们建立一个文字邮件体部分和一个被转发的文字邮件体部分Q然后将q两个邮件体攑ֈ一个Multipart中。说明一下,复制一个邮件内容到另一个邮件的Ҏ(gu)是仅复制它的 DataHandlerQ数据处理者)(j)卛_。这是由JavaBeans Activation Framework定义的一个类Q它提供?jin)对邮g内容的操作命令的讉K、管理了(jin)邮g内容操作Q是不同的数据源和数据格式之间的一致性接口?br /> <br /> // Create the message to forward<br /> Message forward = new MimeMessage(session);<br /> <br /> // Fill in headerforward.setSubject("Fwd: " + message.getSubject());<br /> forward.setFrom(new InternetAddress(from));<br /> forward.addRecipient(Message.RecipientType.TO,   new InternetAddress(to));<br /> <br /> // Create your new message part<br /> BodyPart messageBodyPart = new MimeBodyPart();<br /> messageBodyPart.setText(  "Here you go with the original message:\n\n");<br /> <br /> // Create a multi-part to combine the parts<br /> Multipart multipart = new MimeMultipart();<br /> multipart.addBodyPart(messageBodyPart);<br /> <br /> // Create and fill part for the forwarded contentmessage<br /> BodyPart = new MimeBodyPart();<br /> messageBodyPart.setDataHandler(message.getDataHandler());<br /> <br /> // Add part to multi part<br /> multipart.addBodyPart(messageBodyPart);<br /> <br /> // Associate multi-part with message<br /> forward.setContent(multipart);<br /> <br /> // Send message<br /> Transport.send(forward);<br /> <br /> 7Q用附?br /> 附g作ؓ(f)与邮件相关的资源l常以文本、表根{图片等格式出现Q如行的邮件客L(fng)一P我们可以用JavaMail API从邮件中获取附g或是发送带有附件的邮g?br /> <br /> AQ发送带有附件的邮g<br /> 发送带有附件的邮g的过E有些类D{发邮Ӟ我们需要徏立一个完整邮件的各个邮g体部分,在第一个部分(x们的邮g内容文字Q后Q增加一个具有DataHandler的附件而不是在转发邮g旉样复制第一个部分的DataHandler?br /> <br /> 如果我们文件作为附件发送,那么要徏立FileDataSourcecd的对象作为附件数据源Q如果从URLd数据作ؓ(f)附g发送,那么要建立URLDataSourcecd的对象作为附件数据源?br /> <br /> 然后这个数据源QF(tun)ileDataSource或是URLDataSourceQ对象作为DataHandlercL造方法的参数传入Q从而徏立一个DataHandler对象作ؓ(f)数据源的DataHandler?br /> <br /> 接着这个DataHandler讄为邮件体部分的DataHandler。这样就完成?jin)邮件体与附件之间的兌工作Q下面的工作是BodyPart的setFileName()Ҏ(gu)讄附g名ؓ(f)原文件名?br /> <br /> 最后将两个邮g体放入到Multipart中,讄邮g内容个容器MultipartQ发送邮件?br /> <br /> // Define message<br /> Message message = new MimeMessage(session);<br /> message.setFrom(new InternetAddress(from));<br /> message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));<br /> message.setSubject("Hello JavaMail Attachment");<br /> <br /> // Create the message part BodyPart message<br /> BodyPart = new MimeBodyPart();<br /> <br /> // Fill the message<br /> messageBodyPart.setText("Pardon Ideas");<br /> Multipart multipart = new MimeMultipart();<br /> multipart.addBodyPart(messageBodyPart);<br /> <br /> // Part two is attachment<br /> messageBodyPart = new MimeBodyPart();<br /> DataSource source = new FileDataSource(filename);<br /> messageBodyPart.setDataHandler(new DataHandler(source));<br /> messageBodyPart.setFileName(filename);<br /> multipart.addBodyPart(messageBodyPart);<br /> <br /> // Put parts in message<br /> message.setContent(multipart);<br /> <br /> // Send the message<br /> Transport.send(message);<br /> <br /> 如果我们使用servlet实现发送带有附件的邮gQ则必须上传附glservletQ这旉要注意提交页面form中对~码cd的设|应为multipart/form-data?br /> <br /> <FORM ENCTYPE="multipart/form-data" method="post" action="/myservlet"><br />    <INPUT TYPE="file" NAME="thefile"><br />   <INPUT TYPE="submit" VALUE="Upload"><br /> </FORM><br /> <br /> BQ读取邮件中的附?br /> d邮g中的附g的过E要比发送它的过E复杂一炏V因为带有附件的邮g是多部分l成的,我们必须处理每一个部分获得邮件的内容和附件?br /> 但是如何辨别邮g信息内容和附件呢QSun在Partc(BodyPartcd现的接口c)(j)中提供了(jin)getDisposition()Ҏ(gu)让开发者获得邮件体部分的部|类型,当该部分是附件时Q其q回之将是Part.ATTACHMENT。但附g也可以没有部|类型的方式存在或者部|类型ؓ(f) Part.INLINEQ无论部|类型ؓ(f)Part.ATTACHMENTq是Part.INLINEQ我们都能把该邮件体部分导出保存?br /> <br /> Multipart mp = (Multipart)message.getContent();<br /> for (int i=0, n=multipart.getCount(); i<n; i++) {<br />   Part part = multipart.getBodyPart(i));<br />   String disposition = part.getDisposition();<br />   if ((disposition != null) &&<br />        ((disposition.equals(Part.ATTACHMENT) ||<br />         (disposition.equals(Part.INLINE))) {<br />     saveFile(part.getFileName(), part.getInputStream());<br />   }<br /> }<br /> <br /> 下列代码中用了(jin)saveFileҎ(gu)是自定义的方法,它根据附件的文g名徏立一个文Ӟ如果本地盘上存在名为附件的文gQ那么将在文件名后增加数字表C区别。然后从邮g体中d数据写入到本地文件中Q代码省略)(j)?br /> <br /> // from saveFile()<br /> File file = new File(filename);<br /> for (int i=0; file.exists(); i++) {<br />   file = new File(filename+i);<br /> }<br /> <br /> 以上是邮件体部分被正设|的单例子,如果邮g体部分的部vcd为nullQ那么我们通过获得邮g体部分的MIMEcd来判断其cd作相应的处理Q代码结构框架如下:(x)<br /> <br /> if (disposition == null) {<br />   // Check if plain  <br />   MimeBodyPart mbp = (MimeBodyPart)part;<br />   if (mbp.isMimeType("text/plain")) {<br />     // Handle plain<br />   } else {<br />     // Special non-attachment cases here of<br />     // image/gif, text/html<br />     ...<br />   }<br />   ...<br /> }<br /> <br /> 8Q处理HTML邮g<br /> 前面的例子中发送的邮g都是以文本ؓ(f)内容的(除了(jin)附gQ,下面介l如何接收和发送基于HTML的邮件?br /> AQ发送HTML邮g<br /> 假如我们需要发送一个HTML文g作ؓ(f)邮g内容Qƈ佉K件客L(fng)在读取邮件时获取相关的图片或者文字的话,只要讄邮g内容为html代码Qƈ讄内容cd为text/html卛_Q?br /> <br /> String htmlText = "<H1>Hello</H1>" + "<img src=\"http://www.jguru.com/images/logo.gif\">";<br /> message.setContent(htmlText, "text/html"));<br /> <br /> h意:(x)q里的图片ƈ不是在邮件中内嵌的,而是在URL中定义的。邮件接收者只有在U时才能看到?br /> 在接攉件时Q如果我们用JavaMail API接收邮g的话是无法实CHTML方式昄邮g内容的。因为JavaMail API邮g内容视ؓ(f)二进制流。所以要昄HTML内容的邮Ӟ我们必须使用JEditorPane或者第三方HTML展现lg?br /> <br /> 以下代码昄?jin)如何用JEditorPane昄邮g内容Q?br /> if (message.getContentType().equals("text/html")) {<br />   String content = (String)message.getContent();<br />   JFrame frame = new JFrame();<br />   JEditorPane text = new JEditorPane("text/html", content);<br />   text.setEditable(false);<br />   JScrollPane pane = new JScrollPane(text);<br />   frame.getContentPane().add(pane);<br />   frame.setSize(300, 300);<br />   frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);<br />   frame.show();<br /> }<br /> <br /> BQ在邮g中包含图?br /> 如果我们在邮件中使用HTML作ؓ(f)内容Q那么最好将HTML中用的囄作ؓ(f)邮g的一部分Q这h论是否在UK?x)正的昄HTML中的囄。处理方法就是将HTML中用到的囄作ؓ(f)邮g附gq用特D的cid URL作ؓ(f)囄的引用,q个cid是对图片附件的Content-ID头的引用?br /> 处理内嵌囄像向邮件中d附g一P不同之处在于我们必须通过讄囄附g所在的邮g体部分的header中Content-IDZ个随机字W串Qƈ在HTML中img的src标记中设|ؓ(f)该字W串。这样就完成?jin)图片附件与HTML的关联?br /> <br /> String file = ...;<br /> // Create the message<br /> Message message = new MimeMessage(session);<br /> <br /> // Fill its headers<br /> message.setSubject("Embedded Image");<br /> message.setFrom(new InternetAddress(from));<br /> message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));<br /> <br /> // Create your new message part<br /> BodyPart messageBodyPart = new MimeBodyPart();<br /> String htmlText = "<H1>Hello</H1>" + "<img src=\"cid:memememe\">";<br /> messageBodyPart.setContent(htmlText, "text/html");<br /> <br /> // Create a related multi-part to combine the parts<br /> MimeMultipart multipart = new MimeMultipart("related");<br /> multipart.addBodyPart(messageBodyPart);<br /> <br /> // Create part for the image<br /> messageBodyPart = new MimeBodyPart();<br /> <br /> // Fetch the image and associate to part<br /> DataSource fds = new FileDataSource(file);<br /> messageBodyPart.setDataHandler(new DataHandler(fds));<br /> messageBodyPart.setHeader("Content-ID","<memememe>");<br /> <br /> // Add part to multi-part<br /> multipart.addBodyPart(messageBodyPart);<br /> <br /> // Associate multi-part with <br /> messagemessage.setContent(multipart);<br /> <br /> 9Q在邮g中搜索短?br /> JavaMail API提供?jin)过滤器机制Q它被用来徏立搜索短语。这个短语由javax.mail.search包中的SearchTerm抽象cL定义Q在定义后我们便可以使用Folder的Search()Ҏ(gu)在Folder中查NӞ(x)<br /> SearchTerm st = ...;Message[] msgs = folder.search(st);<br /> 下面?2个不同的c(l承?jin)SearchTermc)(j)供我们用:(x)<br /> AND       terms (class AndTerm)<br /> OR        terms (class OrTerm)<br /> NOT       terms (class NotTerm)<br /> SENT DATE terms (class SentDateTerm)<br /> CONTENT   terms (class BodyTerm)<br /> HEADER    terms (FromTerm / FromStringTerm, <br />                  RecipientTerm / RecipientStringTerm, SubjectTerm, etc.)<br /> 使用q些cd义的断语集合Q我们可以构造一个逻辑表达式,q在Folder中进行搜索。下面是一个实例:(x)在Folder中搜索邮件主题含?#8220;ADV”字符串或者发信h地址为friend@public.com的邮件?br /> <br /> SearchTerm st = new OrTerm(new SubjectTerm("ADV:"), new FromStringTerm("friend@public.com"));<br /> Message[] msgs = folder.search(st);<br /> <img src ="http://www.tkk7.com/AstroQi/aggbug/211873.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/AstroQi/" target="_blank">Astro.Qi</a> 2008-07-01 13:42 <a href="http://www.tkk7.com/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.tkk7.com/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.tkk7.com/AstroQi/archive/2008/06/26/210784.html</guid><wfw:comment>http://www.tkk7.com/AstroQi/comments/210784.html</wfw:comment><comments>http://www.tkk7.com/AstroQi/archive/2008/06/26/210784.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/AstroQi/comments/commentRss/210784.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/AstroQi/services/trackbacks/210784.html</trackback:ping><description><![CDATA[<div class="4yiygug" id="blog_text" class="cnt"> <h5>一、James?/h5> <p>Apache JamesQJava Apache Mail Enterprise ServerQ是Apachel织的子目之一Q完全采用纯Java技术开发,实现?jin)SMTP、POP3与NNTP{多U邮件相兛_议?/p> <p>James也是一个邮件应用^収ͼ可以通过Mailet扩充其功能,如Mail2SMS、Mail2Fax{。James提供?jin)比较完善的配置?gu)Q尤其是关于邮g内容存储和用户信息存储部分,可以选择在文件、数据库或其他介质中保存?/p> <p>James性能E_、可配置性强Q还是开源项目,所有源代码不存在版权问题,因此QJames在项目中的应用日益广泛,现在常用版本?.1Q但最新版?.3已经推出Q在本文中,我们仍以James2.1作ؓ(f)介绍蓝本?/p> <h5>二、一个假讄目</h5> <p>假设我要以James为邮件服务器Q开发一套基于Web的邮件系l,像263.netQ?63.net一P要求实现在线注册、在U收发邮件等功能?/p> <p>默认情况下,James的用户信息存储在文本中,虽然加了(jin)密,但由于文本存档不I不便于查询及(qing)相应处理Q幸好James提供?jin)多U用户信息存储方案,如数据库存储QLDAP存储{?/p> <p>q里我们以数据库存储ؓ(f)例,讲解用户信息的管理,数据库采用MySQL。当然你也可以采用LDAPQ比如免费的OpenLDAPQ功能非常强大?/p> <h5>三、用户信息的数据库存?/h5> <p><span style="color: red;">James邮g用户的用户信息默认保存在apps\james\var\users目录下,通过修改配置文gapps\james\SAR-INF\config.xmlQ可以把用户信息保存到数据库中,配置Ҏ(gu)如下Q?/span></p> <p>W一步:(x)在MySQL中新Z个数据库mailQ用户名rootQ密码ؓ(f)I;</p> <p>W二步:(x)打开config.xmlQ找?lt;users-store>q一,此面默认的内容ؓ(f)Q?/p> <p> <table bgcolor="#d9d9d9" border="1" cellpadding="0" cellspacing="0"> <tbody> <tr> <td class="text1" valign="top" width="537"><repository name="LocalUsers" class="org.apache.james.userrepository.UsersFileRepository"><br />          <destination URL="file://var/users/"/><br /> </repository></td> </tr> </tbody> </table> </p> <p>需要修改ؓ(f)Q?/p> <p> <table class="text1" bgcolor="#d9d9d9" border="1" cellpadding="0" cellspacing="0"> <tbody> <tr> <td valign="top" width="537"><repository name="LocalUsers" class="org.apache.james.userrepository.JamesUsersJdbcRepository" destinationURL="db://maildb/users"><br />         <sqlFile>file://conf/sqlResources.xml</sqlFile><br />       </repository></td> </tr> </tbody> </table> </p> <p>通过修改Q我们就把用户信息的存储介质从fileҎ(gu)?jin)dbQ?lt;sqlFile>是指明了(jin)在db中的数据表结构及(qing)相关数据库信息?/p> <p>W三步:(x)仍然是config.xmlQ找?lt;data-sources>,默认内容为空Q把此项内容修改为:(x)</p> <p> <table class="text1" bgcolor="#d9d9d9" border="1" cellpadding="0" cellspacing="0"> <tbody> <tr> <td valign="top" width="537"><data-source name="maildb" class="org.apache.james.util.mordred.JdbcDataSource"><br />                            <driver>org.gjt.mm.mysql.Driver</driver><br />                             <dburl>jdbc:mysql://127.0.0.1/mail</dburl><br />                             <user>root</user><br />                             <password></password><br />                             <max>20</max><br /> </data-source></td> </tr> </tbody> </table> </p> <p><driver>是指MySQL的JDBC驱动Q?lt;dburl>指数据库的访问\径,IP后的mail即MySQL中新建数据库名,接下来是用户名、密码及(qing)最大连接数?/p> <p>xQ数据库配置完成Q启动JamesQ若正常无误Q请通过telnetd一个新用户Q比如adduser holen 123456Q然后检查MySQL中的mail数据库,下面有一个表usersQ这是JamesҎ(gu)james_home\apps\james\conf的内容创建的?/p> <p>通过以上配置QJames的用户信息就可以保存在数据库中了(jin)?/p> <h5>四、密码问?br /> </h5> <p>当你通过telnetd新用hQ比如adduser holen 123456Q你可以查看数据库中的记录,W一个字D|holenQ第二字D|密码Q但密码q123456Q而一?#8220;q ”QzhwQUMTwdMqWfm/h0biB51GfQ——这是加密码后的密码内容Q再看后面的字段?#8220;SHA”Q显然用的是SHA加密方式?/p> <p>通过telnet方式d新用P用户密码自动加密,然后插入数据库中。但通过telnet方式q行用户理有着诸多不便Q尽你可以借助James的一个RMI工具包,提高效率Q但仍然没有本质改变Q当需要用作商业用途时Q你更不能要求你的客L(fng)记那一堆命令符?/p> <p>一般我们可以做一个Web前端Q通过|页形式Q添加修改用P界面友好Q傻瓜化使用Q如263?63一栗若q样做,我们需要直接操作数据库Q? d用户记录或修改删除用戯录了(jin)。但别忘?jin),James默认对用户密码是加密的,既然我们要直接操作数据库Q那么我们只有两个选择Q要么我们研I其密码 机制Q添加记录时Q我们对新增用户的密码进行同样加密,要么我们LJames的加密机Ӟ使其明码保存?/p> <p>q好Q这两种选择都是可行的。我们从Apache|站下蝲James的源码包Q下载后的文件ؓ(f)james-2.1-src.zipQ接q?MQ通过分析源码Q我们发玎ͼ<span style="color: red;">与用户密码相关的文g是DefaultUser.java</span>Q部分源码如下:(x)</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 /> ……<br /> /**<br />      * Method to verify passwords. <br />      *<br />      * @param pass the String that is claimed to be the password for this user<br />      * @return true if the hash of pass with the current algorithm matches<br />      * the stored hash.<br />      */<br />     public boolean verifyPassword(String pass) {<br />         try {<br />             String hashGuess = DigestUtil.digestString(pass, algorithm);<br />             return hashedPassword.equals(hashGuess);<br />         } catch (NoSuchAlgorithmException nsae) {<br />         throw new RuntimeException("Security error: " + nsae);<br />     }<br />     }<br /> <br />     /**<br />      * Sets new password from String. No checks made on guessability of<br />      * password.<br />      *<br />      * @param newPass the String that is the new password.<br />      * @return true if newPass successfuly hashed<br />      */<br />     public boolean setPassword(String newPass) {<br />         try {<br />             hashedPassword = DigestUtil.digestString(newPass, algorithm);<br />             return true;<br />         } catch (NoSuchAlgorithmException nsae) {<br />             throw new RuntimeException("Security error: " + nsae);<br />         }<br /> }<br /> ……</td> </tr> </tbody> </table> </p> <p> </p> <p>W一个方法verifyPassword()是用来做密码认证Q传入的参数是明文密码,通过DigestUtil.digestString()? 法,转换成密文密码,然后与数据库中密码作比较Q返回比较结果。请注意q里的DigestUtil.digestString()Ҏ(gu)Q在后面q在提到?/p> <p>W二个方法setPassword()是用于密码{换的Q把明文转成密文Q用的同hDigestUtil.digestString()Ҏ(gu)?/p> <p>谈到q里Q相信你应该知道怎么在自qE序中进行密码{换和密码认证?jin)吧Q其实ƈ不是要你自己d一个SHA的加密算法,既然James已经提供?jin)此功能Q你调用便是?jin)?/p> <p>q有一U情况,开发者需要在数据库中必须用明文保存密码,q样׃必在自己写的E序中进行密码{换了(jin)Q而且当多个应用系l采用统一用户模型Ӟ最? 只有一个用户实例。要实现q个需求,只能修改James源代码了(jin)Q把verifyPassword()Ҏ(gu)和setPassword()Ҏ(gu)Q?/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) {       <br />             return hashedPassword.equals(pass);       <br /> }   <br /> public boolean setPassword(String newPass) {      <br />             hashedPassword = newPass;<br />             return true;       <br /> }</td> </tr> </tbody> </table> </p> <p>其实是把{换过E去掉,保存和认证就都采用明文进行了(jin)?/p> <p>你要是觉得SHA方式不妥Q也可以挂接别的加密方式Q同h修改q两个方法?/p> <p>注意Q当你修改了(jin)James的源码后Q你需要用Ant重新build James目Qbuild后将在james-2.1-src\dist\james-2.1\apps下面扑ֈ新生成的james.sar文g。把该文 件覆盖James原来james.sarQƈ删除与james.sar同的james目录Q重启动james卛_。徏议保留原来的 config.xmlQ免得又配一ơ?/p> <p>通过以上探讨Q我们明白了(jin)如何通过Web方式q行用户注册和用L(fng)记等。需要说明一Ҏ(gu)QJames自动生成的users表中只有7个字D,而且? 是系l需要用的。一般注册时需要输入的信息Ҏ(gu)较多Q这时徏议开发者自己再Z个新表USERINFOQ用username把两个表兌hQ不? 改users表的内容Q如果想试试Q请参?a href="file://conf/sqlResources.xml">james_home\apps\james\conf</a>Q?/p> <h5>五、基于James的邮件系l开发方案简q?/h5> <p><br /> </p> <p>Jamesq行在Win2000上,客户端采用Web界面Q仿263风格Q、Foxmail或OutLook ExpressQ该pȝ主要面向1000Z下的中小企业?/p> <p>ZJames的邮件开发,主要包括两个斚wQ一是邮件系l的后台理Q另一个是客户端应用系l?/p> <p>后台理的功能主要包括用L(fng)d、删除、修攏V用户用空间指配、邮件备份等?/p> <p>Web客户端功能包括收件箱、发邮g、发件箱、草E箱、回收站、地址本、自定义文g夏V配|等?/p> <p>用户信息存储在MySQL数据库中Q邮件内定w认存储在文档中?/p> <p>pȝ采用Struts架构Q运行环境ؓ(f)Apache1.3+Tomcat4.1Q数据库q接池采用Tomcat自带的DBCP?/p> <p>pȝ开发预计需60人天完成Q开发h员需要掌握Struts和JavaMail?/p> <p>压力试过50个ƈ发?/p> <h5>六、参考资?/h5> <p>James 2.1 Documentation</p> </div> <img src ="http://www.tkk7.com/AstroQi/aggbug/210784.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/AstroQi/" target="_blank">Astro.Qi</a> 2008-06-26 11:55 <a href="http://www.tkk7.com/AstroQi/archive/2008/06/26/210784.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Apache james 使用入门http://www.tkk7.com/AstroQi/archive/2008/06/26/210781.htmlAstro.QiAstro.QiThu, 26 Jun 2008 03:52:00 GMThttp://www.tkk7.com/AstroQi/archive/2008/06/26/210781.htmlhttp://www.tkk7.com/AstroQi/comments/210781.htmlhttp://www.tkk7.com/AstroQi/archive/2008/06/26/210781.html#Feedback0http://www.tkk7.com/AstroQi/comments/commentRss/210781.htmlhttp://www.tkk7.com/AstroQi/services/trackbacks/210781.html
一、简?/h5>

Apache JamesQJava Apache Mail Enterprise ServerQ是Apachel织的子目之一Q完全采用纯Java技术开发,实现?jin)SMTP、POP3与NNTP{多U邮件相兛_议?/p>

James也是一个邮件应用^収ͼ可以通过Mailet扩充其功能,如Mail2SMS、Mail2Fax{。James提供?jin)比较完善的配置?gu)Q尤其是关于邮g内容存储和用户信息存储部分,可以选择在文件、数据库或其他介质中保存?/p>

James性能E_、可配置性强Q还是开源项目,所有源代码不存在版权问题,因此QJames在项目中的应用日益广泛,现在常用版本?.1Q但最新版?.3已经推出Q在本文中,我们仍以James2.1作ؓ(f)介绍蓝本?/p>

二、安装与配置

James的安装配|过E非常简单?/p>

W一步:(x)安装JDK

请用JDK1.3以上版本Q推荐用JDK1.4Q,假设安装在c:\jdk1.3?/p>

W二步:(x)下蝲JamesQƈ解压

可以到Apache|站上下载James2.1Q下载将得到一个压~文件james-2.1.zipQ大ؓ(f)4.45MQ将此包解压到c:\james?/p>

W三步:(x)直接q行或需要配|JAVA_HOME

q时Q可以尝试直接双击c:\james\bin\run.batQ若启动无误Q将提示如下Q?/p>
Using PHOENIX_HOME: C:\james
Using PHOENIX_TMPDIR: C:\james\temp
Using JAVA_HOME:

Phoenix 4.0.1

James 2.1
Remote Manager Service started plain:4555
POP3 Service started plain:110
SMTP Service started plain:25
NNTP Service Disabled
Fetch POP Disabled

也有可能启动不了(jin)Qƈ报JAVA_HOME找不刎ͼq时Q需要指定JAVA_HOMEQ比较简单的Ҏ(gu)是在c:\james\bin\run.bat中指定JAVA_HOMEQ修改后的run.bat如下Q?/p>
……
rem
rem Determine if JAVA_HOME is set and if so then use it
rem
set JAVA_HOME= c:\jdk1.3
if not "%JAVA_HOME%"=="" goto found_java
……

修改完后再运行run.batQ应该就可以正常启动?jin),若还有什么问题,请参见本文的FAQ部分?/p>

三、项目应?/h5>

1?目需?/strong>

某单位,?6个职能处室,?8台电(sh)脑(操作pȝ为Win98/2000/xpQ,其中?Cؓ(f)专用服务器(Win2000Q,已连成局域网。ؓ(f)使单位内部的信息交流Q尤其是文g交互更加便捷Q单位决定在局域网内部架设一套E-mailpȝ?/p>

2?解决Ҏ(gu)

在专用服务器上安装James2.1Q客L(fng)使用操作pȝ自带的Outlook Express?/p>

3?服务器端配置

首先扑և专用服务器的名字Q假讑֏unitname?/p>

然后打开文gc:\james\apps\james\SAR-INF\config.xml?/p>

在config.xml文g中,扑ֈ Postmaster@localhostQ把此项改ؓ(f) Postmaster@unitnameQ同理,扑ֈlocalhostQ把此项改ؓ(f)unitname。其实,改这两项是把默认的localhost改ؓ(f)机器名,q样做是Z(jin)让其它机器也能访问邮件系l,当然Q前提是在局域网上没有与服务器重名的机器?/p>

4?客户端配|?/strong>

假设有一个̎P用户名ؓ(f)holenQ密码ؓ(f)123456Q如何在Outlook中配|呢Q?/p>

首先Q根据用户名Q可以得?gu)用户邮箱地址?font color="#0000ff">holen@unitname Q然后在输入POP3和SMTP服务器时Q直接用服务器机器名unitname卛_?/p>

5?帐号理

James的̎L(fng)理是通过telnet完成的,d命o(h)为:(x)

telnet unitname 4555

其中unitname也可以换成IPQ?555是端口号。登录时需要用户名和密码,初始的用户名和密码均为root。若d成功Q提C如下:(x)

JAMES Remote Administration Tool 2.1
Please enter your login and password
Login id:
Password:
Welcome root. HELP for a list of commands

需要注意的是,所有敲入的命o(h)都不昄在屏q上?/p>

输入helpQ将出现命o(h)的帮助,信息如下Q?/p>

JAMES Remote Administration Tool 2.1
Please enter your login and password
Login id:
Password:
Welcome root. HELP for a list of commands
Currently implemented commands:
help display this help
listusers display existing accounts
countusers display the number of existing accounts
adduser [username] [password] add a new user
verify [username] verify if specified user exist
deluser [username] delete existing user
setpassword [username] [password] sets a users password
setalias [alias] [user] locally forwards all email for alias t
o user
unsetalias [alias] unsets an alias
setforwarding [username] [emailaddress] forwards a users email to another email
address
unsetforwarding [username] removes a forward
user [repositoryname] change to another user repository
shutdown kills the current JVM (convenient when J
ames is run as a daemon)
quit close connection

常用的命令有listusers、countusers、adduser、deluser、setpassword{?/p>

其中d用户为adduserQ例如:(x)adduser holen 123456?/p>

通过q个后台理界面Q管理员可以实现̎L(fng)理及(qing)其他相应的管理功能?/p>

6?应用情况

q套pȝ在该单位l过一周的试运行后Q已正式q行两个月,用户数约百hQ一直很E_Q期_(d)因操作系l故障,服务器重启两ơ,其他旉Q一直处于运行状态,性能E_Q响应速度快?/p>

四、FAQ

1?在启动jamesӞ提示POP3或SMTP不能使用Q?/strong>

h查一下,?#8220;理工具?gt;服务”里面Q是不是启动?jin)别的邮件服务器Q已?10?5端口占用?jin)?/p>

2?JAVA_HOME找不刎ͼ

请在run.bat中指定JAVA_HOMEQ若q不行,请在“我的?sh)脑?gt;pȝ?gt;高?gt;环境变量”中添加一JAVA_HOMEQ一般不推荐q么做)(j)?/p>

3?服务器启动正常,但客L(fng)不能收发邮gQ?/strong>

h查客L(fng)配置是否正常Q参照前面所Ԍ另外Q请(g)查james下的config.xmlQ是否把localhostҎ(gu)?jin)机器名?/p>

五、ȝ

M而言QJames是一Ƒ֍分优U的邮件服务器Q具有性能E_、扩展性好、可配置性强、响应速度快、源码公开{优炏V同Ӟ׃James的后台管理不够方ѝ缺必要的技术支持等原因Q限制了(jin)james的高端企业应用?/p>

q前情况而言QJames主要用于1000用户量以内的邮gpȝQ而且当James用于商业性项目时Q开发商一般需要对Jamesq行相应的包装,主要是后台管理这一块?/p>



Astro.Qi 2008-06-26 11:52 发表评论
]]>Apache james mailserver + Claros inTouch webmailhttp://www.tkk7.com/AstroQi/archive/2008/06/26/210764.htmlAstro.QiAstro.QiThu, 26 Jun 2008 02:44:00 GMThttp://www.tkk7.com/AstroQi/archive/2008/06/26/210764.htmlhttp://www.tkk7.com/AstroQi/comments/210764.htmlhttp://www.tkk7.com/AstroQi/archive/2008/06/26/210764.html#Feedback30http://www.tkk7.com/AstroQi/comments/commentRss/210764.htmlhttp://www.tkk7.com/AstroQi/services/trackbacks/210764.html阅读全文

Astro.Qi 2008-06-26 10:44 发表评论
]]>
FCKeditor2.6 for JSP 配置Ҏ(gu)http://www.tkk7.com/AstroQi/archive/2008/06/24/210344.htmlAstro.QiAstro.QiTue, 24 Jun 2008 08:55:00 GMThttp://www.tkk7.com/AstroQi/archive/2008/06/24/210344.htmlhttp://www.tkk7.com/AstroQi/comments/210344.htmlhttp://www.tkk7.com/AstroQi/archive/2008/06/24/210344.html#Feedback10http://www.tkk7.com/AstroQi/comments/commentRss/210344.htmlhttp://www.tkk7.com/AstroQi/services/trackbacks/210344.html阅读全文

Astro.Qi 2008-06-24 16:55 发表评论
]]>
վ֩ģ壺 ձѹۿ| ëƬ߹ۿ| ްv2017| ƷɫҹƵѿ| þ޾Ʒϵַ| 91ƷѹƬ| ߹ۿ| 18Ůվ| պĻò| ձѹۿ| wŷs| 㻨߹ۿѹۿ| | һ| Ʒavɫ| ձɫַ| һëƬѹۿշ| ޾ƷӰ߲Ʒ| ޵Ƶѹۿ1000| Av뾫Ʒ| ƷѾƷ| þ޾ƷVA| 91ѹԲ| Ļ| պҹƵ| ҹɫ˽ӰԺվ| Ʒۺһ| þù׾Ʒǿ| ޻ɫվ| ӯӯӰԺƵۿһ| av뾫Ʒַ| ߲| Ůһһ鴤Ƶ| ޾ƷþþþþĻ| þþþùƷѿ| ޹߶| ߿Ƭ˳Ƶڵ| Ů18һëƬѿ| һƷ| 222www߹ۿ| |