﻿<?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-liuzheng-文章分类-JAVA General</title><link>http://www.blogjava.net/liuzheng/category/25219.html</link><description /><language>zh-cn</language><lastBuildDate>Wed, 02 Apr 2008 14:18:04 GMT</lastBuildDate><pubDate>Wed, 02 Apr 2008 14:18:04 GMT</pubDate><ttl>60</ttl><item><title>Date 和 Calender 的转化</title><link>http://www.blogjava.net/liuzheng/articles/190386.html</link><dc:creator>刘铮 </dc:creator><author>刘铮 </author><pubDate>Wed, 02 Apr 2008 07:40:00 GMT</pubDate><guid>http://www.blogjava.net/liuzheng/articles/190386.html</guid><wfw:comment>http://www.blogjava.net/liuzheng/comments/190386.html</wfw:comment><comments>http://www.blogjava.net/liuzheng/articles/190386.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liuzheng/comments/commentRss/190386.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liuzheng/services/trackbacks/190386.html</trackback:ping><description><![CDATA[<div id="related_topics" style="position: relative" _eventid="3" _madepositioned="true">&nbsp;</div>
<script type="text/javascript">
            new Draggable("related_topics");
          </script>1.计算某一月份的最大天数 <br />
<br />
Calendar time=Calendar.getInstance(); <br />
time.clear(); <br />
time.set(Calendar.YEAR,year); //year 为 int <br />
time.set(Calendar.MONTH,i-1);//注意,Calendar对象默认一月为0 <br />
int day=time.getActualMaximum(Calendar.DAY_OF_MONTH);//本月份的天数 <br />
注：在使用set方法之前，必须先clear一下，否则很多信息会继承自系统当前时间 <br />
<br />
2.Calendar和<span class="hilite1"><span class="hilite1">Date</span></span>的转化 <br />
<br />
(1) Calendar转化为<span class="hilite1"><span class="hilite1">Date</span></span> <br />
Calendar cal=Calendar.getInstance(); <br />
<span class="hilite1"><span class="hilite1">Date</span></span> <span class="hilite1"><span class="hilite1">date</span></span>=cal.getTime(); <br />
<br />
(2) <span class="hilite1"><span class="hilite1">Date</span></span>转化为Calendar <br />
<span class="hilite1"><span class="hilite1">Date</span></span> <span class="hilite1"><span class="hilite1">date</span></span>=new <span class="hilite1"><span class="hilite1">Date</span></span>(); <br />
Calendar cal=Calendar.getInstance(); <br />
cal.setTime(<span class="hilite1"><span class="hilite1">date</span></span>); <br />
<br />
3.格式化输出日期时间 （这个用的比较多） <br />
<br />
<span class="hilite1"><span class="hilite1">Date</span></span> <span class="hilite1"><span class="hilite1">date</span></span>=new <span class="hilite1"><span class="hilite1">Date</span></span>(); <br />
Simple<span class="hilite1"><span class="hilite1">Date</span></span>Format df=new Simple<span class="hilite1"><span class="hilite1">Date</span></span>Format("yyyy-MM-dd hh:mm:ss"); <br />
String time=df.format(<span class="hilite1"><span class="hilite1">date</span></span>); <br />
System.out.println(time); <br />
<br />
4.计算一年中的第几星期 <br />
<br />
(1)计算某一天是一年中的第几星期 <br />
Calendar cal=Calendar.getInstance(); <br />
cal.set(Calendar.YEAR, 2006); <br />
cal.set(Calendar.MONTH, 8); <br />
cal.set(Calendar.DAY_OF_MONTH, 3); <br />
int weekno=cal.get(Calendar.WEEK_OF_YEAR); <br />
<br />
(2)计算一年中的第几星期是几号 <br />
Simple<span class="hilite1"><span class="hilite1">Date</span></span>Format df=new Simple<span class="hilite1"><span class="hilite1">Date</span></span>Format("yyyy-MM-dd"); <br />
Calendar cal=Calendar.getInstance(); <br />
cal.set(Calendar.YEAR, 2006); <br />
cal.set(Calendar.WEEK_OF_YEAR, 1); <br />
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY); <br />
System.out.println(df.format(cal.getTime())); <br />
输出: <br />
2006-01-02 <br />
<br />
5.add()和roll()的用法(不太常用) <br />
<br />
(1)add()方法 <br />
Simple<span class="hilite1"><span class="hilite1">Date</span></span>Format df=new Simple<span class="hilite1"><span class="hilite1">Date</span></span>Format("yyyy-MM-dd"); <br />
Calendar cal=Calendar.getInstance(); <br />
cal.set(Calendar.YEAR, 2006); <br />
cal.set(Calendar.MONTH, 8); <br />
cal.set(Calendar.DAY_OF_MONTH, 3); <br />
cal.add(Calendar.<span class="hilite1"><span class="hilite1">DATE</span></span>, -4); <br />
<span class="hilite1"><span class="hilite1">Date</span></span> <span class="hilite1"><span class="hilite1">date</span></span>=cal.getTime(); <br />
System.out.println(df.format(<span class="hilite1"><span class="hilite1">date</span></span>)); <br />
cal.add(Calendar.<span class="hilite1"><span class="hilite1">DATE</span></span>, 4); <br />
<span class="hilite1"><span class="hilite1">date</span></span>=cal.getTime(); <br />
System.out.println(df.format(<span class="hilite1"><span class="hilite1">date</span></span>)); <br />
输出： <br />
2006-08-30 <br />
2006-09-03 <br />
(2)roll方法 <br />
cal.set(Calendar.YEAR, 2006); <br />
cal.set(Calendar.MONTH, 8); <br />
cal.set(Calendar.DAY_OF_MONTH, 3); <br />
cal.roll(Calendar.<span class="hilite1"><span class="hilite1">DATE</span></span>, -4); <br />
<span class="hilite1"><span class="hilite1">date</span></span>=cal.getTime(); <br />
System.out.println(df.format(<span class="hilite1"><span class="hilite1">date</span></span>)); <br />
cal.roll(Calendar.<span class="hilite1"><span class="hilite1">DATE</span></span>, 4); <br />
<span class="hilite1"><span class="hilite1">date</span></span>=cal.getTime(); <br />
System.out.println(df.format(<span class="hilite1"><span class="hilite1">date</span></span>)); <br />
输出： <br />
2006-09-29 <br />
2006-09-03 <br />
可见，roll()方法在本月内循环，一般使用add()方法； <br />
<br />
6.计算两个任意时间中间的间隔天数（这个比较常用） <br />
(1)传进Calendar对象 <br />
public int getIntervalDays(Calendar startday,Calendar endday)...{ <br />
if(startday.after(endday))...{ <br />
Calendar cal=startday; <br />
startday=endday; <br />
endday=cal; <br />
} <br />
long sl=startday.getTimeInMillis(); <br />
long el=endday.getTimeInMillis(); <br />
<br />
long ei=el-sl; <br />
return (int)(ei/(1000*60*60*24)); <br />
} <br />
(2)传进<span class="hilite1"><span class="hilite1">Date</span></span>对象 <br />
<br />
public int getIntervalDays(<span class="hilite1"><span class="hilite1">Date</span></span> startday,<span class="hilite1"><span class="hilite1">Date</span></span> endday)...{ <br />
if(startday.after(endday))...{ <br />
<span class="hilite1"><span class="hilite1">Date</span></span> cal=startday; <br />
startday=endday; <br />
endday=cal; <br />
} <br />
long sl=startday.getTime(); <br />
long el=endday.getTime(); <br />
long ei=el-sl; <br />
return (int)(ei/(1000*60*60*24)); <br />
} <br />
(3)改进精确计算相隔天数的方法 <br />
public int getDaysBetween (Calendar d1, Calendar d2) ...{ <br />
if (d1.after(d2)) ...{ <br />
java.util.Calendar swap = d1; <br />
d1 = d2; <br />
d2 = swap; <br />
} <br />
int days = d2.get(Calendar.DAY_OF_YEAR) - d1.get(Calendar.DAY_OF_YEAR); <br />
int y2 = d2.get(Calendar.YEAR); <br />
if (d1.get(Calendar.YEAR) != y2) ...{ <br />
d1 = (Calendar) d1.clone(); <br />
do ...{ <br />
days += d1.getActualMaximum(Calendar.DAY_OF_YEAR);//得到当年的实际天数 <br />
d1.add(Calendar.YEAR, 1); <br />
} while (d1.get(Calendar.YEAR) != y2); <br />
} <br />
return days; <br />
} <br />
注意：通过上面的方法可以衍生出求任何时间，如要查出邮箱三周之内收到的邮件（得到当前系统时间－再得到三周前时间）用收件的时间去匹配 最好装化成 long去比较 <br />
如：1年前日期（注意毫秒的转换） <br />
java.util.<span class="hilite1"><span class="hilite1">Date</span></span> my<span class="hilite1"><span class="hilite1">Date</span></span>=new java.util.<span class="hilite1"><span class="hilite1">Date</span></span>(); <br />
long myTime=(my<span class="hilite1"><span class="hilite1">Date</span></span>.getTime()/1000)-60*60*24*365; <br />
my<span class="hilite1"><span class="hilite1">Date</span></span>.setTime(myTime*1000); <br />
String m<span class="hilite1"><span class="hilite1">Date</span></span>=formatter.format(my<span class="hilite1"><span class="hilite1">Date</span></span>); <br />
<br />
7. String 和 <span class="hilite1"><span class="hilite1">Date</span></span> ，Long 之间相互转换 （最常用） <br />
<br />
字符串转化成时间类型（字符串可以是任意类型，只要和Simple<span class="hilite1"><span class="hilite1">Date</span></span>Format中的格式一致即可） <br />
通常我们取时间跨度的时候，会substring出具体时间－－long－比较 <br />
<br />
java.text.Simple<span class="hilite1"><span class="hilite1">Date</span></span>Format sdf = new java.text.Simple<span class="hilite1"><span class="hilite1">Date</span></span>Format("M/dd/yyyy hh:mm:ss a",java.util.Locale.US); <br />
java.util.<span class="hilite1"><span class="hilite1">Date</span></span> d = sdf.parse("5/13/2003 10:31:37 AM"); <br />
long dvalue=d.getTime(); <br />
Simple<span class="hilite1"><span class="hilite1">Date</span></span>Format formatter = new Simple<span class="hilite1"><span class="hilite1">Date</span></span>Format("yyyy-MM-dd HH:mm:ss"); <br />
String m<span class="hilite1"><span class="hilite1">Date</span></span>Time1=formatter.format(d); <br />
<br />
8. 通过时间求时间 <br />
<br />
年月周求日期 <br />
Simple<span class="hilite1"><span class="hilite1">Date</span></span>Format formatter2 = new Simple<span class="hilite1"><span class="hilite1">Date</span></span>Format("yyyy-MM F E"); <br />
java.util.<span class="hilite1"><span class="hilite1">Date</span></span> <span class="hilite1"><span class="hilite1">date</span></span>2= formatter2.parse("2003-05 5 星期五"); <br />
Simple<span class="hilite1"><span class="hilite1">Date</span></span>Format formatter3 = new Simple<span class="hilite1"><span class="hilite1">Date</span></span>Format("yyyy-MM-dd"); <br />
String my<span class="hilite1"><span class="hilite1">date</span></span>2=formatter3.format(<span class="hilite1"><span class="hilite1">date</span></span>2); <br />
<br />
求是星期几 <br />
my<span class="hilite1"><span class="hilite1">date</span></span>= myFormatter.parse("2001-1-1"); <br />
Simple<span class="hilite1"><span class="hilite1">Date</span></span>Format formatter4 = new Simple<span class="hilite1"><span class="hilite1">Date</span></span>Format("E"); <br />
String my<span class="hilite1"><span class="hilite1">date</span></span>3=formatter4.format(my<span class="hilite1"><span class="hilite1">date</span></span>); <br />
<br />
9. java 和 具体的数据库结合 <br />
<br />
在开发web应用中，针对不同的数据库日期类型，我们需要在我们的程序中对日期类型做各种不同的转换。若对应数据库数据是oracle的<span class="hilite1"><span class="hilite1">Date</span></span>类型，即只需要年月日的，可以选择使用java.sql.<span class="hilite1"><span class="hilite1">Date</span></span>类型，若对应的是MSsqlserver 数据库的<span class="hilite1"><span class="hilite1">Date</span></span>Time类型，即需要年月日时分秒的，选择java.sql.Timestamp类型 <br />
你可以使用<span class="hilite1"><span class="hilite1">date</span></span>Format定义时间日期的格式，转一个字符串即可 <br />
<br />
class <span class="hilite1"><span class="hilite1">Date</span></span>test{ <br />
*method 将字符串类型的日期转换为一个timestamp（时间戳记java.sql.Timestamp） <br />
*@param <span class="hilite1"><span class="hilite1">date</span></span>String 需要转换为timestamp的字符串 <br />
*@return dataTime timestamp <br />
<br />
public final static java.sql.Timestamp string2Time(String <span class="hilite1"><span class="hilite1">date</span></span>String) <br />
throws java.text.ParseException { <br />
<span class="hilite1"><span class="hilite1">Date</span></span>Format <span class="hilite1"><span class="hilite1">date</span></span>Format; <br />
<span class="hilite1"><span class="hilite1">date</span></span>Format = new Simple<span class="hilite1"><span class="hilite1">Date</span></span>Format("yyyy-MM-dd kk:mm:ss.SSS", Locale.ENGLISH);//设定格式 <br />
//<span class="hilite1"><span class="hilite1">date</span></span>Format = new Simple<span class="hilite1"><span class="hilite1">Date</span></span>Format("yyyy-MM-dd kk:mm:ss", Locale.ENGLISH); <br />
<span class="hilite1"><span class="hilite1">date</span></span>Format.setLenient(false); <br />
java.util.<span class="hilite1"><span class="hilite1">Date</span></span> time<span class="hilite1"><span class="hilite1">Date</span></span> = <span class="hilite1"><span class="hilite1">date</span></span>Format.parse(<span class="hilite1"><span class="hilite1">date</span></span>String);//util类型 <br />
java.sql.Timestamp <span class="hilite1"><span class="hilite1">date</span></span>Time = new java.sql.Timestamp(time<span class="hilite1"><span class="hilite1">Date</span></span>.getTime());//Timestamp类型,time<span class="hilite1"><span class="hilite1">Date</span></span>.getTime()返回一个long型 <br />
return <span class="hilite1"><span class="hilite1">date</span></span>Time; <br />
} <br />
<br />
*method 将字符串类型的日期转换为一个<span class="hilite1"><span class="hilite1">Date</span></span>（java.sql.<span class="hilite1"><span class="hilite1">Date</span></span>） <br />
*@param <span class="hilite1"><span class="hilite1">date</span></span>String 需要转换为<span class="hilite1"><span class="hilite1">Date</span></span>的字符串 <br />
*@return dataTime <span class="hilite1"><span class="hilite1">Date</span></span> <br />
<br />
public final static java.sql.<span class="hilite1"><span class="hilite1">Date</span></span> string2<span class="hilite1"><span class="hilite1">Date</span></span>(String <span class="hilite1"><span class="hilite1">date</span></span>String) <br />
throws java.lang.Exception { <br />
<span class="hilite1"><span class="hilite1">Date</span></span>Format <span class="hilite1"><span class="hilite1">date</span></span>Format; <br />
<span class="hilite1"><span class="hilite1">date</span></span>Format = new Simple<span class="hilite1"><span class="hilite1">Date</span></span>Format("yyyy-MM-dd", Locale.ENGLISH); <br />
<span class="hilite1"><span class="hilite1">date</span></span>Format.setLenient(false); <br />
java.util.<span class="hilite1"><span class="hilite1">Date</span></span> time<span class="hilite1"><span class="hilite1">Date</span></span> = <span class="hilite1"><span class="hilite1">date</span></span>Format.parse(<span class="hilite1"><span class="hilite1">date</span></span>String);//util类型 <br />
java.sql.<span class="hilite1"><span class="hilite1">Date</span></span> <span class="hilite1"><span class="hilite1">date</span></span>Time = new java.sql.<span class="hilite1"><span class="hilite1">Date</span></span>(time<span class="hilite1"><span class="hilite1">Date</span></span>.getTime());//sql类型 <br />
return <span class="hilite1"><span class="hilite1">date</span></span>Time; <br />
} <br />
<br />
public static void main(String[] args){ <br />
<span class="hilite1"><span class="hilite1">Date</span></span> da = new <span class="hilite1"><span class="hilite1">Date</span></span>(); <br />
注意：这个地方da.getTime()得到的是一个long型的值 <br />
System.out.println(da.getTime()); <br />
<br />
由日期<span class="hilite1"><span class="hilite1">date</span></span>转换为timestamp <br />
<br />
第一种方法：使用new Timestamp(long) <br />
Timestamp t = new Timestamp(new <span class="hilite1"><span class="hilite1">Date</span></span>().getTime()); <br />
System.out.println(t); <br />
<br />
第二种方法：使用Timestamp(int year,int month,int <span class="hilite1"><span class="hilite1">date</span></span>,int hour,int minute,int second,int nano) <br />
Timestamp tt = new Timestamp(Calendar.getInstance().get( <br />
Calendar.YEAR) - 1900, Calendar.getInstance().get( <br />
Calendar.MONTH), Calendar.getInstance().get( <br />
Calendar.<span class="hilite1"><span class="hilite1">DATE</span></span>), Calendar.getInstance().get( <br />
Calendar.HOUR), Calendar.getInstance().get( <br />
Calendar.MINUTE), Calendar.getInstance().get( <br />
Calendar.SECOND), 0); <br />
System.out.println(tt); <br />
<br />
try { <br />
String sTo<span class="hilite1"><span class="hilite1">Date</span></span> = "2005-8-18";//用于转换成java.sql.<span class="hilite1"><span class="hilite1">Date</span></span>的字符串 <br />
String sToTimestamp = "2005-8-18 14:21:12.123";//用于转换成java.sql.Timestamp的字符串 <br />
<span class="hilite1"><span class="hilite1">Date</span></span> <span class="hilite1"><span class="hilite1">date</span></span>1 = string2<span class="hilite1"><span class="hilite1">Date</span></span>(sTo<span class="hilite1"><span class="hilite1">Date</span></span>); <br />
Timestamp <span class="hilite1"><span class="hilite1">date</span></span>2 = string2Time(sToTimestamp); <br />
System.out.println("<span class="hilite1"><span class="hilite1">Date</span></span>:"+<span class="hilite1"><span class="hilite1">date</span></span>1.toString());//结果显示 <br />
System.out.println("Timestamp:"+<span class="hilite1"><span class="hilite1">date</span></span>2.toString());//结果显示 <br />
}catch(Exception e) { <br />
e.printStackTrace(); <br />
} <br />
} <br />
} 
<img src ="http://www.blogjava.net/liuzheng/aggbug/190386.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liuzheng/" target="_blank">刘铮 </a> 2008-04-02 15:40 <a href="http://www.blogjava.net/liuzheng/articles/190386.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Jakarta Commons  HttpClient 学习笔记（转）</title><link>http://www.blogjava.net/liuzheng/articles/180506.html</link><dc:creator>刘铮 </dc:creator><author>刘铮 </author><pubDate>Mon, 18 Feb 2008 09:49:00 GMT</pubDate><guid>http://www.blogjava.net/liuzheng/articles/180506.html</guid><wfw:comment>http://www.blogjava.net/liuzheng/comments/180506.html</wfw:comment><comments>http://www.blogjava.net/liuzheng/articles/180506.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liuzheng/comments/commentRss/180506.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liuzheng/services/trackbacks/180506.html</trackback:ping><description><![CDATA[<h4>1、HttpClient的功能</h4>
<br />
<ol><br />
    <li>基于标准，纯正<a href="http://www.myfaq.com.cn/Dev/Programme/Java/index.html" target="_blank">java</a>，实现了http1.0和1.1。<br />
    <li>在一个可扩展的OO框架内，实现了HTTP的全部方法(GET, POST, <br />
    PUT, DELETE, HEAD, OPTIONS, and TRACE)<br />
    <li>支持HTTPS(ssl上的HTTP)的加密操作<br />
    <li>透明地穿过HTTP代理建立连接<br />
    <li>通过CONNECT方法，利用通过建立穿过HTTP代理的HTTPS连接<br />
    <li>利用本地Java socket，透明地穿过SOCKS(版本5和4）代理建立连接<br />
    <li>支持利用Basic、Digest和NTLM加密的<a href="http://www.myfaq.com.cn/RenZ/index.html" target="_blank">认证</a><br />
    <li>支持用于上传大<a href="http://www.myfaq.com.cn/Soft/Tools/File/index.html" target="_blank">文件</a>的Multi-Part表单POST方法<br />
    <li>插件式安全socket实现，易于使用第三方的解决方案<br />
    <li>连接管理，支持多线程应用，支持设定单个主机总连接和最高连接数量,自动检测和关闭失效连接<br />
    <li>直接将请求信息流送到<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a>的端口<br />
    <li>直接读取从<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a>的端口送出的应答信息<br />
    <li>支持HTTP/1.0中用KeepAlive和HTTP/1.1中用persistance设置的持久连接<br />
    <li>直接访问由<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a>送出的应答代码和头部信息<br />
    <li>可设置连接超时时间
    <li><br />
    <li>HttpMethods 实现Command Pattern，以允许并行请求或高效连接复用<br />
    <li>遵循the Apache Software License协议，源码免费可得 <br />
    </li>
</ol>
<br />
<h4>2、预备工作</h4>
<br />
　　对jre1.3.*，如果要HttpClient支持https，则需要下载并安装<a href="http://<a%20href=/" target="_blank" http: www.myfaq.com.cn Dev Programme Java index.html?>java</a>.sun.com/products/jsse/"&gt;jsse</a>和<a href="http://<a%20href=/" target="_blank" http: www.myfaq.com.cn Dev Programme Java index.html?>java</a>.sun.com/products/jce/"&gt;jce</a>.安装的步骤如下：<br />
1)下载jsse和jce.<br />
2)检查CLASSPATH中没有与jsse和jce相关的jar包<br />
3)将 US_export_policy.jar、local_policy.jar、jsse.jar、jnet.jar、jce1_2_x.jar、sunjce_provider.jar、jcert.jar复制到目录：<br />
UNIX:$JDK_HOME/jre/lib/ext<br />
Windows:%JDK_HOME%\jre\lib\ext<br />
4)修改下述目录下的<a href="http://www.myfaq.com.cn/Dev/Programme/Java/index.html" target="_blank">java</a>.security<a href="http://www.myfaq.com.cn/Soft/Tools/File/index.html" target="_blank">文件</a>。<br />
UNIX:$JDK_HOME/jre/lib/security/<br />
Windows:%JDK_HOME%\jre\lib\security\<br />
5)
<div class="code">将<br />
#<br />
# List of providers and their preference orders:<br />
#<br />
security.provider.1=sun.security.provider.Sun<br />
security.provider.2=com.sun.rsajca.Provider<br />
改为：<br />
#<br />
# List of providers and their preference orders:<br />
#<br />
security.provider.1=com.sun.crypto.provider.SunJCE<br />
security.provider.2=sun.security.provider.Sun<br />
security.provider.3=com.sun.rsajca.Provider<br />
security.provider.4=com.sun.net.ssl.internal.ssl.Provider</div>
<br />
　　HttpClient还要求安装commons-logging，下面跟httpclient一块安装。<br />
<h4>3、取得源码</h4>
<br />
<div class="code">cvs -d :pserver:anoncvs@cvs.apache.org:/home/cvspublic login<br />
password: anoncvs<br />
cvs -d :pserver:anoncvs@cvs.apache.org:/home/cvspublic checkout jakarta-commons/logging<br />
cvs -d :pserver:anoncvs@cvs.apache.org:/home/cvspublic checkout jakarta-commons/httpclient</div>
<br />
　　编译：
<div class="code">cd jakarta-commons/logging<br />
ant dist<br />
cp dis/*.jar ../httpclient/lib/<br />
cd ../httpclient<br />
ant dist</div>
<br />
<h4>4、使用HttpClient编程的基本步聚</h4>
<br />
<ol>
    <li>创建 HttpClient 的一个实例.<br />
    <li>创建某个方法（DeleteMethod，EntityEnclosingMethod，ExpectContinueMethod，GetMethod，HeadMethod，MultipartPostMethod，OptionsMethod，PostMethod，PutMethod，TraceMethod）的一个实例，一般可用要目标URL为参数。<br />
    <li>让 HttpClient 执行这个方法.<br />
    <li>读取应答信息.<br />
    <li>释放连接.<br />
    <li>处理应答.<br />
    </li>
</ol>
<br />
　　在执行方法的过程中，有两种异常，一种是HttpRecoverableException，表示偶然性错误发生，一般再试可能成功，另一种是IOException，严重错误。<br />
　　这儿有这个教程中的一个例程，可以<a href="http://hedong.3322.org/archives/docs/HttpClientTutorial.<a%20href=" target="_blank" http: www.myfaq.com.cn Dev Programme Java index.html?>java</a>"&gt;下载</a>。
<h4>5、<a href="http://www.myfaq.com.cn/RenZ/index.html" target="_blank">认证</a></h4>
<br />
　　HttpClient三种不同的<a href="http://www.myfaq.com.cn/RenZ/index.html" target="_blank">认证</a>方案: Basic, Digest and NTLM. 这些方案可用于<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a>或代理对客户端的<a href="http://www.myfaq.com.cn/RenZ/index.html" target="_blank">认证</a>，简称<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a><a href="http://www.myfaq.com.cn/RenZ/index.html" target="_blank">认证</a>或代理<a href="http://www.myfaq.com.cn/RenZ/index.html" target="_blank">认证</a>。<br />
1)<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a><a href="http://www.myfaq.com.cn/RenZ/index.html" target="_blank">认证</a>(Server Authentication)<br />
　　HttpClient处理<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a><a href="http://www.myfaq.com.cn/RenZ/index.html" target="_blank">认证</a>几乎是透明的，仅需要开发人员提供登录信息(login credentials)。登录信息保存在HttpState类的实例中，可以通过 setCredentials(String realm, Credentials cred)和getCredentials(String realm)来获取或设置。注意，设定对非特定站点访问所需要的登录信息，将realm参数置为null. HttpClient内建的自动<a href="http://www.myfaq.com.cn/RenZ/index.html" target="_blank">认证</a>，可以通过HttpMethod类的setDoAuthentication(boolean doAuthentication)方法关闭，而且这次关闭只影响HttpMethod当前的实例。<br />
　　抢先<a href="http://www.myfaq.com.cn/RenZ/index.html" target="_blank">认证</a>(Preemptive Authentication)可以通过下述方法打开.
<div class="code">client.getState().setAuthenticationPreemptive(true);</div>
　　在这种模式时，HttpClient会主动将basic<a href="http://www.myfaq.com.cn/RenZ/index.html" target="_blank">认证</a>应答信息传给<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a>，即使在某种情况下<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a>可能返回<a href="http://www.myfaq.com.cn/RenZ/index.html" target="_blank">认证</a>失败的应答，这样做主要是为了减少连接的建立。为使每个新建的 HttpState实例都实行抢先<a href="http://www.myfaq.com.cn/RenZ/index.html" target="_blank">认证</a>，可以如下设置<a href="http://www.myfaq.com.cn/System/index.html" target="_blank">系统</a>属性。
<div class="code">setSystemProperty(Authenticator.PREEMPTIVE_PROPERTY, "true");</div>
<br />
Httpclient实现的抢先<a href="http://www.myfaq.com.cn/RenZ/index.html" target="_blank">认证</a>遵循rfc2617.<br />
2)代理<a href="http://www.myfaq.com.cn/RenZ/index.html" target="_blank">认证</a>(proxy authentication)<br />
　　除了登录信息需单独存放以外，代理<a href="http://www.myfaq.com.cn/RenZ/index.html" target="_blank">认证</a>与<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a><a href="http://www.myfaq.com.cn/RenZ/index.html" target="_blank">认证</a>几乎一致。用 setProxyCredentials(String realm, Credentials cred)和 getProxyCredentials(String realm)设、取登录信息。<br />
3)<a href="http://www.myfaq.com.cn/RenZ/index.html" target="_blank">认证</a>方案(authentication schemes)<br />
　　Basic<br />
　　是HTTP中规定最早的也是最兼容(?)的方案，遗憾的是也是最不安全的一个方案，因为它以明码传送用户名和密码。它要求一个UsernamePasswordCredentials实例，可以指定<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a>端的访问空间或采用默认的登录信息。<br />
　　Digest<br />
　　是在HTTP1.1中增加的一个方案，虽然不如Basic得到的软件支持多，但还是有广泛的使用。Digest方案比Basic方案安全得多，因它根本就不通过<a href="http://www.myfaq.com.cn/Net/index.html" target="_blank">网络</a>传送实际的密码，传送的是利用这个密码对从<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a>传来的一个随机数(nonce)的加密串。它要求一个UsernamePasswordCredentials实例，可以指定<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a>端的访问空间或采用默认的登录信息。<br />
　　NTLM<br />
　　这是HttpClient支持的最复杂的<a href="http://www.myfaq.com.cn/RenZ/index.html" target="_blank">认证</a>协议。它M$设计的一个私有协议，没有公开的规范说明。一开始由于设计的缺陷，NTLM的安全性比Digest差，后来经过一个ServicePack补丁后，安全性则比较Digest高。NTLM需要一个NTCredentials实例. 注意，由于NTLM不使用访问空间(realms)的概念，HttpClient利用<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a>的域名作访问空间的名字。还需要注意，提供给NTCredentials的用户名，不要用域名的前缀 - 如: "adrian" 是正确的，而 "DOMAIN\adrian" 则是错的.<br />
　　NTLM<a href="http://www.myfaq.com.cn/RenZ/index.html" target="_blank">认证</a>的工作机制与basic和digest有很大的差别。这些差别一般由HttpClient处理，但理解这些差别有助避免在使用NTLM<a href="http://www.myfaq.com.cn/RenZ/index.html" target="_blank">认证</a>时出现错误。<br />
<ol>
    <li>从HttpClientAPI的角度来看，NTLM与其它<a href="http://www.myfaq.com.cn/RenZ/index.html" target="_blank">认证</a>方式一样的工作，差别是需要提供'NTCredentials'实例而不是'UsernamePasswordCredentials'(其实，前者只是扩展了后者)<br />
    <li>对NTLM<a href="http://www.myfaq.com.cn/RenZ/index.html" target="_blank">认证</a>，访问空间是连接到的机器的域名，这对多域名主机会有一些麻烦.只有HttpClient连接中指定的域名才是<a href="http://www.myfaq.com.cn/RenZ/index.html" target="_blank">认证</a>用的域名。建议将realm设为null以使用默认的设置。<br />
    <li>NTLM只是<a href="http://www.myfaq.com.cn/RenZ/index.html" target="_blank">认证</a>了一个连接而不是一请求，所以每当一个新的连接建立就要进行一次<a href="http://www.myfaq.com.cn/RenZ/index.html" target="_blank">认证</a>，且在<a href="http://www.myfaq.com.cn/RenZ/index.html" target="_blank">认证</a>的过程中保持连接是非常重要的。 因此，NTLM不能同时用于代理<a href="http://www.myfaq.com.cn/RenZ/index.html" target="_blank">认证</a>和<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a><a href="http://www.myfaq.com.cn/RenZ/index.html" target="_blank">认证</a>，也不能用于http1.0连接或<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a>不支持持久连接的情况。</li>
</ol>
<h4>6、重定向</h4>
<br />
　　由于技术限制，以及为保证2.0发布版API的稳定，HttpClient还不能自动处重定向，但对重定向到同一主机、同一端口且采用同一协议的情况HttpClient可以支持。不能自动的处理的情况，包括需要人工交互的情况，或超出httpclient的能力。<br />
　　当<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a>重定向指令指到不同的主机时，HttpClient只是简单地将重定向状态码作为应答状态。所有的300到399（包含两端）的返回码，都表示是重定向应答。常见的有：<br />
<ol>
    <li>301 永久移动. HttpStatus.SC_MOVED_PERMANENTLY<br />
    <li>302 临时移动. HttpStatus.SC_MOVED_TEMPORARILY<br />
    <li>303 See Other. HttpStatus.SC_SEE_OTHER<br />
    <li>307 临时重定向. HttpStatus.SC_TEMPORARY_REDIRECT</li>
</ol>
<br />
　　当收到简单的重定向时，<a href="http://www.myfaq.com.cn/Dev/index.html" target="_blank">程序</a>应从HttpMethod对象中抽取新的URL并将其下载。另外,限制一下重定向次数是个好的主意，这可以避免递归循环。新的URL可以从头字段Location中抽取，如下：
<div class="code">String redirectLocation;<br />
Header locationHeader = method.getResponseHeader("location");<br />
if (locationHeader != null) {<br />
redirectLocation = locationHeader.getValue();<br />
} else {<br />
// The response is invalid and did not provide the new location for<br />
// the resource. Report an error or possibly handle the response<br />
// like a 404 Not Found error.<br />
}</div>
<br />
特殊重定向：<br />
<ol>
    <li>300 多重选择. HttpStatus.SC_MULTIPLE_CHOICES<br />
    <li>304 没有改动. HttpStatus.SC_NO T_MODIFIED<br />
    <li>305 使用代理. HttpStatus.SC_USE_PROXY <br />
    </li>
</ol>
　　
<h4>7、<a href="http://www.myfaq.com.cn/Dev/Programme/VC/Str/index.html" target="_blank">字符</a>编码(character encoding)</h4>
<br />
　　一个HTTP协议的请求或应答的头部(在http协议中，数据包分为两部分，一部分是头部，由一些名值对构成，一部分是主体(body)，是真正传办理的数据（如HTML页面等）），必须以US-ASCII编码，这是因为头部不传数据而只描述被要传输的数据的一些信息，一个例外是cookie，它是数据但是通过头部进行传输的，所以它也要用US-ASCII编码。<br />
　　HTTP数据包的主体部分，可以用任何一种方式进行编码，默认是ISO-8859-1，具体可以用头部字段Content-Type指定。可以利用 addRequestHeader方法，设定编码方式；用 getResponseCharSet取得编码方式。对HTML或XML等类型的文档，它们的本身的Content-Type也可以指定编码方式，主要区分两者的作用范围以得到正确实的解码。<br />
　　URL的编码标准，由RFC1738指定为，只能是由可打印8位/字节的us-ascii<a href="http://www.myfaq.com.cn/Dev/Programme/VC/Str/index.html" target="_blank">字符</a>组成，80-ff不是us-ascii<a href="http://www.myfaq.com.cn/Dev/Programme/VC/Str/index.html" target="_blank">字符</a>，而00-1F是控制<a href="http://www.myfaq.com.cn/Dev/Programme/VC/Str/index.html" target="_blank">字符</a>，这两个区域中用的<a href="http://www.myfaq.com.cn/Dev/Programme/VC/Str/index.html" target="_blank">字符</a>都须加以编码(encoded)。<br />
　　
<h4>8、Cookies</h4>
<br />
　　 HttpClient能自动管理cookie,包括允许<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a>设置cookie并在需要的时候自动将cookie返回<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a>，它也支持手工设置cookie后发送到<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a>端。不幸的是，对如何处理cookie，有几个规范互相冲突：Netscape Cookie 草案, RFC2109, RFC2965，而且还有很大数量的软件商的cookie实现不遵循任何规范. 为了处理这种状况，HttpClient提供了策略驱动的cookie管理方式。HttpClient支持的cookie规范有：
<ol>
    <li><a href="http://wp.netscape.com/newsref/std/cookie_spec.html">Netscape cookie草案</a>，是最早的cookie规范，基于rfc2109。尽管这个规范与rc2109有较大的差别，这样做可以与一些<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a>兼容。 <br />
    <li><a title="cookie specification" href="http://www.w3.org/Protocols/rfc2109/rfc2109.txt">rfc2109</a>，是w3c发布的第一个官方cookie规范。理论上讲，所有的<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a>在处理cookie(版本1)时，都要遵循此规范，正因如此，HttpClient将其设为默认的规范。遗憾的是，这个规范太严格了，以致很多<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a>不正确的实施了该规范或仍在作用Netscape规范。在这种情况下，应使用兼容规范。<br />
    <li>兼容性规范，设计用来兼容尽可能多的<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a>，即使它们并没有遵循标准规范。当解析cookie出现问题时，应考虑采用兼容性规范。</li>
</ol>
<br />
　　 RFC2965规范暂时没有被HttpClient支持（在以后的版本为会加上），它定义了cookie版本2，并说明了版本1cookie的不足，RFC2965有意有久取代rfc2109.<br />
　　在HttpClient中，有两种方法来指定cookie规范的使用，
<ol>
    <li>
    <div class="code">HttpClient client = new HttpClient();<br />
    client.getState().setCookiePolicy(CookiePolicy.COMPATIBILITY);</div>
    这种方法设置的规范只对当前的HttpState有效，参数可取值CookiePolicy.COMPATIBILITY，CookiePolicy.NETSCAPE_DRAFT或CookiePolicy.RFC2109。<br />
    <li>
    <div class="code">System.setProperty("apache.commons.httpclient.cookiespec", "COMPATIBILITY");</div>
    此法指的规范，对以后每个新建立的HttpState对象都有效，参数可取值"COMPATIBILITY","NETSCAPE_DRAFT"或"RFC2109"。<br />
    　　常有不能解析cookie的问题，但更换到兼容规范大都能解决。<br />
    </li>
</ol>
　　
<h4>9、使用HttpClient遇到问题怎么办?</h4>
<br />
<ol>
    <li>用一个浏览器访问<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a>，以确认<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a>应答正常<br />
    <li>如果在使代理，关掉代理试试<br />
    <li>另找一个<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a>来试试（如果运行着不同的<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a>软件更好）<br />
    <li>检查代码是否按教程中讲的思路编写<br />
    <li>设置log级别为debug，找出问题出现的原因<br />
    <li>打开wiretrace，来追踪客户端与<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a>的通信，以确实问题出现在什么地方<br />
    <li>用telnet或netcat手工将信息发送到<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a>，适合于猜测已经找到了原因而进行试验时<br />
    <li>将netcat以监听方式运行，用作<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a>以检查httpclient如何处理应答的。<br />
    <li>利用最新的httpclient试试，bug可能在最新的版本中修复了<br />
    <li>向邮件列表求帮助<br />
    <li>向bugzilla报告bug. </li>
</ol>
　　
<h4>10、SSL</h4>
<br />
　　借助Java Secure Socket Extension (JSSE)，HttpClient全面支持Secure Sockets Layer (SSL)或IETF Transport Layer Security (TLS)协议上的HTTP。JSSE已经jre1.4及以后的版本中，以前的版本则需要手工安装设置，具体过程参见<a href="http://<a%20href=/" target="_blank" http: www.myfaq.com.cn Dev Programme Java index.html?>java</a>.sun.com/products/jsse/doc/guide/API_users_guide.html#Installation"&gt;Sun网站</a>或本学习笔记。<br />
　　HttpClient中使用SSL非常简单，参考下面两个例子:
<div class="code">HttpClient httpclient = new HttpClient();<br />
GetMethod httpget = new GetMethod("https://www.verisign.com/"); <br />
httpclient.executeMethod(httpget);<br />
System.out.println(httpget.getStatusLine().toString());</div>
，如果通过需要授权的代理，则如下：
<div class="code">HttpClient httpclient = new HttpClient();<br />
httpclient.getHostConfiguration().setProxy("myproxyhost", 8080);<br />
httpclient.getState().setProxyCredentials("my-proxy-realm", " myproxyhost",<br />
new UsernamePasswordCredentials("my-proxy-username", "my-proxy-password"));<br />
GetMethod httpget = new GetMethod("https://www.verisign.com/"); <br />
httpclient.executeMethod(httpget);<br />
System.out.println(httpget.getStatusLine().toString());</div>
<br />
　　在HttpClient中定制SSL的步骤如下：<br />
<ol>
    <li>提供了一个实现了org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory接口的socket factory。这个 socket factory负责打一个到<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a>的端口，使用标准的或第三方的SSL函数库，并进行象连接握手等初始化操作。通常情况下，这个初始化操作在端口被创建时自动进行的。<br />
    <li>实例化一个org.apache.commons.httpclient.protocol.Protocol对象。创建这个实例时，需要一个合法的协议类型(如https)，一个定制的socket factory，和一个默认的端中号(如https的443端口).
    <div class="code">Protocol myhttps = new Protocol("https", new MySSLSocketFactory(), 443);</div>
    然后，这个实例可被设置为协议的处理器。
    <div class="code">HttpClient httpclient = new HttpClient();<br />
    httpclient.getHostConfiguration().setHost("www.whatever.com", 443, myhttps);<br />
    GetMethod httpget = new GetMethod("/");<br />
    httpclient.executeMethod(httpget);</div>
    <br />
    <li>通过调用Protocol.registerProtocol方法，将此定制的实例，注册为某一特定协议的默认的处理器。由此，可以很方便地定制自己的协议类型(如myhttps)。
    <div class="code">Protocol.registerProtocol("myhttps", <br />
    new Protocol("https", new MySSLSocketFactory(), 9443));<br />
    ...<br />
    HttpClient httpclient = new HttpClient();<br />
    GetMethod httpget = new GetMethod("myhttps://www.whatever.com/");<br />
    httpclient.executeMethod(httpget);</div>
    如果想用自己定制的处理器取代https默认的处理器，只需要将其注册为"https"即可。
    <div class="code">Protocol.registerProtocol("https", <br />
    new Protocol("https", new MySSLSocketFactory(), 443));<br />
    HttpClient httpclient = new HttpClient();<br />
    GetMethod httpget = new GetMethod("https://www.whatever.com/");<br />
    httpclient.executeMethod(httpget);</div>
    </li>
</ol>
<br />
　　已知的限制和问题<br />
<ol>
    <li>持续的SSL连接在Sun的低于1.4JVM上不能工作，这是由于JVM的bug造成。<br />
    <li>通过代理访问<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a>时，非抢先<a href="http://www.myfaq.com.cn/RenZ/index.html" target="_blank">认证</a>（ Non-preemptive authentication）会失败，这是由于HttpClient的设计缺陷造成的，以后的版本中会修改。</li>
</ol>
<br />
　　遇到问题的处理<br />
　　很多问题，特别是在jvm低于1.4时，是由jsse的安装造成的。<br />
　　下面的代码，可作为最终的检测手段。<br />
<div class="code">import <a href="http://www.myfaq.com.cn/Dev/Programme/Java/index.html" target="_blank">java</a>.io.BufferedReader;<br />
import <a href="http://www.myfaq.com.cn/Dev/Programme/Java/index.html" target="_blank">java</a>.io.InputStreamReader;<br />
import <a href="http://www.myfaq.com.cn/Dev/Programme/Java/index.html" target="_blank">java</a>.io.OutputStreamWriter;<br />
import <a href="http://www.myfaq.com.cn/Dev/Programme/Java/index.html" target="_blank">java</a>.io.Writer;<br />
import <a href="http://www.myfaq.com.cn/Dev/Programme/Java/index.html" target="_blank">java</a>.net.Socket; import <a href="http://www.myfaq.com.cn/Dev/Programme/Java/index.html" target="_blank">java</a>x.net.ssl.SSLSocketFactory; public class Test {<br />
<br />
public static final String TARGET_HTTPS_SERVER = "www.verisign.com"; <br />
public static final int TARGET_HTTPS_PORT = 443; <br />
<br />
public static void main(String[] args) throws Exception {<br />
<br />
Socket socket = SSLSocketFactory.getDefault().<br />
createSocket(TARGET_HTTPS_SERVER, TARGET_HTTPS_PORT);<br />
try {<br />
Writer out = new OutputStreamWriter(<br />
socket.getOutputStream(), "ISO-8859-1");<br />
out.write("GET / HTTP/1.1\r\n"); <br />
out.write("Host: " + TARGET_HTTPS_SERVER + ":" + <br />
TARGET_HTTPS_PORT + "\r\n"); <br />
out.write("Agent: SSL-TEST\r\n"); <br />
out.write("\r\n"); <br />
out.flush(); <br />
BufferedReader in = new BufferedReader(<br />
new InputStreamReader(socket.getInputStream(), "ISO-8859-1"));<br />
String line = null;<br />
while ((line = in.readLine()) != null) {<br />
System.out.println(line);<br />
}<br />
} finally {<br />
socket.close(); <br />
}<br />
}<br />
}</div>
<br />
　　
<h4>11、httpclient的多线程处理</h4>
<br />
　　使用多线程的主要目的，是为了实现并行的下载。在httpclient运行的过程中，每个http协议的方法，使用一个HttpConnection实例。由于连接是一种有限的资源，每个连接在某一时刻只能供一个线程和方法使用，所以需要确保在需要时正确地分配连接。HttpClient采用了一种类似jdbc连接池的方法来管理连接，这个管理工作由 MultiThreadedHttpConnectionManager完成。
<div class="code">MultiThreadedHttpConnectionManager connectionManager = <br />
new MultiThreadedHttpConnectionManager();<br />
HttpClient client = new HttpClient(connectionManager);</div>
此是，client可以在多个线程中被用来执行多个方法。每次调用HttpClient.executeMethod() 方法，都会去链接管理器申请一个连接实例，申请成功这个链接实例被签出(checkout)，随之在链接使用完后必须归还管理器。管理器支持两个设置：
<table border="1">
    <tbody>
        <tr>
            <td>maxConnectionsPerHost</td>
            <td>每个主机的最大并行链接数，默认为2</td>
        </tr>
        <tr>
            <td>maxTotalConnections</td>
            <td>客户端总并行链接最大数，默认为20</td>
        </tr>
    </tbody>
</table>
<br />
　　管理器重新利用链接时，采取早归还者先重用的方式（least recently used approach）。<br />
　　由于是使用HttpClient的<a href="http://www.myfaq.com.cn/Dev/index.html" target="_blank">程序</a>而不是HttpClient本身来读取应答包的主体，所以HttpClient无法决定什么时间连接不再使用了，这也就要求在读完应答包的主体后必须手工显式地调用releaseConnection()来释放申请的链接。
<div class="code">MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();<br />
HttpClient client = new HttpClient(connectionManager);<br />
...<br />
// 在某个线程中。<br />
GetMethod get = new GetMethod("http://jakarta.apache.org/");<br />
try {<br />
client.executeMethod(get);<br />
// print response to stdout<br />
System.out.println(get.getResponseBodyAsStream());<br />
} finally {<br />
// be sure the connection is released back to the connection <br />
// manager<br />
get.releaseConnection();<br />
}</div>
对每一个HttpClient.executeMethod须有一个method.releaseConnection()与之匹配.
<h4>12、HTTP方法</h4>
<br />
　　HttpClient支持的HTTP方法有8种，下面分述之。<br />
<br />
　　1、Options<br />
<br />
　　HTTP方法Options用来向<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a>发送请求，希望获得针对由请求URL(request url)标志的资源在请求/应答的通信过程可以使用的功能选项。通过这个方法，客户端可以在采取具体行动之前，就可对某一资源决定采取什么动作和/或以及一些必要条件，或者了解<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a>提供的功能。这个方法最典型的应用，就是用来获取<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a>支持哪些HTTP方法。<br />
　　HttpClient中有一个类叫OptionsMethod，来支持这个HTTP方法，利用这个类的getAllowedMethods方法，就可以很简单地实现上述的典型应用。<br />
<div class="code">OptionsMethod options = new OptionsMethod("http://jakarta.apache.org");<br />
// 执行方法并做相应的异常处理<br />
...<br />
Enumeration allowedMethods = options.getAllowedMethods();<br />
options.releaseConnection();</div>
<br />
　　2、Get<br />
<br />
　　 HTTP方法GET用来取回请求URI（request-URI）标志的任何信息（以实体(entity)的形式），"get"这个单词本意就是&#8221;获取&#8220;的意思。如果请求URI指向的一个数据处理过程，那这个过程生成的数据，在应答中以实体的形式被返回，而不是将这个过程的代码的返回。<br />
　　如果HTTP包中含有If-ModifiedSince, If-Unmodified-Since, If-Match, If-None-Match, 或 If-Range等头字段，则GET也就变成了&#8221;条件GET&#8220;，即只有满足上述字段描述的条件的实体才被取回，这样可以减少一些非必需的<a href="http://www.myfaq.com.cn/Net/index.html" target="_blank">网络</a>传输，或者减少为获取某一资源的多次请求（如第一次检查，第二次下载）。（一般的浏览器，都有一个临时目录，用来缓存一些网页信息，当再次浏览某个页面的时候，只下载那些修改过的内容，以加快浏览速度，就是这个道理。至于检查，则常用比GET更好的方法HEAD来实现。）如果HTTP包中含有Range头字段，那么请求URI指定的实体中，只有决定范围条件的那部分才被取回来。（用过多线程下载工具的朋友，可能比较容易理解这一点）<br />
　　这个方法的典型应用，用来从web<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a>下载文档。HttpClient定义了一个类叫GetMethod来支持这个方法，用GetMethod类中getResponseBody, getResponseBodyAsStream 或 getResponseBodyAsString函数就可以取到应答包包体中的文档（如HTML页面）信息。这这三个函数中，getResponseBodyAsStream通常是最好的方法，主要是因为它可以避免在处理下载的文档之前缓存所有的下载的数据。<br />
<div class="code">GetMethod get = new GetMethod("http://jakarta.apache.org");<br />
// 执行方法，并处理失败的请求.<br />
...<br />
InputStream in = get.getResponseBodyAsStream();<br />
// 利用输入流来处理信息。<br />
get.releaseConnection();</div>
<br />
　　对GetMethod的最常见的不正确的使用，是没有将全部的应答主体的数据读出来。还有，必须注意要手工明确地将链接释放。<br />
<br />
　　3、Head<br />
<br />
　　HTTP的Head方法，与Get方法完全一致，唯一的差别是<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a>不能在应答包中包含主体(message-body)，而且一定不能包含主体。使用这个方法，可以使得客户无需将资源下载回就可就以得到一些关于它的基本信息。这个方法常用来检查超链的可访问性以及资源最近有没有被修改。<br />
　　HTTP的head方法最典型的应用，是获取资源的基本信息。HttpClient定义了HeadMethod类支持这个方法，HeadMethod类与其它*Method类一样，用 getResponseHeaders()取回头部信息，而没有自己的特殊方法。<br />
<div class="code">HeadMethod head = new HeadMethod("http://jakarta.apache.org");<br />
// 执行方法，并处理失败的请求.<br />
...<br />
// 取回应答包的头字段信息.<br />
Header[] headers = head.getResponseHeaders(); // 只取回最后修改日期字段的信息.<br />
String lastModified = head.getResponseHeader("last-modified").getValue();</div>
<br />
<br />
　　4、Post<br />
<br />
　　Post在英文有&#8220;派驻&#8221;的意思，HTTP方法POST就是要求<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a>接受请求包中的实体，并将其作为请求URI的下属资源。从本质上说，这意味着<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a>要保存这个实体信息，而且通常由<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a>端的<a href="http://www.myfaq.com.cn/Dev/index.html" target="_blank">程序</a>进行处理。Post方法的设计意图，是要以一种统一的方式实现下列功能：
<ol>
    <li>对已有的资源做评注<br />
    <li>将信息发布到BBS、新闻组、邮件列表，或类似的文章组中<br />
    <li>将一块数据，提交给数据处理进程<br />
    <li>通过追加操作，来扩展一个<a href="http://www.myfaq.com.cn/Dev/DataBase/index.html" target="_blank">数据库</a></li>
</ol>
　　这些都操作期待着在<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a>端产生一定的&#8220;副作用&#8221;，如修改了<a href="http://www.myfaq.com.cn/Dev/DataBase/index.html" target="_blank">数据库</a>等。<br />
　　HttpClient定义PostMethod类以支持该HTTP方法，在httpclient中，使用post方法有两个基本的步骤：为请求包准备数据，然后读取<a href="http://www.myfaq.com.cn/System/Server/index.html" target="_blank">服务器</a>来的应答包的信息。通过调用 setRequestBody()函数，来为请求包提供数据，它可以接收三类参数：输入流、名值对数组或<a href="http://www.myfaq.com.cn/Dev/Programme/VC/Str/index.html" target="_blank">字符</a>串。至于读取应答包需要调用 getResponseBody* 那一系列的方法，与GET方法处理应答包的方法相同。<br />
　　常见问题是，没有将全部应答读取（无论它对<a href="http://www.myfaq.com.cn/Dev/index.html" target="_blank">程序</a>是否有用），或没有释放链接资源。
<img src ="http://www.blogjava.net/liuzheng/aggbug/180506.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liuzheng/" target="_blank">刘铮 </a> 2008-02-18 17:49 <a href="http://www.blogjava.net/liuzheng/articles/180506.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用command-chain完成的For循环</title><link>http://www.blogjava.net/liuzheng/articles/176927.html</link><dc:creator>刘铮 </dc:creator><author>刘铮 </author><pubDate>Tue, 22 Jan 2008 02:24:00 GMT</pubDate><guid>http://www.blogjava.net/liuzheng/articles/176927.html</guid><wfw:comment>http://www.blogjava.net/liuzheng/comments/176927.html</wfw:comment><comments>http://www.blogjava.net/liuzheng/articles/176927.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liuzheng/comments/commentRss/176927.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liuzheng/services/trackbacks/176927.html</trackback:ping><description><![CDATA[<p>package nl.enovation.commons.command;</p>
<p>import java.util.Collection;</p>
<p>import org.apache.commons.chain.Command;<br />
import org.apache.commons.chain.Context;</p>
<p>public class ForeachCommand implements Command {<br />
&nbsp;&nbsp;&nbsp; private String collectionProperty;<br />
&nbsp;&nbsp;&nbsp; private String instanceProperty;<br />
&nbsp;&nbsp;&nbsp; private Command command;<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; @SuppressWarnings("unchecked")<br />
&nbsp;&nbsp;&nbsp; public boolean execute(Context context) throws Exception {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Collection&lt;? extends Object&gt; collection = (Collection&lt;? extends Object&gt;) context.get(collectionProperty);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (collection != null) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(Object object : collection) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; context.put(instanceProperty, object);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (PROCESSING_COMPLETE == command.execute(context)) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return PROCESSING_COMPLETE;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } // else continue<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return CONTINUE_PROCESSING;<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; public String getCollectionProperty() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return collectionProperty;<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; public void setCollectionProperty(String collectionProperty) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.collectionProperty = collectionProperty;<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; public String getInstanceProperty() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return instanceProperty;<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; public void setInstanceProperty(String instanceProperty) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.instanceProperty = instanceProperty;<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; public Command getCommand() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return command;<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; public void setCommand(Command command) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.command = command;<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>}<br />
</p>
<img src ="http://www.blogjava.net/liuzheng/aggbug/176927.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liuzheng/" target="_blank">刘铮 </a> 2008-01-22 10:24 <a href="http://www.blogjava.net/liuzheng/articles/176927.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>文件处理</title><link>http://www.blogjava.net/liuzheng/articles/176807.html</link><dc:creator>刘铮 </dc:creator><author>刘铮 </author><pubDate>Mon, 21 Jan 2008 09:44:00 GMT</pubDate><guid>http://www.blogjava.net/liuzheng/articles/176807.html</guid><wfw:comment>http://www.blogjava.net/liuzheng/comments/176807.html</wfw:comment><comments>http://www.blogjava.net/liuzheng/articles/176807.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liuzheng/comments/commentRss/176807.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liuzheng/services/trackbacks/176807.html</trackback:ping><description><![CDATA[<p>package nl.enovation.ems.transferlink.client.util;</p>
<p>import java.io.File;<br />
import java.io.FileInputStream;<br />
import java.io.FileOutputStream;<br />
import java.io.IOException;<br />
import java.io.InputStream;<br />
import java.io.RandomAccessFile;<br />
import java.nio.ByteBuffer;<br />
import java.nio.MappedByteBuffer;<br />
import java.nio.channels.Channels;<br />
import java.nio.channels.FileChannel;<br />
import java.nio.channels.ReadableByteChannel;<br />
import java.nio.channels.WritableByteChannel;<br />
import java.util.ArrayList;<br />
import java.util.Collection;<br />
import java.util.Enumeration;<br />
import java.util.zip.ZipEntry;<br />
import java.util.zip.ZipFile;<br />
import java.util.zip.ZipOutputStream;</p>
<p>public class FileUtil {</p>
<p><br />
&nbsp;public static void moveFile(File source, String path) throws IOException {<br />
&nbsp;&nbsp;if(!source.renameTo(new File(path, source.getName()))){ <br />
&nbsp;&nbsp;&nbsp;throw new IOException(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"Can't move file " <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+ source.getName() <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+ " to " <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+ path);<br />
&nbsp;&nbsp;}<br />
&nbsp;}<br />
&nbsp;<br />
&nbsp;public static File moveFile(File source, File path) throws IOException {<br />
&nbsp;&nbsp;File newFile = new File(path, source.getName());<br />
&nbsp;&nbsp;if(!source.renameTo(newFile)){ <br />
&nbsp;&nbsp;&nbsp;throw new IOException(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"Can't move file " <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+ source.getName() <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+ " to " <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+ path);<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;return newFile;<br />
&nbsp;}<br />
&nbsp;<br />
&nbsp;public static void moveFile(File source, File path, boolean uniqueFileName) throws IOException {<br />
&nbsp;&nbsp;String fileName = source.getName();<br />
&nbsp;&nbsp;File file = new File(path, fileName);<br />
&nbsp;&nbsp;int count = 1;<br />
&nbsp;&nbsp;while(true) {<br />
&nbsp;&nbsp;&nbsp;if(file.exists()) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;String newFileName = null;<br />
&nbsp;&nbsp;&nbsp;&nbsp;int idx = fileName.lastIndexOf(".");<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(idx &gt; 0) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;newFileName = fileName.substring(0, idx) + "." + count + fileName.substring(idx);&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;} else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;newFileName = fileName + "." + count;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;file = new File(path, newFileName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;count++;<br />
&nbsp;&nbsp;&nbsp;} else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;if(!source.renameTo(file)){<br />
&nbsp;&nbsp;&nbsp;//try {<br />
&nbsp;&nbsp;&nbsp;//&nbsp;copyFile(source, file);<br />
&nbsp;&nbsp;&nbsp;//&nbsp;deleteFile(source);<br />
&nbsp;&nbsp;&nbsp;//}<br />
&nbsp;&nbsp;&nbsp;//catch (IOException e)<br />
&nbsp;&nbsp;&nbsp;//{<br />
&nbsp;&nbsp;&nbsp;&nbsp;throw new IOException(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"Can't move file " <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+ source.getName() //+ " (" + source.getAbsolutePath() + ")"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+ " to " <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+ path);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//+"("+e.getMessage()+")"); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// + " (" + file.getAbsolutePath() + ")");<br />
&nbsp;&nbsp;&nbsp;//}<br />
&nbsp;&nbsp;}<br />
&nbsp;}<br />
&nbsp;<br />
&nbsp;public static void moveFiles(File sourceDir, File destDir) throws IOException {<br />
&nbsp;&nbsp;java.io.File[] list=sourceDir.listFiles();<br />
&nbsp;&nbsp;for (int i = 0; i &lt; list.length; i++) {<br />
&nbsp;&nbsp;&nbsp;if (!list[i].isDirectory()) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(!list[i].renameTo(new File(destDir, list[i].getName()))) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw new IOException(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"Can't move file " <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+ list[i].getName() <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+ " to " <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+ destDir.getAbsolutePath());<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;}<br />
&nbsp;}<br />
&nbsp;<br />
&nbsp;/**<br />
&nbsp; * Copy a File (source) to a File (destination) <br />
&nbsp; * @param source<br />
&nbsp; * @param dest<br />
&nbsp; * @throws IOException<br />
&nbsp; */<br />
&nbsp;public static void copyFile(File source, File dest) throws IOException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FileChannel in = null, out = null;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; in = new FileInputStream(source).getChannel();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out = new FileOutputStream(dest).getChannel();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; long size = in.size();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MappedByteBuffer buf = in.map(FileChannel.MapMode.READ_ONLY, 0, size);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.write(buf);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } finally {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (in != null)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;in.close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (out != null)&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;out.close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;}<br />
&nbsp;<br />
&nbsp;/**<br />
&nbsp; * Write an input stream to a file.<br />
&nbsp; * @param source<br />
&nbsp; * @param dest<br />
&nbsp; * @param size<br />
&nbsp; * @throws IOException<br />
&nbsp; */<br />
&nbsp;public static int writeFile(InputStream source, File dest, long buffer) throws IOException {<br />
&nbsp;&nbsp;int bytesWrote = 0;<br />
&nbsp;&nbsp;FileChannel out = null;<br />
&nbsp;&nbsp;ReadableByteChannel in = null;<br />
&nbsp;&nbsp;ByteBuffer data = ByteBuffer.allocate((int) buffer);<br />
&nbsp;&nbsp;try {<br />
&nbsp;&nbsp;&nbsp;in = Channels.newChannel(source);<br />
&nbsp;&nbsp;&nbsp;out = new FileOutputStream(dest).getChannel();<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;int read = in.read(data);<br />
&nbsp;&nbsp;&nbsp;while(read &gt; 0) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;bytesWrote += read;<br />
&nbsp;&nbsp;&nbsp;&nbsp;data.flip();<br />
&nbsp;&nbsp;&nbsp;&nbsp;out.write(data);<br />
&nbsp;&nbsp;&nbsp;&nbsp;data.clear();<br />
&nbsp;&nbsp;&nbsp;&nbsp;read = in.read(data);<br />
&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;} finally {<br />
&nbsp;&nbsp;&nbsp;if(out != null) <br />
&nbsp;&nbsp;&nbsp;&nbsp;out.close();<br />
&nbsp;&nbsp;&nbsp;if(in != null) <br />
&nbsp;&nbsp;&nbsp;&nbsp;in.close();<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;return bytesWrote;<br />
&nbsp;}<br />
&nbsp;<br />
&nbsp;public static void delete(java.io.File path) throws IOException {<br />
&nbsp;&nbsp;if (path.isDirectory()) {<br />
&nbsp;&nbsp;&nbsp;deleteDirectory(path);<br />
&nbsp;&nbsp;} else {<br />
&nbsp;&nbsp;&nbsp;deleteFile(path);<br />
&nbsp;&nbsp;}<br />
&nbsp;}<br />
&nbsp;<br />
&nbsp;protected static void deleteDirectory(java.io.File path) throws IOException {<br />
&nbsp;&nbsp;java.io.File[] list = path.listFiles();<br />
&nbsp;&nbsp;for (int i = 0; i &lt; list.length; i++) {<br />
&nbsp;&nbsp;&nbsp;if (list[i].isDirectory()) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;deleteDirectory(list[i]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;if (!list[i].delete()) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw new IOException("Can't delete directory '"+list[i]+"'.");<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;} else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;deleteFile(list[i]);<br />
&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;}<br />
&nbsp;}<br />
&nbsp;<br />
&nbsp;protected static void deleteFile(java.io.File path) throws IOException {<br />
&nbsp;&nbsp;if (!path.delete()) {<br />
&nbsp;&nbsp;&nbsp;throw new IOException("Can't delete file '"+path+"'.");<br />
&nbsp;&nbsp;}<br />
&nbsp;}<br />
&nbsp;<br />
&nbsp;// TODO optimize ... read and write with buffers?!<br />
&nbsp;//@SuppressWarnings("unchecked")<br />
&nbsp;public static Collection splitFile(File file, int splitlen, File tmpDir) throws IOException<br />
&nbsp;{<br />
&nbsp;&nbsp;long leng = 0;<br />
&nbsp;&nbsp;int count = 1, read = 0;<br />
&nbsp;&nbsp;byte [] buffer = new byte[8196];<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;String fileName&nbsp; = file.getName();<br />
&nbsp;&nbsp;Collection files = new ArrayList();&nbsp;&nbsp;<br />
&nbsp;&nbsp;RandomAccessFile infile = new RandomAccessFile(file, "r");<br />
&nbsp;&nbsp;read = infile.read(buffer);<br />
&nbsp;&nbsp;while(read != -1)<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;file = new File(tmpDir, fileName + ".lms.sp" + count);<br />
&nbsp;&nbsp;&nbsp;RandomAccessFile outfile = new RandomAccessFile(file, "rw");<br />
&nbsp;&nbsp;&nbsp;while( read != -1 &amp;&amp; leng &lt; splitlen)<br />
&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;outfile.write(buffer, 0, read);<br />
&nbsp;&nbsp;&nbsp;&nbsp;leng += read;<br />
&nbsp;&nbsp;&nbsp;&nbsp;read = infile.read(buffer);<br />
&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;leng = 0;<br />
&nbsp;&nbsp;&nbsp;outfile.close();<br />
&nbsp;&nbsp;&nbsp;file.deleteOnExit();<br />
&nbsp;&nbsp;&nbsp;files.add(file);<br />
&nbsp;&nbsp;&nbsp;count++;<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;return files;<br />
&nbsp;}<br />
&nbsp;<br />
&nbsp;public static File joinFile(String fileName, File tmpDir) throws IOException<br />
&nbsp;{<br />
&nbsp;&nbsp;int count = 1, read = 0;<br />
&nbsp;&nbsp;byte [] buffer = new byte[8196];<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;File destFile = new File(tmpDir, fileName);<br />
&nbsp;&nbsp;RandomAccessFile outfile = new RandomAccessFile(destFile, "rw");<br />
&nbsp;&nbsp;while(true)<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;File readFile = new File(tmpDir, fileName + ".lms.sp" + count);<br />
&nbsp;&nbsp;&nbsp;if (readFile.exists())<br />
&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;RandomAccessFile infile = new RandomAccessFile(readFile, "r");<br />
&nbsp;&nbsp;&nbsp;&nbsp;read = infile.read(buffer);<br />
&nbsp;&nbsp;&nbsp;&nbsp;while(read != -1)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;outfile.write(buffer, 0, read);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;read = infile.read(buffer);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;infile.close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;readFile.delete();<br />
&nbsp;&nbsp;&nbsp;&nbsp;count++;<br />
&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;else<br />
&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;outfile.close();<br />
&nbsp;&nbsp;return destFile;<br />
&nbsp;}<br />
&nbsp;<br />
&nbsp;public static boolean isComplete(String fileName, File dir, int parts) {<br />
&nbsp;&nbsp;int counter = 1;<br />
&nbsp;&nbsp;int matched = 0;<br />
&nbsp;&nbsp;File[] list = dir.listFiles();<br />
&nbsp;&nbsp;for (int i = 0; i &lt; list.length; i++) {<br />
&nbsp;&nbsp;&nbsp;if (!list[i].isDirectory()) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;String f = list[i].getName();<br />
&nbsp;&nbsp;&nbsp;&nbsp;String f2 = fileName + ".lms.sp";<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(f.startsWith(f2)) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;matched++;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;counter++;<br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;if(matched == parts) { <br />
&nbsp;&nbsp;&nbsp;return true;<br />
&nbsp;&nbsp;} else {<br />
&nbsp;&nbsp;&nbsp;return false;<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;<br />
&nbsp;}<br />
&nbsp;<br />
&nbsp;public static File zipFile(File file, File dir) throws IOException {<br />
&nbsp;&nbsp;WritableByteChannel out = null;<br />
&nbsp;&nbsp;ReadableByteChannel in = null;<br />
&nbsp;&nbsp;FileInputStream source = new FileInputStream(file);<br />
&nbsp;&nbsp;File dest = new File(dir, file.getName() + ".zip");<br />
&nbsp;&nbsp;ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(dest));<br />
&nbsp;&nbsp;dest.deleteOnExit();<br />
&nbsp;&nbsp;int buffer = 4096;<br />
&nbsp;&nbsp;ByteBuffer data = ByteBuffer.allocate(buffer);<br />
&nbsp;&nbsp;try {<br />
&nbsp;&nbsp;&nbsp;zos.putNextEntry(new ZipEntry(file.getName()));</p>
<p>&nbsp;&nbsp;&nbsp;in = Channels.newChannel(source);<br />
&nbsp;&nbsp;&nbsp;out = Channels.newChannel(zos);<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;int read = in.read(data);<br />
&nbsp;&nbsp;&nbsp;while(read &gt; 0) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;data.flip();<br />
&nbsp;&nbsp;&nbsp;&nbsp;out.write(data);<br />
&nbsp;&nbsp;&nbsp;&nbsp;data.clear();<br />
&nbsp;&nbsp;&nbsp;&nbsp;read = in.read(data);<br />
&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;zos.closeEntry();<br />
&nbsp;&nbsp;} finally {<br />
&nbsp;&nbsp;&nbsp;if(zos != null) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;zos.finish();<br />
&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;if(out != null) <br />
&nbsp;&nbsp;&nbsp;&nbsp;out.close();<br />
&nbsp;&nbsp;&nbsp;if(in != null) <br />
&nbsp;&nbsp;&nbsp;&nbsp;in.close();<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;return dest;<br />
&nbsp;}<br />
&nbsp;<br />
&nbsp;public static File unzipFile(File file, File dir) throws IOException {<br />
&nbsp;&nbsp;WritableByteChannel out = null;<br />
&nbsp;&nbsp;ReadableByteChannel in = null;<br />
&nbsp;&nbsp;ZipEntry entry = null;<br />
&nbsp;&nbsp;ZipFile zipFile = null; <br />
&nbsp;&nbsp;int buffer = 4096;<br />
&nbsp;&nbsp;ByteBuffer data = ByteBuffer.allocate(buffer);<br />
&nbsp;&nbsp;File unzippedFile = null;<br />
&nbsp;&nbsp;try {<br />
&nbsp;&nbsp;&nbsp;zipFile = new ZipFile(file, ZipFile.OPEN_READ);<br />
&nbsp;&nbsp;&nbsp;Enumeration zipFileEntries = zipFile.entries();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;// Process each entry<br />
&nbsp;&nbsp;&nbsp;if (zipFileEntries.hasMoreElements()) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;// grab a zip file entry<br />
&nbsp;&nbsp;&nbsp;&nbsp;entry = (ZipEntry) zipFileEntries.nextElement();<br />
&nbsp;&nbsp;&nbsp;&nbsp;String currentEntry = entry.getName();<br />
&nbsp;&nbsp;&nbsp;&nbsp;InputStream input = zipFile.getInputStream(entry);<br />
&nbsp;&nbsp;&nbsp;&nbsp;unzippedFile = new File(dir, currentEntry);<br />
&nbsp;&nbsp;&nbsp;&nbsp;FileOutputStream output = new FileOutputStream(unzippedFile);<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;in = Channels.newChannel(input);<br />
&nbsp;&nbsp;&nbsp;&nbsp;out = Channels.newChannel(output);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;int read = in.read(data);<br />
&nbsp;&nbsp;&nbsp;&nbsp;while(read &gt; 0) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;data.flip();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.write(data);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;data.clear();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;read = in.read(data);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;} finally {<br />
&nbsp;&nbsp;&nbsp;if(file != null) <br />
&nbsp;&nbsp;&nbsp;&nbsp;file.delete();<br />
&nbsp;&nbsp;&nbsp;if(zipFile != null)<br />
&nbsp;&nbsp;&nbsp;&nbsp;zipFile.close();<br />
&nbsp;&nbsp;&nbsp;if(out != null) <br />
&nbsp;&nbsp;&nbsp;&nbsp;out.close();<br />
&nbsp;&nbsp;&nbsp;if(in != null) <br />
&nbsp;&nbsp;&nbsp;&nbsp;in.close();<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;return unzippedFile;<br />
&nbsp;}<br />
}<br />
<br />
<br />
不过最好使用Apache Common 的IO组件。<br />
里面有个FileUtils，提供了很多很好的方法。<br />
可以参考：<br />
&nbsp; </p>
<p class="MsoPlainText"><a href="http://commons.apache.org/io/apidocs/index.html">http://commons.apache.org/io/apidocs/index.html</a></p>
<img src ="http://www.blogjava.net/liuzheng/aggbug/176807.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liuzheng/" target="_blank">刘铮 </a> 2008-01-21 17:44 <a href="http://www.blogjava.net/liuzheng/articles/176807.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>有关JAXB对xsd中的时间数据类型的处理</title><link>http://www.blogjava.net/liuzheng/articles/173389.html</link><dc:creator>刘铮 </dc:creator><author>刘铮 </author><pubDate>Mon, 07 Jan 2008 09:09:00 GMT</pubDate><guid>http://www.blogjava.net/liuzheng/articles/173389.html</guid><wfw:comment>http://www.blogjava.net/liuzheng/comments/173389.html</wfw:comment><comments>http://www.blogjava.net/liuzheng/articles/173389.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liuzheng/comments/commentRss/173389.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liuzheng/services/trackbacks/173389.html</trackback:ping><description><![CDATA[<p>使用xjc 将xsd中的时间数据：time datetime 等等转化为XMLGregorianCalendar的类<br />
处理XMLGregorianCalendar可以使用DatatypeFactory的工厂类进行创建，其中有个<code><strong><a href="mk:@MSITStore:D:\My%20Java%20Help%20Document\Java%20General\JDK_API_1_6_zh_CN.CHM::/javax/xml/datatype/DatatypeFactory.html#newXMLGregorianCalendar(java.util.GregorianCalendar)">newXMLGregorianCalendar</a></strong>(<a title="java.util 中的类" href="mk:@MSITStore:D:\My%20Java%20Help%20Document\Java%20General\JDK_API_1_6_zh_CN.CHM::/java/util/GregorianCalendar.html">GregorianCalendar</a>&nbsp;cal)</code> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;根据 <a title="java.util 中的类" href="mk:@MSITStore:D:\My%20Java%20Help%20Document\Java%20General\JDK_API_1_6_zh_CN.CHM::/java/util/GregorianCalendar.html"><code>GregorianCalendar</code></a> 创建 <code>XMLGregorianCalendar<br />
<code><strong><a href="mk:@MSITStore:D:\My%20Java%20Help%20Document\Java%20General\JDK_API_1_6_zh_CN.CHM::/javax/xml/datatype/DatatypeFactory.html#newXMLGregorianCalendar(int, int, int, int, int, int, int, int)">newXMLGregorianCalendar</a></strong>(int&nbsp;year, int&nbsp;month, int&nbsp;day, int&nbsp;hour, int&nbsp;minute, int&nbsp;second, int&nbsp;millisecond, int&nbsp;timezone)</code> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<code>java.util.GregorianCalendar</code> 实例需要转换为 <code>XMLGregorianCalendar</code> 实例的值空间的构造方法。</code></p>
<img src ="http://www.blogjava.net/liuzheng/aggbug/173389.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liuzheng/" target="_blank">刘铮 </a> 2008-01-07 17:09 <a href="http://www.blogjava.net/liuzheng/articles/173389.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>标准的读取文件的方法，读取整个文件</title><link>http://www.blogjava.net/liuzheng/articles/172271.html</link><dc:creator>刘铮 </dc:creator><author>刘铮 </author><pubDate>Wed, 02 Jan 2008 10:02:00 GMT</pubDate><guid>http://www.blogjava.net/liuzheng/articles/172271.html</guid><wfw:comment>http://www.blogjava.net/liuzheng/comments/172271.html</wfw:comment><comments>http://www.blogjava.net/liuzheng/articles/172271.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liuzheng/comments/commentRss/172271.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liuzheng/services/trackbacks/172271.html</trackback:ping><description><![CDATA[public void test() throws IOException{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; File f=new File("d:"+File.separator+"1.txt");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream(f)));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; StringBuffer whole=new StringBuffer();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String line=new String();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (line=br.readLine(); line!=null; line=br.readLine()) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; whole.append(line);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(whole.toString());<br />
&nbsp;&nbsp;&nbsp; }<br />
使用readLine()对整个文件或者Read流进行字符扫描<br />
<br />
<br />
<p>public void test1() throws IOException{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; File f=new File("d:"+File.separator+"1.txt");</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BufferedInputStream br=new BufferedInputStream(new FileInputStream(f));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; StringBuffer whole=new StringBuffer();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int line;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (line=br.read(); line!=-1; line=br.read()) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; whole.append(line);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(whole.toString());<br />
&nbsp;&nbsp;&nbsp; }</p>
使用read()对整个文件或者Read流进行字节的扫描<br />
<br />
<img src ="http://www.blogjava.net/liuzheng/aggbug/172271.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liuzheng/" target="_blank">刘铮 </a> 2008-01-02 18:02 <a href="http://www.blogjava.net/liuzheng/articles/172271.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java多线程中sleep()和join()的区别 </title><link>http://www.blogjava.net/liuzheng/articles/167243.html</link><dc:creator>刘铮 </dc:creator><author>刘铮 </author><pubDate>Wed, 12 Dec 2007 07:21:00 GMT</pubDate><guid>http://www.blogjava.net/liuzheng/articles/167243.html</guid><wfw:comment>http://www.blogjava.net/liuzheng/comments/167243.html</wfw:comment><comments>http://www.blogjava.net/liuzheng/articles/167243.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liuzheng/comments/commentRss/167243.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liuzheng/services/trackbacks/167243.html</trackback:ping><description><![CDATA[<p style="font-family: Verdana"><font size="2">If the Sleep method is called with System.Threading.Timeout.Infinite passed in as the parameter, the thread will remain in the WaitSleepJoin state until a different thread wakes it by using the</font><font color="#ff0000" size="2"> Interrupt method</font><font size="2">. Thread.Sleep(System.Threading.Timeout.Infinite)</font></p>
<p style="font-family: Verdana"><font size="2">One reason you might want to do this is if a thread determines that it is in a state where the best thing it can do is nothing. This may be an alternative to ending the thread by using the Abort method, or simply exiting the thread&#8217;s method. Once a thread ends, there is no way to restart it. However, if a thread calls the Sleep method and passes in Infinite for the timeout value, it is possible to exit that state at a later time. This concept is similar to calling Join. </font></p>
<p style="font-family: Verdana"><font size="2">When Join is called and no parameter is passed in, </font><font color="#ff0000" size="2">the current thread </font><font size="2">will wait indefinitely for the thread to end. When Join is called with a timeout value, </font><font color="#ff6600" size="2">the Join method will block for at most that period of time and then return a value indicating if the thread of interest ended</font><font size="2">. </font><font color="#ff0000" size="2"><strong>A key difference is that Join is called on a different thread while Sleep is called on the current thread. </strong></font><font size="2">Join also causes the current thread to pause for a period of time, but with the idea that it is waiting for </font><font color="#ff6600" size="2">some other thread </font><font size="2">to terminate. At the point the thread being joined terminates, the Join method returns. </font></p>
<img src ="http://www.blogjava.net/liuzheng/aggbug/167243.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liuzheng/" target="_blank">刘铮 </a> 2007-12-12 15:21 <a href="http://www.blogjava.net/liuzheng/articles/167243.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java多线程的中止</title><link>http://www.blogjava.net/liuzheng/articles/166419.html</link><dc:creator>刘铮 </dc:creator><author>刘铮 </author><pubDate>Sun, 09 Dec 2007 03:35:00 GMT</pubDate><guid>http://www.blogjava.net/liuzheng/articles/166419.html</guid><wfw:comment>http://www.blogjava.net/liuzheng/comments/166419.html</wfw:comment><comments>http://www.blogjava.net/liuzheng/articles/166419.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liuzheng/comments/commentRss/166419.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liuzheng/services/trackbacks/166419.html</trackback:ping><description><![CDATA[使用flag控制一个线程的中止<br />
<br />
在run方法中加入<br />
public void run(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;while(flag){<br />
&nbsp;&nbsp;&nbsp;&nbsp;......<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}<br />
再加入<br />
public void shutDown(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;flag=false;<br />
}<br />
<br />
以后使用shutDown进行关闭线程，而不用废弃了的stop方法，因为stop方法太粗暴了，立马停止线程的话，对已经打开的资源不能进行处理。
<img src ="http://www.blogjava.net/liuzheng/aggbug/166419.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liuzheng/" target="_blank">刘铮 </a> 2007-12-09 11:35 <a href="http://www.blogjava.net/liuzheng/articles/166419.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java 5 中的enum的深入学习心得</title><link>http://www.blogjava.net/liuzheng/articles/165741.html</link><dc:creator>刘铮 </dc:creator><author>刘铮 </author><pubDate>Thu, 06 Dec 2007 02:55:00 GMT</pubDate><guid>http://www.blogjava.net/liuzheng/articles/165741.html</guid><wfw:comment>http://www.blogjava.net/liuzheng/comments/165741.html</wfw:comment><comments>http://www.blogjava.net/liuzheng/articles/165741.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liuzheng/comments/commentRss/165741.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liuzheng/services/trackbacks/165741.html</trackback:ping><description><![CDATA[<pre>The full <tt>enum</tt> syntax actually provides quite a bit more power and flexibility:
<ul>
    <li>
    <p class="docList">You can define your own fields, methods, and constructors for the enumerated type.</p>
    <li>
    <p class="docList">If you define one or more constructors, you can invoke a constructor for each enumerated value by following the value name with constructor arguments in parentheses.</p>
    <li>
    <p class="docList">Although an <tt>enum</tt> may not <tt>extend</tt> anything, it may <tt>implement</tt> one or more interfaces.</p>
    <li>
    <p class="docList">Most esoterically, individual enumerated values can have their own class bodies that override methods defined by the type.</p>
    </li>
</ul>
<p class="docText">Rather than formally specifying the syntax for each of these advanced <tt>enum</tt> declarations, we'll demonstrate the syntax in the examples that follow.</p>
</pre>
<pre>&nbsp;</pre>
<pre>for example:</pre>
<pre>&nbsp;</pre>
<pre>public enum Prefix {
// These are the values of this enumerated type.
// Each one is followed by constructor arguments in parentheses.
// The values are separated from each other by commas, and the
// list of values is terminated with a semicolon to separate it from
// the class body that follows.
MILLI("m",    .001),
CENTI("c",    .01),
DECI("d",     .1),
DECA("D",   10.0),
HECTA("h", 100.0),
KILO("k", 1000.0);  // Note semicolon
// This is the constructor invoked for each value above.
Prefix(String abbrev, double multiplier) {
this.abbrev = abbrev;
this.multiplier = multiplier;
}
// These are the private fields set by the constructor
private String abbrev;
private double multiplier;
// These are accessor methods for the fields.  They are instance methods
// of each value of the enumerated type.
public String abbrev() { return abbrev; }
public double multiplier() { return multiplier; }
}</pre>
<img src ="http://www.blogjava.net/liuzheng/aggbug/165741.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liuzheng/" target="_blank">刘铮 </a> 2007-12-06 10:55 <a href="http://www.blogjava.net/liuzheng/articles/165741.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java 5中枚举类型学习</title><link>http://www.blogjava.net/liuzheng/articles/165597.html</link><dc:creator>刘铮 </dc:creator><author>刘铮 </author><pubDate>Wed, 05 Dec 2007 09:17:00 GMT</pubDate><guid>http://www.blogjava.net/liuzheng/articles/165597.html</guid><wfw:comment>http://www.blogjava.net/liuzheng/comments/165597.html</wfw:comment><comments>http://www.blogjava.net/liuzheng/articles/165597.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liuzheng/comments/commentRss/165597.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liuzheng/services/trackbacks/165597.html</trackback:ping><description><![CDATA[转帖：<br />
Tiger 中的一个重要新特性是枚举构造，它是一种新的类型，允许用常量来表示特定的数据 片断，而且全部都以类型安全的形式来表示。Tiger 专家、developerWorks 的多产作者 Brett McLaughlin将解释枚举的定义，介绍如何在应用程序中运用枚举，以及它为什么能够让您抛弃所有旧的<br />
public static final 代码。<br />
<br />
　 您已经知道，Java 代码的两个基本的构造块是类 和接口。现在 Tiger 又引入了枚举，一般简称它为 enum。这个新类型允许您表示特定的数据点，这些数据点只接受分配时预先定 义的值集合。 <br />
　当然，熟练的程序员可以用静态常量实现这项功能，如清单 1 所示：<br />
<br />
<br />
<br />
清单 1. public static final 的常量<br />
<br />
public class OldGrade {<br />
<br />
　public static final int A = 1;<br />
　public static final int B = 2;<br />
　public static final int C = 3;<br />
　public static final int D = 4;<br />
　public static final int F = 5;<br />
　public static final int INCOMPLETE = 6;<br />
}<br />
<br />
<br />
<br />
说明：我要感谢 O"Reilly 媒体公司，该公司允许在本文中使用我撰写的 Java 1.5 Tiger:<br />
A Developer"s Notebook 一书中&#8220;枚举&#8221;这一章中的代码示例（请参阅参考资料）。<br />
<br />
然后您就可以让类接受像 OldGrade.B 这样的常量，但是在这样做的时候，请记住这类常量<br />
是 Java 中 int 类型的常量，这意味着该方法可以接受任何 int 类型的值，即使它和<br />
OldGrade 中定的所有级别都不对应。因此，您需要检测上界和下界，在出现无效值的时候，可能还<br />
要包含一个 IllegalArgumentException。而且，如果后来又添加另外一个级别（例如<br />
OldGrade.WITHDREW_PASSING），那么必须改变所有代码中的上界，才能接受这个新值。<br />
<br />
换句话说，在使用这类带有整型常量的类时，该解决方案也许可行，但并不是非常有效。幸<br />
运的是，枚举提供了更好的方法。<br />
<br />
定义枚举<br />
清单 2 使用了一个可以提供与清单 1 相似的功能的枚举：<br />
<br />
清单 2. 简单的枚举类型<br />
<br />
package com.oreilly.tiger.ch03;<br />
<br />
public enum Grade {<br />
　A, B, C, D, F, INCOMPLETE<br />
};<br />
<br />
<br />
<br />
在这里，我使用了新的关键字 enum，为 enum 提供了一个名称，并指定了允许的值。然后<br />
，Grade 就变成了一个枚举类型，您可以按清单 3 所示的方法使用它：<br />
<br />
清单 3. 使用枚举类型<br />
<br />
package com.oreilly.tiger.ch03;<br />
<br />
public class Student {<br />
<br />
　private String firstName;<br />
　private String lastName;<br />
　private Grade grade;<br />
<br />
　public Student(String firstName, String lastName) {<br />
　　this.firstName = firstName;<br />
　　this.lastName = lastName;<br />
　}<br />
<br />
　public void setFirstName(String firstName) {<br />
　　this.firstName = firstName;<br />
　}<br />
<br />
　public String getFirstName() {<br />
　　return firstName;<br />
　}<br />
<br />
　public void setLastName(String lastName) {<br />
　　this.lastName = lastName;<br />
　}<br />
<br />
　public String getLastName() {<br />
　　return lastName;<br />
　}<br />
<br />
　public String getFullName() {<br />
　　return new StringBuffer(firstName)<br />
　　　　　 .append(" ")<br />
　　　　　 .append(lastName)<br />
　　　　　 .toString();<br />
　}<br />
<br />
　public void assignGrade(Grade grade) {<br />
　　this.grade = grade;<br />
　}<br />
<br />
　public Grade getGrade() {<br />
　　return grade;<br />
　}<br />
}<br />
<br />
<br />
<br />
用以前定义过的类型建立一个新的枚举（grade）之后，您就可以像使用其他成员变量一样<br />
使用它了。当然，枚举只能分配枚举值中的一个（例如，A、C 或 INCOMPLETE）。而且，在<br />
assignGrade() 中是没有进行错误检测的代码，也没有考虑边界情况，请注意这是如何做到<br />
。<br />
<br />
使用枚举值<br />
迄今为止，您所看到的示例都相当简单，但是枚举类型提供的东西远不止这些。您可以逐个<br />
遍历枚举值，也可以在 switch 语句中使用枚举值，枚举是非常有价值的。<br />
<br />
遍历枚举值<br />
下面我们用一个示例显示如何遍历枚举类型的值。清单 4 所示的这项技术，适用于调试、<br />
快速打印任务以及把枚举加载到集合（我很快将谈到）中的工具：<br />
<br />
清单 4. 遍历枚举值<br />
<br />
public void listGradeValues(PrintStream out) throws IOException {<br />
　for (Grade g : Grade.values()) {<br />
　　out.println("Allowed value: "" + g + """);<br />
　}<br />
}<br />
<br />
<br />
<br />
运行这段代码，将得到清单 5 所示的输出：<br />
<br />
清单 5. 迭代操作的输出<br />
<br />
Allowed Value: "A"<br />
Allowed Value: "B"<br />
Allowed Value: "C"<br />
Allowed Value: "D"<br />
Allowed Value: "F"<br />
Allowed Value: "INCOMPLETE"<br />
<br />
<br />
<br />
这里有许多东西。首先，我使用了 Tiger 的新的 for/in 循环（也叫作 foreach 或 增强<br />
的 for）。另外，您可以看到 values() 方法返回了一个由独立的 Grade 实例构成的数组<br />
，每个数组都有一个枚举类型的值。换句话说，values() 的返回值是 Grade[]。<br />
<br />
在枚举间切换<br />
能够在枚举的值之间移动很好，但是更重要的是根据枚举的值进行决策。您当然可以写一堆<br />
if (grade.equals(Grade.A)) 类型的语句，但那是在浪费时间。Tiger 能够很方便地把枚<br />
举支持添加到过去的好东西 switch 语句上，所以它很容易使用，而且适合您已知的内容。<br />
清单 6<br />
向将展示如何解决这个难题：<br />
<br />
清单 6. 在枚举之间切换<br />
<br />
public void testSwitchStatement(PrintStream out) throws IOException {<br />
　StringBuffer outputText = new StringBuffer(student1.getFullName());<br />
<br />
　switch (student1.getGrade()) {<br />
　　case A:<br />
　　　outputText.append(" excelled with a grade of A");<br />
　　　break;<br />
　　case B: // fall through to C<br />
　　case C:<br />
　　　outputText.append(" passed with a grade of ")<br />
　　　　　　　　.append(student1.getGrade().toString());<br />
　　　break;<br />
　　case D: // fall through to F<br />
　　case F:<br />
　　　outputText.append(" failed with a grade of ")<br />
　　　　　　　　.append(student1.getGrade().toString());<br />
　　　break;<br />
　　case INCOMPLETE:<br />
　　　outputText.append(" did not complete the class.");<br />
　　　break;<br />
　}<br />
<br />
　out.println(outputText.toString());<br />
}<br />
<br />
<br />
<br />
在这里，枚举值被传递到 switch 语句中（请记住，getGrade() 是作为 Grade 的实例返回<br />
的），而每个 case 子句将处理一个特定的值。该值在提供时没有枚举前缀，这意味着不用<br />
将代码写成 case Grade.A，只需将其写成 case A 即可。如果您不这么做，编译器不会接<br />
受有前缀的值。<br />
<br />
现在，您应该已经了解使用 switch 语句时的基本语法，但是还有一些事情您需要知道。<br />
在使用 switch 之前进行计划<br />
正如您所期待的，在使用枚举和 switch 时，您可以使用 default 语句。清单 7 显示了这<br />
个用法:<br />
<br />
清单 7. 添加一个 default 块<br />
<br />
public void testSwitchStatement(PrintStream out) throws IOException {<br />
　StringBuffer outputText = new StringBuffer(student1.getFullName());<br />
<br />
　switch (student1.getGrade()) {<br />
　　case A:<br />
　　　outputText.append(" excelled with a grade of A");<br />
　　　break;<br />
　　case B: // fall through to C<br />
　　case C:<br />
　　　outputText.append(" passed with a grade of ")<br />
　　　　　　　　.append(student1.getGrade().toString());<br />
　　　break;<br />
　　case D: // fall through to F<br />
　　case F:<br />
　　　outputText.append(" failed with a grade of ")<br />
　　　　　　　　.append(student1.getGrade().toString());<br />
　　　break;<br />
　　case INCOMPLETE:<br />
　　　outputText.append(" did not complete the class.");<br />
　　　break;<br />
　　default:<br />
　　　outputText.append(" has a grade of ")<br />
　　　　　　　　.append(student1.getGrade().toString());<br />
　　　break;<br />
　}<br />
<br />
　out.println(outputText.toString());<br />
}<br />
<br />
<br />
<br />
研究以上代码可以看出，任何没有被 case 语句处理的枚举值都会被 default 语句处理。<br />
这项技术您应当坚持采用。原因是：假设 Grade 枚举被您的小组中其他程序员修改（而且<br />
他忘记告诉您这件事）成清单 8 所示的版本：<br />
<br />
清单 8. 给 Grade 枚举添加一个值<br />
<br />
package com.oreilly.tiger.ch03;<br />
<br />
public enum Grade {<br />
　A, B, C, D, F, INCOMPLETE,<br />
　WITHDREW_PASSING, WITHDREW_FAILING<br />
};<br />
<br />
<br />
<br />
现在，如果使用清单 6 的代码所示的新版 Grade，那么这两个新值会被忽略。更糟的是，<br />
您甚至看不到错误！在这种情况下，存在某种能够通用的 default 语句是非常重要的。清<br />
单 7 无法很好地处理这些值，但是它会提示您还有其他值，您需要处理这些值。一旦完成处理，<br />
您就会有一个继续运行的应用程序，而且它不会忽略这些值，甚至还会指导您下一步的动作<br />
。所以这是一个良好的编码习惯。<br />
<br />
枚举和集合<br />
您所熟悉的使用 public static final 方法进行编码的那些东西，可能已经转而采用枚举<br />
的值作为映射的键。如果您不知道其中的含义，请参见清单 9，它是一个公共错误信息的示<br />
例，在使用 Ant 的 build 文件时，可能会弹出这样的消息，如下所示：<br />
<br />
清单 9. Ant 状态码<br />
<br />
package com.oreilly.tiger.ch03;<br />
<br />
public enum AntStatus {<br />
　INITIALIZING,<br />
　COMPILING,<br />
　COPYING,<br />
　JARRING,<br />
　ZIPPING,<br />
　DONE,<br />
　ERROR<br />
}<br />
<br />
<br />
<br />
为每个状态码分配一些人们能读懂的错误信息，从而允许人们在 Ant 提供某个代码时查找<br />
合适的错误信息，将这些信息显示在控制台上。这是映射（Map）的一个绝好用例，在这里<br />
，每个映射（Map）的键都是一个枚举值，而每个值都是键的错误信息。清单 10 演示了该<br />
映射的工作方式：<br />
<br />
清单 10. 枚举的映射（Map）<br />
<br />
public void testEnumMap(PrintStream out) throws IOException {<br />
　// Create a map with the key and a String message<br />
　EnumMap&lt;AntStatus, String&gt; antMessages =<br />
　　new EnumMap&lt;AntStatus, String&gt;(AntStatus.class);<br />
<br />
　// Initialize the map<br />
　antMessages.put(AntStatus.INITIALIZING, "Initializing Ant...");<br />
　antMessages.put(AntStatus.COMPILING,　　"Compiling Java classes...");<br />
　antMessages.put(AntStatus.COPYING,　　　"Copying files...");<br />
　antMessages.put(AntStatus.JARRING,　　　"JARring up files...");<br />
　antMessages.put(AntStatus.ZIPPING,　　　"ZIPping up files...");<br />
　antMessages.put(AntStatus.DONE,　　　　 "Build complete.");<br />
　antMessages.put(AntStatus.ERROR,　　　　"Error occurred.");<br />
<br />
　// Iterate and print messages<br />
　for (AntStatus status : AntStatus.values() ) {<br />
　　out.println("For status " + status + ", message is: " +<br />
　　　　　　　　antMessages.get(status));<br />
　}<br />
}<br />
<br />
<br />
<br />
该代码使用了泛型（generics）（请参阅参考资料）和新的 EnumMap 构造来建立新映射。<br />
而且，枚举值是通过其 Class 对象提供的，同时提供的还有映射值的类型（在该例中，它<br />
只是一个简单的字符串）。该方法的输出如清单 11 所示：<br />
<br />
枚举的 Class 对象<br />
您可能已经注意到，清单 10 中的示例代码实际上表明 Tiger 把枚举当作类，这可以从<br />
AntStatus 的 Class 对象那里得到证明，该对象不仅可用，而且正被实际使用。这是真的<br />
。归根到底, Tiger 还是把枚举看成是特殊的类类型。有关枚举的具体实现细节，请参阅<br />
Java 5.0 Tiger: A Developer"s Notebook 的第三章（请参阅参考资料）。<br />
<br />
<br />
清单 11. 清单 10 的输出<br />
<br />
[echo] Running AntStatusTester...<br />
[java] For status INITIALIZING, message is: Initializing Ant...<br />
[java] For status COMPILING, message is: Compiling Java classes...<br />
[java] For status COPYING, message is: Copying files...<br />
[java] For status JARRING, message is: JARring up files...<br />
[java] For status ZIPPING, message is: ZIPping up files...<br />
[java] For status DONE, message is: Build complete.<br />
[java] For status ERROR, message is: Error occurred.<br />
<br />
<br />
<br />
更进一步枚举也可以与集合结合使用，而且非常像新的 EnumMap 构造，Tiger 提供了一套新的<br />
EnumSet实现，允许您使用位操作符。另外，可以为枚举添加方法，用它们实现接口，定义叫作特定<br />
值的类的实体，在该实体中，特定的代码被附加到枚举的具体值上。这些特性超出了本文的<br />
范围，但是在其他地方，有详细介绍它们的文档（请参阅参考资料）。<br />
<br />
使用枚举，但是不要滥用<br />
学习任何新版语言的一个危险就是疯狂使用新的语法结构。如果这样做，那么您的代码就会<br />
突然之间有 80% 是泛型、标注和枚举。所以，应当只在适合使用枚举的地方才使用它。那<br />
么，枚举在什么地方适用呢？一条普遍规则是，任何使用常量的地方，例如目前用 switch<br />
代码切换常量的地方。如果只有单独一个值（例如，鞋的最大尺寸，或者笼子中能装猴子的<br />
最大数目），则还是把这个任务留给常量吧。但是，如果定义了一组值，而这些值中的任何<br />
一个都可以用于特定的数据类型，那么将枚举用在这个地方最适合不过。<br />
<img src ="http://www.blogjava.net/liuzheng/aggbug/165597.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liuzheng/" target="_blank">刘铮 </a> 2007-12-05 17:17 <a href="http://www.blogjava.net/liuzheng/articles/165597.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>利用jakarta Commons组件收发邮件</title><link>http://www.blogjava.net/liuzheng/articles/162544.html</link><dc:creator>刘铮 </dc:creator><author>刘铮 </author><pubDate>Fri, 23 Nov 2007 02:13:00 GMT</pubDate><guid>http://www.blogjava.net/liuzheng/articles/162544.html</guid><wfw:comment>http://www.blogjava.net/liuzheng/comments/162544.html</wfw:comment><comments>http://www.blogjava.net/liuzheng/articles/162544.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liuzheng/comments/commentRss/162544.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liuzheng/services/trackbacks/162544.html</trackback:ping><description><![CDATA[发邮件：<br />
<br />
<p class="docText"><a name="jakartackbk-CHP-10-ITERM-3172"></a>Telnet to port 25 of a SMTP server, <a name="jakartackbk-CHP-10-ITERM-3173"></a>and you will see the server respond with a numeric code (220). <tt>SMTPReply.isPositiveCompletion( )</tt> returns <tt>true</tt> if the response code of the previously executed command is between 200 and 299; the value of the initial response code, 220, is equal to the public static variable <tt>SMTPReply.SERVICE_READY</tt>. The following example uses <tt>getReplyCode( )</tt><a name="jakartackbk-CHP-10-ITERM-3174"></a> <a name="jakartackbk-CHP-10-ITERM-3175"></a>and <tt>SMTPReply.isPositiveCompletion()</tt><a name="jakartackbk-CHP-10-ITERM-3176"></a> <a name="jakartackbk-CHP-10-ITERM-3177"></a>to test the connection to<a name="jakartackbk-CHP-10-ITERM-3178"></a> <a name="jakartackbk-CHP-10-ITERM-3179"></a>the SMTP server:</p>
<pre>import org.apache.commons.net.smtp.SMTP;
import org.apache.commons.net.smtp.SMTPClient;
import org.apache.commons.net.smtp.SMTPReply;
SMTPClient client = new SMTPClient( );
client.connect("www.discursive.com");
int response = client.getReplyCode( );
if( SMTPReply.isPositiveCompletion( response ) ) {
// Set the sender and the recipients
client.setSender( "tobrien@discursive.com" );
client.addRecipient( "president@whitehouse.gov" );
client.addRecipient( "vicepresident@whitehouse.gov" );
// Supply the message via a Writer
Writer message = client.sendMessageData( );
message.write( "Spend more money on energy research.  Thanks." );
message.close( );
// Send the message and print a confirmation
boolean success = client.completePendingCommand( );
if( success ) {
System.out.println( "Message sent" );
}
} else {
System.out.println( "Error communicating with SMTP server" );
}
client.disconnect( );</pre>
<br />
<p class="docText">Instead of <tt>sendSimpleMessage( )</tt>, the previous example sets a sender address and two recipient addresses using <tt>setSender( )</tt> and <tt>addRecipient()</tt>. The message body is then written to a <tt>Writer</tt> returned by <tt>sendMessageData()</tt>. When the <tt>Writer</tt> is closed, the message is sent by calling <tt>completePendingCommand()</tt>. <tt>completePendingCommand( )</tt> returns <tt>true</tt> if the message has been queued for delivery.</p>
收邮件：<br />
<p class="docText">Use Commons Net <tt>POP3Client</tt> to check a POP3 mailbox for incoming mail. The following example connects to the <a name="jakartackbk-CHP-10-ITERM-3190"></a>POP3 server <em>www.discursive.com</em>, logs in as <tt>tobrien@discursive.com</tt>, and prints each message in the mailbox:</p>
<pre>import org.apache.commons.io.CopyUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.net.pop3.POP3Client;
import org.apache.commons.net.pop3.POP3MessageInfo;
POP3Client client = new POP3Client( );
client.connect("www.discursive.com");
client.login("tobrien@discursive.com", "secretpassword");
POP3MessageInfo[] messages = client.listMessages( );
for (int i = 0; i &lt; messages.length; i++) {
int messageNum = messages[i].number;
System.out.println( "************* Message number: " + messageNum );
Reader reader = client.retrieveMessage( messageNum );
System.out.println( "Message:\n" + IOUtils.toString( reader ) );
IOUtils.closeQuietly( reader );
}
client.logout( );
client.disconnect( );</pre>
<img src ="http://www.blogjava.net/liuzheng/aggbug/162544.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liuzheng/" target="_blank">刘铮 </a> 2007-11-23 10:13 <a href="http://www.blogjava.net/liuzheng/articles/162544.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用J2SE API读取Properties文件的六种方法</title><link>http://www.blogjava.net/liuzheng/articles/157562.html</link><dc:creator>刘铮 </dc:creator><author>刘铮 </author><pubDate>Thu, 01 Nov 2007 09:54:00 GMT</pubDate><guid>http://www.blogjava.net/liuzheng/articles/157562.html</guid><wfw:comment>http://www.blogjava.net/liuzheng/comments/157562.html</wfw:comment><comments>http://www.blogjava.net/liuzheng/articles/157562.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liuzheng/comments/commentRss/157562.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liuzheng/services/trackbacks/157562.html</trackback:ping><description><![CDATA[使用J2SE API读取Properties文件的六种方法<br />
　　<br />
　　1.使用java.util.Properties类的load()方法<br />
　　<br />
　　示例： InputStream in = lnew BufferedInputStream(new FileInputStream(name));<br />
　　Properties p = new Properties();<br />
　　p.load(in);<br />
　　<br />
　　2.使用java.util.ResourceBundle类的getBundle()方法<br />
　　<br />
　　示例： ResourceBundle rb = ResourceBundle.getBundle(name, Locale.getDefault());<br />
　　<br />
　　3.使用java.util.PropertyResourceBundle类的构造函数<br />
　　<br />
　　示例： InputStream in = new BufferedInputStream(new FileInputStream(name));<br />
　　ResourceBundle rb = new PropertyResourceBundle(in);<br />
　　<br />
　　4.使用class变量的getResourceAsStream()方法<br />
　　<br />
　　示例： InputStream in = JProperties.class.getResourceAsStream(name);<br />
　　Properties p = new Properties();<br />
　　p.load(in);<br />
　　<br />
　　5.使用class.getClassLoader()所得到的java.lang.ClassLoader的getResourceAsStream()方法<br />
　　<br />
　　示例： InputStream in = JProperties.class.getClassLoader().getResourceAsStream(name); <span class="Zci715">bitsCN.nET中国网管博客</span> <br />
　　Properties p = new Properties();<br />
　　p.load(in);<br />
　　<br />
　　6.使用java.lang.ClassLoader类的getSystemResourceAsStream()静态方法<br />
　　<br />
　　示例： InputStream in = ClassLoader.getSystemResourceAsStream(name);<br />
　　Properties p = new Properties();<br />
　　p.load(in);<br />
　　<br />
　　补充<br />
　　<br />
　　Servlet中可以使用javax.servlet.ServletContext的getResourceAsStream()方法<br />
　　<br />
　　示例：InputStream in = context.getResourceAsStream(path);<br />
　　Properties p = new Properties();<br />
　　p.load(in);<br />
　　<br />
　　完整的示例，可以参考附件文件<br />
　　<br />
　　如何上传文件，谁知道请告诉以下。 只好把source都贴上来了<br />
　　<br />
　　JProperties.java文件<br />
　　<br />
　　/**<br />
　　** This program is free software.<br />
　　**<br />
　　** You may redistribute it and/or modify it under the terms of the GNU<br />
　　** General Public License as published by the Free Software Foundation.<br />
　　** Version 2 of the license should be included with this distribution in<br />
　　** the file LICENSE, as well as License.html. If the license is not <span class="Zci715">09hr.com网管求职</span> <br />
　　** included with this distribution, you may find a copy at the FSF web<br />
　　** site at 'www.gnu.org' or 'www.fsf.org', or you may write to the<br />
　　** Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139 USA.<br />
　　**<br />
　　** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,<br />
　　** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR<br />
　　** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY<br />
　　** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR<br />
　　** REDISTRIBUTION OF THIS SOFTWARE.<br />
　　**/<br />
　　<br />
　　package com.kindani;<br />
　　<br />
　　//import javax.servlet.ServletContext;<br />
　　import java.util.*;<br />
　　import java.io.InputStream;<br />
　　import java.io.IOException;<br />
　　import java.io.BufferedInputStream;<br />
　　import java.io.FileInputStream;<br />
　　<br />
　　/**<br />
　　* 使用J2SE API読取Properties文件的六種方法<br />
　　* User: SYNFORM<br />
　　* Date: 2005/07/12<br />
　　* Time: 18:40:55<br />
　　* To change this template use File | Settings | File Templates.
<p class="Zci715">bitsCN_com</p>
<br />
　　*/<br />
　　public class JProperties {<br />
　　<br />
　　public final static int BY_PROPERTIES = 1;<br />
　　public final static int BY_RESOURCEBUNDLE = 2;<br />
　　public final static int BY_PROPERTYRESOURCEBUNDLE = 3;<br />
　　public final static int BY_CLASS = 4;<br />
　　public final static int BY_CLASSLOADER = 5;<br />
　　public final static int BY_SYSTEM_CLASSLOADER = 6;<br />
　　<br />
　　public final static Properties loadProperties(final String name, final int type) throws IOException {<br />
　　Properties p = new Properties();<br />
　　InputStream in = null;<br />
　　if (type == BY_PROPERTIES) {<br />
　　in = new BufferedInputStream(new FileInputStream(name));<br />
　　assert (in != null);<br />
　　p.load(in);<br />
　　} else if (type == BY_RESOURCEBUNDLE) {<br />
　　ResourceBundle rb = ResourceBundle.getBundle(name, Locale.getDefault());<br />
　　assert (rb != null);<br />
　　p = new ResourceBundleAdapter(rb);<br />
　　} else if (type == BY_PROPERTYRESOURCEBUNDLE) {<br />
　　in = new BufferedInputStream(new FileInputStream(name));<br />
　　assert (in != null);
<p class="Zci715">DL.bitsCN.com网管软件下载</p>
<br />
　　ResourceBundle rb = new PropertyResourceBundle(in);<br />
　　p = new ResourceBundleAdapter(rb);<br />
　　} else if (type == BY_CLASS) {<br />
　　assert (JProperties.class.equals(new JProperties().getClass()));<br />
　　in = JProperties.class.getResourceAsStream(name);<br />
　　assert (in != null);<br />
　　p.load(in);<br />
　　//　　　　return new JProperties().getClass().getResourceAsStream(name);<br />
　　} else if (type == BY_CLASSLOADER) {<br />
　　assert (JProperties.class.getClassLoader().equals(new JProperties().getClass().getClassLoader()));<br />
　　in = JProperties.class.getClassLoader().getResourceAsStream(name);<br />
　　assert (in != null);<br />
　　p.load(in);<br />
　　//　　　　 return new JProperties().getClass().getClassLoader().getResourceAsStream(name);<br />
　　} else if (type == BY_SYSTEM_CLASSLOADER) {<br />
　　in = ClassLoader.getSystemResourceAsStream(name);<br />
　　assert (in != null);<br />
　　p.load(in);<br />
　　}<br />
　　<br />
　　if (in != null) {<br />
　　in.close();<br />
　　}<br />
　　return p;<br />
　　<br />
　　}<br />
　　 <span class="Zci715">09hr.com网管求职</span> <br />
　　// ---------------------------------------------- servlet used<br />
　　/*<br />
　　public static Properties loadProperties(ServletContext context, String path) throws IOException {<br />
　　assert (context != null);<br />
　　InputStream in = context.getResourceAsStream(path);<br />
　　assert (in != null);<br />
　　Properties p = new Properties();<br />
　　p.load(in);<br />
　　in.close();<br />
　　return p;<br />
　　}<br />
　　*/<br />
　　<br />
　　// ---------------------------------------------- support class<br />
　　<br />
　　/**<br />
　　* ResourceBundle Adapter class.<br />
　　*/<br />
　　public static class ResourceBundleAdapter extends Properties {<br />
　　public ResourceBundleAdapter(ResourceBundle rb) {<br />
　　assert (rb instanceof java.util.PropertyResourceBundle);<br />
　　this.rb = rb;<br />
　　java.util.Enumeration e = rb.getKeys();<br />
　　while (e.hasMoreElements()) {<br />
　　Object o = e.nextElement();<br />
　　this.put(o, rb.getObject((String) o));<br />
　　}<br />
　　}<br />
　　<br />
　　private ResourceBundle rb = null;<br />
　　<br />
　　public ResourceBundle getBundle(String baseName) {
<p class="Zci715">BBS.bitsCN.com国内最早的网管论坛</p>
<br />
　　return ResourceBundle.getBundle(baseName);<br />
　　}<br />
　　<br />
　　public ResourceBundle getBundle(String baseName, Locale locale) {<br />
　　return ResourceBundle.getBundle(baseName, locale);<br />
　　}<br />
　　<br />
　　public ResourceBundle getBundle(String baseName, Locale locale, ClassLoader loader) {<br />
　　return ResourceBundle.getBundle(baseName, locale, loader);<br />
　　}<br />
　　<br />
　　public Enumeration&lt;String&gt; getKeys() {<br />
　　return rb.getKeys();<br />
　　}<br />
　　<br />
　　public Locale getLocale() {<br />
　　return rb.getLocale();<br />
　　}<br />
　　<br />
　　public Object getObject(String key) {<br />
　　return rb.getObject(key);<br />
　　}<br />
　　<br />
　　public String getString(String key) {<br />
　　return rb.getString(key);<br />
　　}<br />
　　<br />
　　public String[] getStringArray(String key) {<br />
　　return rb.getStringArray(key);<br />
　　}<br />
　　<br />
　　protected Object handleGetObject(String key) {<br />
　　return ((PropertyResourceBundle) rb).handleGetObject(key);<br />
　　}<br />
　　<br />
　　}<br />
　　<br />
　　}
<div class="Zci715">Play.bitsCN.com小游戏</div>
<br />
　　<br />
　　<br />
　　JPropertiesTest.java文件<br />
　　<br />
　　/**<br />
　　** This program is free software.<br />
　　**<br />
　　** You may redistribute it and/or modify it under the terms of the GNU<br />
　　** General Public License as published by the Free Software Foundation.<br />
　　** Version 2 of the license should be included with this distribution in<br />
　　** the file LICENSE, as well as License.html. If the license is not<br />
　　** included with this distribution, you may find a copy at the FSF web<br />
　　** site at 'www.gnu.org' or 'www.fsf.org', or you may write to the<br />
　　** Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139 USA.<br />
　　**<br />
　　** THIS 
<img src ="http://www.blogjava.net/liuzheng/aggbug/157562.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liuzheng/" target="_blank">刘铮 </a> 2007-11-01 17:54 <a href="http://www.blogjava.net/liuzheng/articles/157562.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java 的读写问题</title><link>http://www.blogjava.net/liuzheng/articles/157546.html</link><dc:creator>刘铮 </dc:creator><author>刘铮 </author><pubDate>Thu, 01 Nov 2007 09:28:00 GMT</pubDate><guid>http://www.blogjava.net/liuzheng/articles/157546.html</guid><wfw:comment>http://www.blogjava.net/liuzheng/comments/157546.html</wfw:comment><comments>http://www.blogjava.net/liuzheng/articles/157546.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liuzheng/comments/commentRss/157546.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liuzheng/services/trackbacks/157546.html</trackback:ping><description><![CDATA[A common question when using the IO classes is why this block of code does not work:
<p><code></span><br />
<span class="java_type">File</span>&nbsp;aFile&nbsp;=&nbsp;<span class="java_keyword">new</span>&nbsp;<span class="java_type">File</span>(<span class="java_literal">"input.data"</span>);</span><br />
<span class="java_type">InputStream</span>&nbsp;is&nbsp;=&nbsp;<span class="java_keyword">new</span>&nbsp;<span class="java_type">FileInputStream</span>(aFile);</span><br />
<span class="java_type">byte</span>[]&nbsp;data&nbsp;=&nbsp;<span class="java_keyword">new</span>&nbsp;<span class="java_type">byte</span>[aFile.length()];</span><br />
is.read(data);</span><br />
</code>
<p>The results can be puzzling. If the input file is an image it may be mangled or not display at all. Binary or text data may be incomplete. This is because Read Doesn't Do What You Think It Does. A quick glance at the Java API for <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/io/InputStream.html" rel="nofollow">java.io.InputStream</a> gives us the following information:
<p><code></span><br />
<span class="java_keyword">public</span>&nbsp;<span class="java_type">int</span>&nbsp;read(<span class="java_type">byte</span>[]&nbsp;b)&nbsp;<span class="java_keyword">throws</span>&nbsp;<span class="java_type">IOException</span></span><br />
</code>
<p>
<pre>Reads some number of bytes from the input stream and stores them
into the buffer array b. The number of bytes actually read is returned as an integer. . .</pre>
<p>The documentation states that read reads "some number" of bytes. It is not guaranteed to fill the byte array. The number of bytes read is returned by the read method. One should use this return value to make sure that he is receiving the data which he expects. A correct usage of read() would be to read chunks of a file and collect them in a buffer like so:
<p><code></span><br />
<span class="java_type">ByteArrayOutputStream</span>&nbsp;buffer&nbsp;=&nbsp;<span class="java_keyword">new</span>&nbsp;<span class="java_type">ByteArrayOutputStream</span>();</span><br />
<span class="java_type">File</span>&nbsp;aFile&nbsp;=&nbsp;<span class="java_keyword">new</span>&nbsp;<span class="java_type">File</span>(<span class="java_literal">"input.data"</span>);</span><br />
<span class="java_type">InputStream</span>&nbsp;is&nbsp;=&nbsp;<span class="java_keyword">new</span>&nbsp;<span class="java_type">FileInputStream</span>(aFile);</span><br />
<span class="java_type">byte</span>[]&nbsp;temp&nbsp;=&nbsp;<span class="java_keyword">new</span>&nbsp;<span class="java_type">byte</span>[<span class="java_literal">1024</span>];</span><br />
<span class="java_type">int</span>&nbsp;read;</span><br />
</span><br />
<span class="java_keyword">while</span>((read&nbsp;=&nbsp;is.read(temp))&nbsp;&gt;&nbsp;<span class="java_literal">0</span>){</span><br />
&nbsp;&nbsp;&nbsp;buffer.write(temp,&nbsp;<span class="java_literal">0</span>,&nbsp;read);</span><br />
}</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><br />
<span class="java_type">byte</span>[]&nbsp;data&nbsp;=&nbsp;buffer.toByteArray();</span><br />
<span class="java_comment">//&nbsp;process&nbsp;the&nbsp;data&nbsp;array&nbsp;.&nbsp;.&nbsp;.</span><br />
</code></p>
<img src ="http://www.blogjava.net/liuzheng/aggbug/157546.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liuzheng/" target="_blank">刘铮 </a> 2007-11-01 17:28 <a href="http://www.blogjava.net/liuzheng/articles/157546.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>内部类的作用</title><link>http://www.blogjava.net/liuzheng/articles/155015.html</link><dc:creator>刘铮 </dc:creator><author>刘铮 </author><pubDate>Mon, 22 Oct 2007 07:59:00 GMT</pubDate><guid>http://www.blogjava.net/liuzheng/articles/155015.html</guid><wfw:comment>http://www.blogjava.net/liuzheng/comments/155015.html</wfw:comment><comments>http://www.blogjava.net/liuzheng/articles/155015.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liuzheng/comments/commentRss/155015.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liuzheng/services/trackbacks/155015.html</trackback:ping><description><![CDATA[转贴：<br />
<div style="text-indent: 17.95pt">Java内部类是Java言语的一个很重要的概念，《Java编程思想》花了很大的篇幅来讲述这个概念。但是我们在实践中很少用到它，虽然我们在很多时候会被动的使用到它，但它仍然像一个幕后英雄一样，不为我们所知，不为我们所用。</div>
<div style="text-indent: 17.95pt">本文不试图来讲述Java内部类的今生前世、来龙去脉，这些在网络上都已经汗牛充栋。如果读者想了解这些，可以在网络上搜索来学习。Java内部类总是躲在它的外部类里，像一个幕后英雄一样。但是幕后英雄也有用武之地，在很多时候，恰当的使用Java内部类能起到让人拍案叫绝的作用。本文试图谈一谈让这个幕后英雄也有用武之地的四个场景，希望引起大家对使用Java内部类的兴趣。</div>
<div style="text-indent: 17.95pt">以下的文字，要求大家熟悉Java内部类的概念后来阅读。</div>
<div style="text-indent: 17.95pt">&nbsp;</div>
<div style="text-indent: 17.95pt">&nbsp;</div>
<div style="text-indent: 17.95pt">场景一：当某个类除了它的外部类，不再被其他的类使用时</div>
<div style="text-indent: 17.95pt">我们说这个内部类依附于它的外部类而存在，可能的原因有：1、不可能为其他的类使用；2、出于某种原因，不能被其他类引用，可能会引起错误。等等。这个场景是我们使用内部类比较多的一个场景。下面我们以一个大家熟悉的例子来说明。</div>
<div style="text-indent: 17.95pt">在我们的企业级Java项目开发过程中，数据库连接池是一个我们经常要用到的概念。虽然在很多时候，我们都是用的第三方的数据库连接池，不需要我们亲自来做这个数据库连接池。但是，作为我们Java内部类使用的第一个场景，这个数据库连接池是一个很好的例子。为了简单起见，以下我们就来简单的模拟一下数据库连接池，在我们的例子中，我们只实现数据库连接池的一些简单的功能。如果想完全实现它，大家不妨自己试一试。</div>
<div style="text-indent: 17.95pt">首先，我们定义一个接口，将数据库连接池的功能先定义出来，如下：</div>
<div style="text-indent: 17.95pt">public interface Pool extends TimerListener</div>
<div style="text-indent: 17.95pt">{</div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //</span>初始化连接池</div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public boolean init();</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //</span>销毁连接池</div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void destory();</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //</span>取得一个连接</div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public Connection getConn();</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //</span>还有一些其他的功能，这里不再列出</div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8230;&#8230;</span></div>
<div style="text-indent: 17.95pt">}</div>
<div style="text-indent: 17.95pt">有了这个功能接口，我们就可以在它的基础上实现数据库连接池的部分功能了。我们首先想到这个数据库连接池类的操作对象应该是由Connection对象组成的一个数组，既然是数组，我们的池在取得Connection的时候，就要对数组元素进行遍历，看看Connection对象是否已经被使用，所以数组里每一个Connection对象都要有一个使用标志。我们再对连接池的功能进行分析，会发现每一个Connection对象还要一个上次访问时间和使用次数。</div>
<div style="text-indent: 17.95pt">通过上面的分析，我们可以得出，连接池里的数组的元素应该是由对象组成，该对象的类可能如下：</div>
<div style="text-indent: 17.95pt">public class PoolConn</div>
<div style="text-indent: 17.95pt">{</div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private Connection conn;</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private boolean isUse;</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private long lastAccess;</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private int useCount;</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8230;&#8230;</span></div>
<div style="text-indent: 17.95pt">}</div>
<div style="text-indent: 17.95pt">下面的省略号省掉的是关于四个属性的一些get和set方法。我们可以看到这个类的核心就是Connection，其他的一些属性都是Connection的一些标志。可以说这个类只有在连接池这个类里有用，其他地方用不到。这时候，我们就该考虑是不是可以把这个类作为一个内部类呢？而且我们把它作为一个内部类以后，可以把它定义成一个私有类，然后将它的属性公开，这样省掉了那些无谓的get和set方法。下面我们就试试看：</div>
<div style="text-indent: 17.95pt">public class ConnectPool implements Pool</div>
<div style="text-indent: 17.95pt">{</div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //</span>存在Connection的数组</div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private PoolConn[] poolConns;</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //</span>连接池的最小连接数</div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private int min;</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //</span>连接池的最大连接数</div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private int max;</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //</span>一个连接的最大使用次数</div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private int maxUseCount;</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //</span>一个连接的最大空闲时间</div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private long maxTimeout;</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //</span>同一时间的Connection最大使用个数</div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private int maxConns;</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //</span>定时器</div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private Timer timer;</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public boolean init()</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8230;&#8230;</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.poolConns = new PoolConn[this.min];</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&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;this.min;i++)</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></div>
<div style="text-indent: 17.95pt"><span>&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; PoolConn poolConn = new PoolConn();</span></div>
<div style="text-indent: 17.95pt"><span>&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; poolConn.conn = ConnectionManager.getConnection();</span></div>
<div style="text-indent: 17.95pt"><span>&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; poolConn.isUse = false;</span></div>
<div style="text-indent: 17.95pt"><span>&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; poolConn.lastAccess = new Date().getTime();</span></div>
<div style="text-indent: 17.95pt"><span>&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; poolConn.useCount = 0;</span></div>
<div style="text-indent: 17.95pt"><span>&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; this.poolConns[i] = poolConn;</span></div>
<div style="margin: 0cm 0cm 0pt 63pt; text-indent: 21pt">}</div>
<div style="margin: 0cm 0cm 0pt 63pt; text-indent: 21pt">&#8230;&#8230;</div>
<div style="margin: 0cm 0cm 0pt 63pt; text-indent: 21pt">return true;</div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch(Exception e)</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return false;</span></div>
<div style="margin: 0cm 0cm 0pt 42pt; text-indent: 21pt">}</div>
<div style="margin: 0cm 0cm 0pt 21pt; text-indent: 21pt">}</div>
<div style="margin: 0cm 0cm 0pt 21pt; text-indent: 21pt">&#8230;&#8230;</div>
<div style="margin: 0cm 0cm 0pt 21pt; text-indent: 21pt">private class PoolConn</div>
<div style="margin: 0cm 0cm 0pt 21pt; text-indent: 21pt">{</div>
<div style="margin: 0cm 0cm 0pt 21pt; text-indent: 21pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public Connection conn;</span></div>
<div style="margin: 0cm 0cm 0pt 21pt; text-indent: 21pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public boolean isUse;</span></div>
<div style="margin: 0cm 0cm 0pt 42pt; text-indent: 21pt">public long lastAccess;</div>
<div style="margin: 0cm 0cm 0pt 21pt; text-indent: 21pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public int useCount;</span></div>
<div style="margin: 0cm 0cm 0pt 21pt; text-indent: 21pt">}</div>
<div style="text-indent: 17.95pt">}</div>
<div style="text-indent: 17.95pt">因为本文不是专题来讲述数据库连接池的，所以在上面的代码中绝大部分的内容被省略掉了。PoolConn类不大可能被除了ConnectionPool类的其他类使用到，把它作为ConnectionPool的私有内部类不会影响到其他类。同时，我们可以看到，使用了内部类，使得我们可以将该内部类的数据公开，ConnectionPool类可以直接操作PoolConn类的数据成员，避免了因set和get方法带来的麻烦。</div>
<div style="text-indent: 17.95pt">上面的一个例子，是使用内部类使得你的代码得到简化和方便。还有些情况下，你可能要避免你的类被除了它的外部类以外的类使用到，这时候你却不得不使用内部类来解决问题。</div>
<div style="text-indent: 17.95pt">&nbsp;</div>
<div style="text-indent: 17.95pt">场景二：解决一些非面向对象的语句块</div>
<div style="text-indent: 17.95pt">这些语句块包括if&#8230;else if&#8230;else语句，case语句，等等。这些语句都不是面向对象的，给我们造成了系统的扩展上的麻烦。我们可以看看，在模式中，有多少模式是用来解决由if语句带来的扩展性的问题。</div>
<div style="text-indent: 17.95pt">Java编程中还有一个困扰我们的问题，那就是try&#8230;catch&#8230;问题，特别是在JDBC编程过程中。请看下面的代码：</div>
<div style="text-indent: 17.95pt">&#8230;&#8230;</div>
<div style="text-indent: 17.95pt">try</div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;{</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;String[] divisionData = null;</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;conn = manager.getInstance().getConnection();</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;stmt = (OracleCallableStatement)conn.prepareCall("{ Call PM_GET_PRODUCT.HEADER_DIVISION(?, ?) }");</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;stmt.setLong(1 ,productId.longValue() );</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;stmt.registerOutParameter(2, oracle.jdbc.OracleTypes.CURSOR); ;</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;stmt.execute();</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;ResultSet rs = stmt.getCursor(2);</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;int i = 0 ;</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;String strDivision = "";</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;while( rs.next() )</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;{</span></div>
<div style="text-indent: 17.95pt"><span>&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; strDivision += rs.getString("DIVISION_ID") + ","&nbsp;;</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; }</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; int length = strDivision.length() ;</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; if(length != 0 )</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; {</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; strDivision = strDivision.substring(0,length - 1);</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; }</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; divisionData = StringUtil.split(strDivision, ",") ;</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; map.put("Division", strDivision ) ;</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; LoggerAgent.debug("GetHeaderProcess","getDivisionData","getValue + " + strDivision +" " + productId) ;</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }catch(Exception&nbsp;e)</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;LoggerAgent.error("GetHeaderData", "getDivisionData",</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; "SQLException: " + e);</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;e.printStackTrace() ;</span></div>
<div style="text-indent: 17.95pt">&nbsp;</div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }finally</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;manager.close(stmt);</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;manager.releaseConnection(conn);</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div style="text-indent: 17.95pt">这是我们最最常用的一个JDBC编程的代码示例。一个系统有很多这样的查询方法，这段代码一般分作三段：try关键字括起来的那段是用来做查询操作的，catch关键字括起来的那段需要做两件事，记录出错的原因和事务回滚（如果需要的话），finally关键字括起来的那段用来释放数据库连接。</div>
<div style="text-indent: 17.95pt">我们的烦恼是：try关键字括起来的那段是变化的，每个方法的一般都不一样。而catch和finally关键字括起来的那两段却一般都是不变的，每个方法的那两段都是一样的。既然后面那两段是一样的，我们就非常希望将它们提取出来，做一个单独的方法，然后让每一个使用到它们的方法调用。但是，try&#8230;catch&#8230;finally&#8230;是一个完整的语句段，不能把它们分开。这样的结果，使得我们不得不在每一个数据层方法里重复的写相同的catch&#8230;finally&#8230;这两段语句。</div>
<div style="text-indent: 17.95pt">既然不能将那些讨厌的try&#8230;catch&#8230;finally&#8230;作为一个公用方法提出去，那么我们还是需要想其他的办法来解决这个问题。不然我们老是写那么重复代码，真是既繁琐，又不容易维护。</div>
<div style="text-indent: 17.95pt">我们容易想到，既然catch&#8230;finally&#8230;这两段代码不能提出来，那么我们能不能将try&#8230;里面的代码提出去呢？唉哟，try&#8230;里面的代码是可变的呢。怎么办？</div>
<div style="text-indent: 17.95pt">既然try&#8230;里面的代码是可变的，这意味着这些代码是可扩展的，是应该由用户来实现的，对于这样的可扩展内容，我们很容易想到用接口来定义它们，然后由用户去实现。这样以来我们首先定义一个接口：</div>
<div style="text-indent: 17.95pt">public interface DataManager</div>
<div style="text-indent: 17.95pt">{</div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void manageData();</span></div>
<div style="text-indent: 17.95pt">}</div>
<div style="text-indent: 17.95pt">我们需要用户在manageData()方法中实现他们对数据层访问的代码，也就是try&#8230;里面的代码。</div>
<div style="text-indent: 17.95pt">然后我们使用一个模板类来实现所有的try&#8230;catch&#8230;finally&#8230;语句的功能，如下：</div>
<div style="text-indent: 17.95pt">public class DataTemplate</div>
<div style="text-indent: 17.95pt">{</div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void execute(DataManager dm)</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dm.manageData();</span></div>
<div style="margin: 0cm 0cm 0pt 42pt; text-indent: 21pt">}</div>
<div style="text-indent: 17.95pt">catch(Exception&nbsp;e)</div>
<div style="text-indent: 17.95pt">{</div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LoggerAgent.error("GetHeaderData", "getDivisionData",</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; "SQLException: " + e);</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e.printStackTrace() ;</span></div>
<div style="text-indent: 17.95pt">&nbsp;</div>
<div style="text-indent: 17.95pt">}finally</div>
<div style="text-indent: 17.95pt">{</div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; manager.close(stmt);</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; manager.releaseConnection(conn);</span></div>
<div style="margin: 0cm 0cm 0pt 38.95pt; text-indent: 21pt">}</div>
<div style="margin: 0cm 0cm 0pt 17.95pt; text-indent: 21pt">}</div>
<div style="text-indent: 17.95pt">}</div>
<div style="text-indent: 17.95pt">这样，一个模板类就完成了。我们也通过这个模板类将catch&#8230;finally&#8230;两段代码提出来了。我们来看看使用了这个模板类的数据层方法是怎么实现的：</div>
<div style="text-indent: 17.95pt">new DataTemplate().execute(new DataManager()</div>
<div style="text-indent: 17.95pt">{</div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void manageData()</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;String[] divisionData = null;</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;conn = manager.getInstance().getConnection();</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;stmt = (OracleCallableStatement)conn.prepareCall("{ Call PM_GET_PRODUCT.HEADER_DIVISION(?, ?) }");</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;stmt.setLong(1 ,productId.longValue() );</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;stmt.registerOutParameter(2, oracle.jdbc.OracleTypes.CURSOR); ;</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;stmt.execute();</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;ResultSet rs = stmt.getCursor(2);</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;int i = 0 ;</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;String strDivision = "";</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;while( rs.next() )</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;{</span></div>
<div style="text-indent: 17.95pt"><span>&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; strDivision += rs.getString("DIVISION_ID") + ","&nbsp;;</span></div>
<div style="text-indent: 10.5pt">}</div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; int length = strDivision.length() ;</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; if(length != 0 )</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; {</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; strDivision = strDivision.substring(0,length - 1);</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; }</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; divisionData = StringUtil.split(strDivision, ",") ;</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; map.put("Division", strDivision ) ;</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; LoggerAgent.debug("GetHeaderProcess","getDivisionData","getValue + " + strDivision +" " + productId) ;</span></div>
<div style="margin: 0cm 0cm 0pt 21pt; text-indent: 21pt">}</div>
<div style="text-indent: 17.95pt">});</div>
<div style="text-indent: 17.95pt">注意：本段代码仅供思路上的参考，没有经过上机测试。</div>
<div style="text-indent: 17.95pt">我们可以看到，正是这个实现了DataManager接口得匿名内部类的使用，才使得我们解决了对try&#8230;catch&#8230;finally&#8230;语句的改造。这样，第一为我们解决了令人痛苦的重复代码；第二也让我们在数据层方法的编码中，直接关注对数据的操作，不用关心那些必需的但是与数据操作无关的东西。</div>
<div style="text-indent: 17.95pt">我们现在来回想一下Spring框架的数据层，是不是正是使用了这种方法呢？</div>
<div style="text-indent: 17.95pt">&nbsp;</div>
<div style="text-indent: 17.95pt">&nbsp;</div>
<div style="text-indent: 17.95pt">场景之三：一些多算法场合</div>
<div style="text-indent: 17.95pt">假如我们有这样一个需求：我们的一个方法用来对数组排序并且依次打印各元素，对数组排序方法有很多种，用哪种方法排序交给用户自己确定。</div>
<div style="text-indent: 17.95pt">对于这样一个需求，我们很容易解决。我们决定给哪些排序算法定义一个接口，具体的算法实现由用户自己完成，只要求他实现我们的接口就行。</div>
<div style="text-indent: 17.95pt">public interface SortAlgor</div>
<div style="text-indent: 17.95pt">{</div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void sort(int[] is);</span></div>
<div style="text-indent: 17.95pt">}</div>
<div style="text-indent: 17.95pt">这样，我们再在方法里实现先排序后打印，代码如下：</div>
<div style="text-indent: 17.95pt">public void printSortedArray(int[] is,SortAlgor sa)</div>
<div style="text-indent: 17.95pt">{</div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8230;&#8230;</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sa.sort(is);</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(int i=0;i&lt;is.length;i++)</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.print(is[i]+&#8221; &#8220;);</span></div>
<div style="margin: 0cm 0cm 0pt 21pt; text-indent: 21pt">}</div>
<div style="margin: 0cm 0cm 0pt 21pt; text-indent: 21pt">System.out.println();</div>
<div style="text-indent: 17.95pt">}</div>
<div style="text-indent: 17.95pt">客户端对上面方法的使用如下：</div>
<div style="text-indent: 17.95pt">int[] is = new int[]{3,1,4,9,2};</div>
<div style="text-indent: 17.95pt">printSortedArray(is,new SortAlgor()</div>
<div style="text-indent: 17.95pt">{</div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void sort(is)</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int k = 0;</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(int i=0;i&lt;is.length;i++)</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(int j=i+1;j&lt;is.length;j++)</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></div>
<div style="text-indent: 17.95pt"><span>&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; if(is[i]&gt;is[j])</span></div>
<div style="text-indent: 17.95pt"><span>&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; {</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; k = is[i];</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; is[i] = is[j];</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; is[j] = k;</span></div>
<div style="text-indent: 17.95pt"><span>&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; }</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div style="margin: 0cm 0cm 0pt 21pt; text-indent: 21pt">}</div>
<div style="text-indent: 17.95pt">});</div>
<div style="text-indent: 17.95pt">这样的用法很多，我们都或多或少的被动的使用过。如在Swing编程中，我们经常需要对组件增加监听器对象，如下所示：</div>
<div style="text-indent: 17.95pt">spinner2.addChangeListener(new ChangeListener()</div>
<div style="margin: 0cm 0cm 0pt 21pt; text-indent: 21pt">{</div>
<div style="margin: 0cm 0cm 0pt 62.8pt">public void stateChanged(ChangeEvent e) </div>
<div style="text-indent: -10.5pt">{<br />
System.out.println("Source: " + e.getSource());</div>
<div style="text-indent: -10.5pt">}</div>
<div style="margin: 0cm 0cm 0pt 21pt; text-indent: 21pt">}</div>
<div style="text-indent: 17.95pt">);</div>
<div style="text-indent: 17.95pt">在Arrays包里，对元素为对象的数组的排序：</div>
<div style="text-indent: 17.95pt">Arrays.sort(emps,new Comparator(){</div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Public int compare(Object o1,Object o2)</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ((Employee)o1).getServedYears()-((Employee)o2).getServedYears();</span></div>
<div style="margin: 0cm 0cm 0pt 21pt; text-indent: 21pt">}</div>
<div style="text-indent: 17.95pt">})；</div>
<div style="text-indent: 17.95pt">这样的例子还有很多，JDK教会了我们很多使用内部类的方法。随时我们都可以看一看API，看看还会在什么地方使用到内部类呢？</div>
<div style="text-indent: 17.95pt">&nbsp;</div>
<div style="text-indent: 17.95pt">&nbsp;</div>
<div style="text-indent: 17.95pt">&nbsp;</div>
<div style="text-indent: 17.95pt">场景之四：适当使用内部类，使得代码更加灵活和富有扩展性</div>
<div style="text-indent: 17.95pt">适当的使用内部类，可以使得你的代码更加灵活和富有扩展性。当然，在这里头起作用的还是一些模式的运行，但如果不配以内部类的使用，这些方法的使用效果就差远了。不信？请看下面的例子：</div>
<div style="text-indent: 17.95pt">我们记得简单工厂模式的作用就是将客户对各个对象的依赖转移到了工厂类里。很显然，简单工厂模式并没有消除那些依赖，只是简单的将它们转移到了工厂类里。如果有新的对象增加进来，则我们需要修改工厂类。所以我们需要对工厂类做进一步的改造，进一步消除它对具体类的依赖。以前我们提供过一个使用反射来消除依赖的方法；这里，我们将提供另外一种方法。</div>
<div style="text-indent: 17.95pt">这种方法是将工厂进一步抽象，而将具体的工厂类交由具体类的创建者来实现，这样，工厂类和具体类的依赖的问题就得到了解决。而工厂的使用者则调用抽象的工厂来获得具体类的对象。如下。</div>
<div style="text-indent: 17.95pt">我们以一个生产形体的工厂为例，下面是这些形体的接口：</div>
<div style="text-indent: 17.95pt">package polyFactory;</div>
<div style="text-indent: 17.95pt">&nbsp;</div>
<div style="text-indent: 17.95pt">public interface Shape {</div>
<div style="text-indent: 17.95pt">public void draw();</div>
<div style="text-indent: 17.95pt">public void erase();</div>
<div style="text-indent: 17.95pt">&nbsp;</div>
<div style="text-indent: 17.95pt">}</div>
<div style="text-indent: 17.95pt">&nbsp;</div>
<div style="text-indent: 17.95pt">通过上面的描述，大家都可能已经猜到，这个抽象的工厂肯定使用的是模板方法模式。如下：</div>
<div style="text-indent: 17.95pt">package polyFactory;</div>
<div style="text-indent: 17.95pt">&nbsp;</div>
<div style="text-indent: 17.95pt">import java.util.HashMap;</div>
<div style="text-indent: 17.95pt">import java.util.Map;</div>
<div style="text-indent: 17.95pt">&nbsp;</div>
<div style="text-indent: 17.95pt">&nbsp;</div>
<div style="text-indent: 17.95pt">public abstract class ShapeFactory {</div>
<div style="text-indent: 17.95pt">protected abstract Shape create();</div>
<div style="text-indent: 17.95pt">private static Map factories = new HashMap();</div>
<div style="text-indent: 17.95pt">public static void addFactory(String id,ShapeFactory f)</div>
<div style="text-indent: 17.95pt">{</div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; factories.put(id,f);</span></div>
<div style="text-indent: 17.95pt">}</div>
<div style="text-indent: 17.95pt">public static final Shape createShape(String id)</div>
<div style="text-indent: 17.95pt">{</div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(!factories.containsKey(id))</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Class.forName("polyFactory."+id);</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch(ClassNotFoundException e)</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new RuntimeException("Bad shape creation : "+id);</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ((ShapeFactory)factories.get(id)).create();</span></div>
<div style="text-indent: 17.95pt">}</div>
<div style="text-indent: 17.95pt">}</div>
<div style="text-indent: 17.95pt">不错，正是模板方法模式的运用。这个类蛮简单的：首先是一个create()方法，用来产生具体类的对象，留交各具体工厂实现去实现。然后是一个Map类型的静态变量，用来存放具体工厂的实现以及他们的ID号。接着的一个方法使用来增加一个具体工厂的实现。最后一个静态方法是用来获取具体对象，里面的那个Class.forName&#8230;&#8230;的作用是调用以ID号为类名的类的一些静态的东西。</div>
<div style="text-indent: 17.95pt">下面，我们来看具体的类的实现：</div>
<div style="text-indent: 17.95pt">package polyFactory;</div>
<div style="text-indent: 17.95pt">&nbsp;</div>
<div style="text-indent: 17.95pt">public class Circle implements Shape {</div>
<div style="text-indent: 17.95pt">&nbsp;</div>
<div style="text-indent: 17.95pt">&nbsp;</div>
<div style="text-indent: 17.95pt">public void draw() {</div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // TODO Auto-generated method stub</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("the circle is drawing...");</span></div>
<div style="text-indent: 17.95pt">}</div>
<div style="text-indent: 17.95pt">&nbsp;</div>
<div style="text-indent: 17.95pt">&nbsp;</div>
<div style="text-indent: 17.95pt">public void erase() {</div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // TODO Auto-generated method stub</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("the circle is erasing...");</span></div>
<div style="text-indent: 17.95pt">}</div>
<div style="text-indent: 17.95pt">private static class Factory extends ShapeFactory</div>
<div style="text-indent: 17.95pt">{</div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; protected Shape create()</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return new Circle();</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div style="text-indent: 17.95pt">}</div>
<div style="text-indent: 17.95pt">static {ShapeFactory.addFactory("Circle",new Factory());}</div>
<div style="text-indent: 17.95pt">&nbsp;</div>
<div style="text-indent: 17.95pt">}</div>
<div style="text-indent: 17.95pt">这个类的其他的地方也平常得很。但就是后面的那个内部类Factory用得好。第一呢，这个类只做一件事，就是产生一个Circle对象，与其他类无关，就这一个条也就满足了使用内部类的条件。第二呢，这个Factory类需要是静态的，这也得要求它被使用内部类，不然，下面的ShapeFacotry.addFactory就没办法add了。而最后的那个静态的语句块是用来将具体的工厂类添加到抽象的工厂里面去。在抽象工厂里调用Class.forName就会执行这个静态的语句块了。</div>
<div style="text-indent: 17.95pt">下面仍然是一个具体类：</div>
<div style="text-indent: 17.95pt">package polyFactory;</div>
<div style="text-indent: 17.95pt">&nbsp;</div>
<div style="text-indent: 17.95pt">&nbsp;</div>
<div style="text-indent: 17.95pt">public class Square implements Shape {</div>
<div style="text-indent: 17.95pt">&nbsp;</div>
<div style="text-indent: 17.95pt">public void draw() {</div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // TODO Auto-generated method stub</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("the square is drawing...");</span></div>
<div style="text-indent: 17.95pt">}</div>
<div style="text-indent: 17.95pt">&nbsp;</div>
<div style="text-indent: 17.85pt">public void erase() {</div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // TODO Auto-generated method stub</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("the square is erasing...");</span></div>
<div style="text-indent: 17.95pt">}</div>
<div style="text-indent: 17.95pt">private static class Factory extends ShapeFactory</div>
<div style="text-indent: 17.95pt">{</div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; protected Shape create()</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return new Square();</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div style="text-indent: 17.95pt">}</div>
<div style="text-indent: 17.95pt">static {ShapeFactory.addFactory("Square",new Factory());}</div>
<div style="text-indent: 17.95pt">&nbsp;</div>
<div style="text-indent: 17.95pt">}</div>
<div style="text-indent: 17.95pt">最后，我们来测试一下：</div>
<div style="margin: 0cm 0cm 0pt 21pt; text-indent: 21pt">String[] ids = new String[]{"Circle","Square","Square","Circle"};</div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(int i=0;i&lt;ids.length;i++)</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Shape shape = ShapeFactory.createShape(ids[i]);</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; shape.draw();</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; shape.erase();</span></div>
<div style="text-indent: 17.95pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div style="text-indent: 17.95pt">测试结果为：</div>
<div style="text-indent: 17.95pt" align="left"><span style="font-size: 10pt; background: white; color: blue">the circle is drawing...</span></div>
<div style="text-indent: 17.95pt" align="left"><span style="font-size: 10pt; background: white; color: blue">the circle is erasing...</span></div>
<div style="text-indent: 17.95pt" align="left"><span style="font-size: 10pt; background: white; color: blue">the square is drawing...</span></div>
<div style="text-indent: 17.95pt" align="left"><span style="font-size: 10pt; background: white; color: blue">the square is erasing...</span></div>
<div style="text-indent: 17.95pt" align="left"><span style="font-size: 10pt; background: white; color: blue">the square is drawing...</span></div>
<div style="text-indent: 17.95pt" align="left"><span style="font-size: 10pt; background: white; color: blue">the square is erasing...</span></div>
<div style="text-indent: 17.1pt" align="left"><span style="font-size: 10pt; background: white; color: blue">the circle is drawing...</span></div>
<div style="text-indent: 17.1pt"><span style="font-size: 10pt; background: white; color: blue">the circle is erasing...</span></div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;这个方法是巧妙地使用了内部类，将具体类的实现和它的具体工厂类绑定起来，由具体类的实现者在这个内部类的具体工厂里去产生一个具体类的对象，这当然容易得多。虽然需要每一个具体类都创建一个具体工厂类，但由于具体工厂类是一个内部类，这样也不会随着具体类的增加而不断增加新的工厂类，使得代码看起来很臃肿，这也是本方法不得不使用内部类的一个原因吧。</div>
<img src ="http://www.blogjava.net/liuzheng/aggbug/155015.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liuzheng/" target="_blank">刘铮 </a> 2007-10-22 15:59 <a href="http://www.blogjava.net/liuzheng/articles/155015.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>有关类中的重构问题</title><link>http://www.blogjava.net/liuzheng/articles/153827.html</link><dc:creator>刘铮 </dc:creator><author>刘铮 </author><pubDate>Thu, 18 Oct 2007 04:07:00 GMT</pubDate><guid>http://www.blogjava.net/liuzheng/articles/153827.html</guid><wfw:comment>http://www.blogjava.net/liuzheng/comments/153827.html</wfw:comment><comments>http://www.blogjava.net/liuzheng/articles/153827.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liuzheng/comments/commentRss/153827.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liuzheng/services/trackbacks/153827.html</trackback:ping><description><![CDATA[类中可以将按照Constraint, Process and Specification进行重构<br />
<br />
例如：<br />
public class Bookshelf {<br />
private int capacity = 20;<br />
private Collection content;<br />
public void add(Book book) {<br />
if(content.size() + 1 &lt;= capacity)<br />
{<br />
content.add(book);<br />
} else {<br />
throw new<br />
IllegalOperationException(<br />
&#8220;The bookshelf has reached<br />
its limit.&#8221;);<br />
}<br />
}<br />
}<br />
We can refactor the code, extracting the constraint in a separate<br />
method.<br />
public class Bookshelf {<br />
private int capacity = 20;<br />
private Collection content;<br />
public void add(Book book) {<br />
if(isSpaceAvailable()) {<br />
content.add(book);<br />
} else {<br />
throw new<br />
IllegalOperationException(<br />
&#8220;The bookshelf has reached<br />
its limit.&#8221;);<br />
}<br />
}<br />
private boolean isSpaceAvailable() {<br />
return content.size() &lt; capacity;<br />
}<br />
}
<img src ="http://www.blogjava.net/liuzheng/aggbug/153827.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liuzheng/" target="_blank">刘铮 </a> 2007-10-18 12:07 <a href="http://www.blogjava.net/liuzheng/articles/153827.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在java中使用DOM对XML的解析</title><link>http://www.blogjava.net/liuzheng/articles/153013.html</link><dc:creator>刘铮 </dc:creator><author>刘铮 </author><pubDate>Mon, 15 Oct 2007 08:22:00 GMT</pubDate><guid>http://www.blogjava.net/liuzheng/articles/153013.html</guid><wfw:comment>http://www.blogjava.net/liuzheng/comments/153013.html</wfw:comment><comments>http://www.blogjava.net/liuzheng/articles/153013.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liuzheng/comments/commentRss/153013.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liuzheng/services/trackbacks/153013.html</trackback:ping><description><![CDATA[通过DOM模型可以对XML进行解析：<br />
<pre>DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
</pre>
<br />
<p class="docText">You can now read a document from a file:</p>
<pre>File f = . . .
Document doc = builder.parse(f);
</pre>
<br />
<p class="docText">Alternatively, you can use a URL:</p>
<pre>URL u = . . .
Document doc = builder.parse(u);
</pre>
<br />
<p class="docText">You can even specify an arbitrary input stream:</p>
<pre>InputStream in = . . .
Document doc = builder.parse(in);
</pre>
<br />
Element root = doc.getDocumentElement();<br />
<br />
注意如果使用这种解析方法的话：<br />
会有空格产生<br />
<pre>NodeList children = root.getChildNodes();
for (int i = 0; i &lt; children.getLength(); i++)
{
Node child = children.item(i);
. . .
}
</pre>
<br />
如果避免空格产生<br />
<br />
<br />
<p class="docText">If you expect only subelements, then you can ignore the whitespace:</p>
<pre>for (int i = 0; i &lt; children.getLength(); i++)
{
Node child = children.item(i);
if (child instanceof Element)
{
Element childElement = (Element) child;
. . .
}
}
</pre>
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Text textNode = (Text) childElement.getFirstChild();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String text = textNode.getData().trim();<br />
getData()方法可以得到textNode中的值<br />
<br />
<img src ="http://www.blogjava.net/liuzheng/aggbug/153013.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liuzheng/" target="_blank">刘铮 </a> 2007-10-15 16:22 <a href="http://www.blogjava.net/liuzheng/articles/153013.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>分页通用技术</title><link>http://www.blogjava.net/liuzheng/articles/145904.html</link><dc:creator>刘铮 </dc:creator><author>刘铮 </author><pubDate>Mon, 17 Sep 2007 08:41:00 GMT</pubDate><guid>http://www.blogjava.net/liuzheng/articles/145904.html</guid><wfw:comment>http://www.blogjava.net/liuzheng/comments/145904.html</wfw:comment><comments>http://www.blogjava.net/liuzheng/articles/145904.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liuzheng/comments/commentRss/145904.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liuzheng/services/trackbacks/145904.html</trackback:ping><description><![CDATA[<span style="color: red">首先声明以下是转载的，感谢原作者</span><br />
<br />
<p><font face="verdana, arial, helvetica" size="2"><span class="javascript" id="text6288990" style="font-size: 12px">通用分页实现及其OO设计探讨<br />
<br />
本来是打算拿到it168投稿的！！那边的速度太慢了！先贴出来先！！<br />
<br />
分页是一种常用的页面数据显示技术，分页能够通过减少页面数据处理量从而提高了系统的性能。分页应该是做WEB开发必须掌握的一个小技术。而分页却是复杂的，倒不是它的技术有多复杂；而是有太多的重复代码，这些代码都难以重用。能不能实现一个通用的分页框架？每次只需要去覆写一两个方法，通过少量的代码就能实现分页的功能？<br />
<br />
一般分页应该要具有的功能有<br />
1. 灵活的设置分页大小。可以动态的设置分页大小，而不是写死到代码中。<br />
2. 自动计算总页数。根据分页大小和总记录数自动计算总页数。<br />
3. 获得当前页的页号。<br />
4. 获得当前页的总记录数。一般是最后一页的时候可能会小于分页大小。<br />
5. 判断当前页是否为第一页。<br />
6. 判断当前页是否为最后一页。<br />
7. 判断当前页是否有上一页。<br />
8. 判断当前页是否有下一页。<br />
9. 获得当前页的数据列表。<br />
10. 获得当前页的第一条记录的索引号<br />
11. 获得当前页的最后一条记录的索引号。<br />
二、常用的分页技术<br />
目前常用的分页技术有两种：<br />
1. 第一次访问是读取所有记录，放入session中，然后每次从session对象中读取当前页的数据<br />
2. 每次都访问数据库，从数据库中读取当前页的记录。<br />
这两种方法都各有优缺点，当数据量比较少时，第一种方法无疑是要快一些，因为减少与数据库的连接访问。而当数据量比较大时，比如查询结果可能会是上万条，那么内存的开销是十分大的，放到session中还有一个问题是能不能及时的清除无用的对象。而且这么大数据量在网络中传输也会使系统变得很慢。<br />
第二种方法就是专门解决这个问题的，它每次访问数据库，只读取当前页所需的记录，大大的减少网络传输量；它不会把页数据放到session中，大大提高服务器的性能。<br />
所以第二种方式要优于第一种方法。Session不要乱用，要用也仅仅是存放一些公共变量，相对于占用空间比较少的对象。不适合存放大量的数据，否则在很多个用户同时访问时那么系统会很慢，因为服务器内存被销耗的很厉害</span></font></p>
<p><font face="verdana, arial, helvetica" size="2"><span class="javascript" id="text6288997" style="font-size: 12px">三、通用分页框架需要解决的问题<br />
作为一个通用分页框架，<br />
1． 应该不依赖于任何其它框架<br />
2． 应该支持多种数据库<br />
3． 应该可以应用于任何web框架中，如：struts,spring等。<br />
4． 应该把数据访问的具体实现留给用户去实现。<br />
5． 应该实现关键的算法和过程，如：计算总页数，所需的实始化动作。<br />
6． 应该减化Contrller控制器的代码，以往的分页技术在Contrller中存在太多的if&#8230;else代码。十分难懂，应该由一个辅助类来实现。<br />
7． 应该减化jsp页面的代码，页面应该没有任何与分页相关的计算。应该由分页对象来实现。<br />
8． 应该支持两种分页方式，采用session或不采用session由用户控制。</span></font></p>
<p><font face="verdana, arial, helvetica" size="2"><span class="javascript" id="text6289006" style="font-size: 12px">四、具体实现<br />
1.通用分页接口。定义接口可以有更多不同的实现，接口只声明了分页应该具有的公共行为。<br />
ViewPage.java<br />
/**<br />
* 分页接口<br />
* @author ex_yuanguangdong<br />
*<br />
*/<br />
public interface ViewPage {<br />
<br />
<br />
<br />
/**<br />
* 获取总页数<br />
* @return 总页数<br />
*/<br />
public int getPageCount();<br />
<br />
<br />
/**<br />
* 获得页面大小<br />
* @return 页面大小<br />
*/<br />
public int getPageSize();<br />
<br />
<br />
/**<br />
* 设置页面大小<br />
* @param size<br />
*/<br />
public void setPageSize(int size);<br />
/**<br />
* 获得当前页数据<br />
* @return 数据列表<br />
*/<br />
public List getPageData();<br />
<br />
<br />
/**<br />
* 获得当前页索引号<br />
* @return 当前页索引号<br />
*/<br />
public int getPageIndex();<br />
<br />
/**<br />
* 获得当前页记录总数<br />
* @return 当前页记录总数<br />
*/<br />
public int getPageRows();<br />
<br />
/**<br />
* 是否有下一页<br />
* @return <br />
*/<br />
public boolean getHashNextPage();<br />
<br />
<br />
/**<br />
* 是否有上一页<br />
* @return<br />
*/<br />
public boolean getHashPreviousPage();<br />
<br />
/**<br />
* 转到尾页<br />
*<br />
*/<br />
public void gotoLastPage();<br />
/**<br />
* 转到首页<br />
*<br />
*/<br />
public void gotoFirstPage();<br />
<br />
/**<br />
* 是否首页<br />
* @return <br />
*/<br />
public boolean isFirstPage();<br />
<br />
/**<br />
* 是否尾页<br />
* @return<br />
*/<br />
public boolean isLastPage();<br />
<br />
/**<br />
* 转到上一页<br />
*<br />
*/<br />
public void gotoPreviousPage();<br />
<br />
/**<br />
* 转到下一页<br />
*<br />
*/<br />
public void gotoNextPage();<br />
<br />
/**<br />
* 转到指定页面,pageIndex小于1时，转到第一页;pageIndex大于总页数时，转到最尾页<br />
* @param pageIndex 指定的页号<br />
*/<br />
public void gotoPage(int pageIndex);<br />
<br />
/**<br />
* 获取当前页第一条记录的记录号<br />
* @return int 当前页第一条记录的记录号<br />
*/<br />
public int getPageFirstRecord();<br />
<br />
/**<br />
* 获取当前页最后一条记录的记录号<br />
* @return int 当前页最后一条记录的记录号<br />
*/<br />
public int getPageLastRecord();<br />
<br />
}</span></font></p>
<p><font face="verdana, arial, helvetica" size="2"><span class="javascript" id="text6289017" style="font-size: 12px">2． 分页抽像实现类，实现关键的算法<br />
AbstractViewPage.java<br />
/**<br />
* 分页默认抽象实现<br />
* 初始时，分页类有下列默认值：<br />
* 分页大小为-1,为不分页;<br />
* 总页数为1页<br />
* 当前页为第一页<br />
* 总记录数为0条<br />
* 当前页数据列表为没有任何记录的列表<br />
* @author ex_yuanguangdong<br />
*<br />
*/<br />
public abstract class AbstractViewPage implements ViewPage {<br />
<br />
//-----------------------------------------<br />
//私有静态常量<br />
//-----------------------------------------<br />
<br />
private static final int DEFAULT_PAGE_INDEX = 1;<br />
<br />
private static final int DEFALT_PAGE_COUNT = 1;<br />
<br />
private static final int DEFAULT_PAGE_SIZE = -1;<br />
<br />
private static final int DEFAULT_ROWS = 0;<br />
<br />
//-----------------------------------------<br />
//私有成员变量<br />
//-----------------------------------------<br />
<br />
/**当前页索引号**/<br />
private int pageIndex = DEFAULT_PAGE_INDEX;<br />
/**总页数**/<br />
private int pageCount =DEFALT_PAGE_COUNT;<br />
<br />
/**分页大小**/<br />
private int pageSize = DEFAULT_PAGE_SIZE ;<br />
<br />
/**数据总记录数**/<br />
private int rows = DEFAULT_ROWS;<br />
<br />
<br />
//------------------------------------------<br />
//本地成员变量getter,setter方法<br />
//------------------------------------------<br />
<br />
<br />
/**<br />
* 设置新页号，只有大于等于1而且小于等于总页数并且不为当前页时，才允许设置<br />
* @param pageIndex The pageIndex to set.<br />
*/<br />
private void setPageIndex(int newPageIndex) {<br />
<br />
if( newPageIndex &gt;= this.DEFAULT_PAGE_INDEX &amp;&amp; newPageIndex &lt;= this.getPageCount() &amp;&amp; newPageIndex != this.pageIndex) {<br />
this.pageIndex = newPageIndex;<br />
}<br />
<br />
}<br />
<br />
/**<br />
* @return Returns the rows.<br />
*/<br />
private int getRows() {<br />
return rows;<br />
}<br />
<br />
/**<br />
* @param rows The rows to set.<br />
*/<br />
private void setRows(int rows) {<br />
this.rows = rows;<br />
}<br />
/**<br />
* @param pageCount The pageCount to set.<br />
*/<br />
private void setPageCount(int pageCount) {<br />
this.pageCount = pageCount;<br />
}<br />
<br />
<br />
<br />
//--------------------------------------<br />
//实现Page接口方法<br />
//--------------------------------------<br />
<br />
<br />
/**<br />
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#getPageData()<br />
*/<br />
public List getPageData() {<br />
List pageList =null;<br />
<br />
//获得当前页数据 <br />
pageList = this.pageList(this.getPageFirstRecord(), this.getPageRows());<br />
//保证不返回null<br />
if(pageList == null) {<br />
pageList =new ArrayList();<br />
}<br />
return pageList;<br />
<br />
}<br />
<br />
/** <br />
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#getPageIndex()<br />
*/<br />
public int getPageIndex() {<br />
return this.pageIndex;<br />
}<br />
/**<br />
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#isFirstPage()<br />
*/<br />
public boolean isFirstPage() {<br />
<br />
return this.DEFAULT_PAGE_INDEX ==this.pageIndex;<br />
}<br />
/**<br />
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#isLastPage()<br />
*/<br />
public boolean isLastPage() {<br />
//当前页索引为总页数时为最后一页<br />
return this.pageIndex == this.pageCount;<br />
} <br />
<br />
/**<br />
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#getHashNextPage()<br />
*/<br />
public boolean getHashNextPage() {<br />
//当前页索引号小于总页数<br />
return this.pageIndex &lt; this.pageCount ;<br />
}<br />
<br />
/**<br />
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#getHashPreviousPage()<br />
*/<br />
public boolean getHashPreviousPage() {<br />
//当前页索引号大于默认的初始页号,这里为1<br />
return this.pageIndex &gt; this.DEFAULT_PAGE_INDEX ;<br />
}<br />
<br />
<br />
<br />
/**<br />
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#getPageCount()<br />
*/<br />
public int getPageCount() {<br />
<br />
return this.pageCount;<br />
}<br />
<br />
<br />
<br />
/**<br />
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#getPageSize()<br />
*/<br />
public int getPageSize() {<br />
<br />
return this.pageSize;<br />
}<br />
<br />
/**<br />
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#getPageRows()<br />
*/<br />
public int getPageRows() {<br />
//当页面大小为-1 时,返回总记录数<br />
if(this.DEFAULT_PAGE_SIZE == this.pageSize ) {<br />
return this.rows;<br />
}<br />
<br />
//不为最后一页时，返回pageSize<br />
if(!this.isLastPage()) {<br />
return this.pageSize;<br />
}<br />
//最后一页时<br />
return this.rows - (this.pageSize * (this.pageCount -1));<br />
}<br />
<br />
<br />
<br />
/**<br />
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#getPageFirstRecord()<br />
*/<br />
public int getPageFirstRecord() {<br />
<br />
//页大小为-1 时<br />
if(this.DEFAULT_PAGE_SIZE== this.pageSize ) {<br />
return 0;<br />
}<br />
return (this.pageIndex -1)* this.pageSize;<br />
}<br />
<br />
/**<br />
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#getPageLastRecord()<br />
*/<br />
public int getPageLastRecord() {<br />
//页大小为-1时,返回总记录数<br />
if(this.DEFAULT_PAGE_SIZE == this.pageSize) {<br />
return this.rows;<br />
}<br />
return this.getPageFirstRecord() + this.getPageRows() ;<br />
} <br />
/**<br />
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#gotoFirstPage()<br />
*/<br />
public void gotoFirstPage() {<br />
this.gotoPage(this.DEFAULT_PAGE_INDEX);<br />
<br />
}<br />
<br />
/**<br />
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#gotoLastPage()<br />
*/<br />
public void gotoLastPage() {<br />
this.gotoPage(this.getPageCount());<br />
<br />
}<br />
<br />
/**<br />
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#gotoPreviousPage()<br />
*/<br />
public void gotoPreviousPage() {<br />
this.gotoPage(this.getPageIndex() -1);<br />
<br />
} <br />
<br />
/**<br />
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#gotoNextPage()<br />
*/<br />
public void gotoNextPage() {<br />
this.gotoPage(this.getPageIndex() + 1);<br />
<br />
}<br />
<br />
/**<br />
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#gotoPage(int)<br />
*/<br />
public void gotoPage(int newPageIndex) {<br />
if( newPageIndex &gt;= this.DEFAULT_PAGE_INDEX &amp;&amp; newPageIndex &lt;= this.getPageCount() ) {<br />
this.setPageIndex(newPageIndex); <br />
}<br />
<br />
}<br />
/**<br />
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#setPageSize(int)<br />
*/<br />
public void setPageSize(int size) {<br />
if(size &lt; 1) {<br />
size = 1;<br />
}<br />
<br />
this.pageSize = size;<br />
<br />
//进行初始化<br />
this.doInit();<br />
}<br />
<br />
//-----------------------------------<br />
//辅助方法<br />
//-----------------------------------<br />
<br />
<br />
/**<br />
* 分页初始化方法,为了保证总是能正确的初始化，所以声明为final ,为了让子类可以调用声明为protected<br />
*<br />
*/<br />
protected final void doInit() {<br />
int rows = 0;<br />
<br />
//获得总记录数<br />
rows= totalRows();<br />
<br />
//设置总记录数<br />
this.setRows(rows);<br />
//设置新的总页数<br />
<br />
//计算并设置总页数<br />
int pages = calculatePageCount();<br />
this.setPageCount(pages);<br />
<br />
//转到第一页<br />
this.gotoPage(this.DEFAULT_PAGE_INDEX);<br />
<br />
onInit();<br />
}<br />
/**<br />
* 记算总页数<br />
* @return 总页数<br />
*/<br />
private int calculatePageCount() {<br />
<br />
//总记录数为0条，则返回的总页数为1<br />
if(this.getRows() == 0) {<br />
return this.DEFALT_PAGE_COUNT;<br />
}<br />
<br />
//如果页面大小为-1,则返回的总页数为1<br />
if(this.DEFAULT_PAGE_SIZE == this.getPageSize() ) {<br />
return this.DEFALT_PAGE_COUNT;<br />
}<br />
<br />
return this.getRows() / this.getPageSize() + ( this.getRows() % this.getPageSize() ==0 ? 0 :1);<br />
}<br />
<br />
<br />
/**<br />
* 获得总记录数，调用queryTotalRows(),将异常封装为non-checked 异常<br />
* @return 总记录数<br />
* @throws ApplicationRuntimeException<br />
*/<br />
private int totalRows() throws ApplicationRuntimeException{<br />
try{<br />
return queryTotalRows();<br />
}<br />
catch(Exception ex){<br />
throw new ApplicationRuntimeException(ex);<br />
}<br />
}<br />
/**<br />
* 获得当前页数据，调用queryPageList()方法，将异常封装为non-checked异常<br />
* @param startRow 开始记录号<br />
* @param rowCount 记录总数<br />
* @return 当前页数据<br />
* @throws ApplicationRuntimeException<br />
*/<br />
private List pageList(int startRow, int rowCount) throws ApplicationRuntimeException{<br />
try{<br />
return queryPageList(startRow, rowCount);<br />
}catch(Exception ex){<br />
throw new ApplicationRuntimeException(ex);<br />
}<br />
}<br />
<br />
<br />
//-----------------------------------------<br />
//子类实现的方法<br />
//-----------------------------------------<br />
<br />
/**<br />
* 初始化附加方法，由子类扩展<br />
*/<br />
protected void onInit() {<br />
<br />
}<br />
<br />
<br />
/**<br />
* 查询获得总记录数，由子类具体实现<br />
* @return 总记录数<br />
* @throws Exception<br />
*/<br />
protected abstract int queryTotalRows() throws Exception;<br />
<br />
/**<br />
* 查询当前页数据,从startRow 开始的rowCount条记录<br />
* @param startRow 开始记录号<br />
* @param rowCount 记录总数<br />
* @return 当前页数据<br />
* @throws Exception<br />
*/<br />
protected abstract List queryPageList(int startRow, int rowCount) throws Exception;<br />
<br />
}</span></font></p>
<p><font face="verdana, arial, helvetica" size="2"><span class="javascript" id="text6289039" style="font-size: 12px">3． 分页辅助类<br />
ViewPageHelper.java/**<br />
* 分页辅助类,用于减化Controller中的代码<br />
* @author yuanguangdong<br />
* date: Oct 22, 2006<br />
*/<br />
public class ViewPageHelper {<br />
private static final int FIRST_PAGE_VALUE = 1;<br />
<br />
private static final int PREVIOUS_PAGE_VALUE = 2;<br />
<br />
private static final int NEXT_PAGE_VALUE = 3;<br />
<br />
private static final int LAST_PAGE_VALUE = 4;<br />
<br />
private static final int SPECIAL_PAGE_VALUE = 5;<br />
<br />
public static final String FIRST_PAGE = "FIRST_PAGE";<br />
<br />
public static final String PREVIOUS_PAGE = "PREVIOUS_PAGE";<br />
<br />
public static final String NEXT_PAGE = "NEXT_PAGE";<br />
<br />
public static final String LAST_PAGE = "LAST_PAGE";<br />
<br />
public static final String SPECIAL_PAGE = "SPECIAL_PAGE";<br />
<br />
/**分页动作参数名**/<br />
public static final String PAGE_ACTION = "page_action";<br />
<br />
/**分页对象属性名**/<br />
public static final String SESSION_PAGE = "session_page";<br />
<br />
/**页号参数名**/<br />
public static final String PAGE_NO = "page_no";<br />
<br />
private static Map actionMap = new HashMap();<br />
static {<br />
actionMap.put(FIRST_PAGE, new Integer(FIRST_PAGE_VALUE));<br />
actionMap.put(PREVIOUS_PAGE, new Integer(PREVIOUS_PAGE_VALUE));<br />
actionMap.put(NEXT_PAGE, new Integer(NEXT_PAGE_VALUE));<br />
actionMap.put(LAST_PAGE, new Integer(LAST_PAGE_VALUE));<br />
actionMap.put(SPECIAL_PAGE, new Integer(SPECIAL_PAGE_VALUE));<br />
}<br />
/**<br />
* 执行分页动作<br />
* @param page 分页对象<br />
* @param action 分页动作参数<br />
* @param pageIndex 页号<br />
*/<br />
public static void doAction(ViewPage page, String action, int pageIndex) {<br />
int actionIndex = 0;<br />
if (page == null) {<br />
throw new NullPointerException("Page对象null");<br />
}<br />
if (action == null || "".equals(action)) {<br />
throw new IllegalArgumentException("无效的分页动作参数null");<br />
}<br />
action = action.toUpperCase();<br />
if (!actionMap.containsKey(action)) {<br />
throw new UnsupportedOperationException("不支持的分页动作参数:" + action);<br />
}<br />
Integer index = (Integer) actionMap.get(action);<br />
actionIndex = index.intValue();<br />
switch (actionIndex) {<br />
case FIRST_PAGE_VALUE:<br />
page.gotoFirstPage();<br />
break;<br />
case PREVIOUS_PAGE_VALUE:<br />
page.gotoPreviousPage();<br />
break;<br />
case NEXT_PAGE_VALUE:<br />
page.gotoNextPage();<br />
break;<br />
case LAST_PAGE_VALUE:<br />
page.gotoLastPage();<br />
break;<br />
case SPECIAL_PAGE_VALUE:<br />
page.gotoPage(pageIndex);<br />
}<br />
}<br />
<br />
public static void doAction(ViewPage page, String action){<br />
doAction(page, action, 1);<br />
}<br />
}</span></font></p>
<p><font face="verdana, arial, helvetica" size="2"><span class="javascript" id="text6289047" style="font-size: 12px">五、应用通用分页框架<br />
1．继承AbstractViewPage类，实现queryPageList(int startRow, int endRow)和<br />
queryTotalRows()方法。<br />
<br />
protected int queryTotalRows() throws Exception<br />
获得查询条件的总记录数<br />
<br />
protected List queryPageList(int startRow, int rowCount)<br />
用于查询指定范围的数据。startRow为开始记录号, rowCount为查询的记录数<br />
<br />
queryPageList(0,20)为查询从第一条开始的20条记录。<br />
<br />
使用Ibatis可以由queryPageList调用queryForList()方法。<br />
<br />
/**<br />
* 用户信息分页内部类<br />
* @author yuanguangdong<br />
* date: Oct 22, 2006<br />
*/<br />
class UserInfoPage extends AbstractViewPage{<br />
<br />
//------------------------------------------------<br />
//实现AbstractViewPage抽象类的抽象方法<br />
//------------------------------------------------<br />
<br />
/**<br />
* @see com.prs.application.ehld.web.mvc.AbstractViewPage#getPageDate(int, int)<br />
*/<br />
protected List queryPageList(int startRow, int endRow) throws Exception {<br />
return sampleAction.getUserInfoList(startRow, endRow);<br />
}<br />
<br />
/** <br />
* @see com.prs.application.ehld.web.mvc.AbstractViewPage#getRows()<br />
*/<br />
protected int queryTotalRows() throws Exception {<br />
return sampleAction.getUserCount();<br />
}<br />
<br />
}<br />
<br />
<br />
<br />
3. 在Contrller中的实现<br />
public ModelAndView listUser(HttpServletRequest request,<br />
HttpServletResponse response) throws Exception {<br />
String pageAction = <br />
RequestUtils.getStringParameter(request,ViewPageHelper.PAGE_ACTION);<br />
Integer pageIndex = <br />
RequestUtils.getIntParameter(request,ViewPageHelper.PAGE_NO);<br />
//声明分页对象<br />
ViewPage userPage =<br />
(ViewPage) request.getSession().getAttribute(ViewPageHelper.SESSION_PAGE);<br />
//第一次请求<br />
if(pageAction == null || userPage == null){<br />
//构建一个新的分页对象<br />
userPage = new UserInfoPage();<br />
//设置分页大小<br />
userPage.setPageSize(2);<br />
}else{<br />
<br />
if(ViewPageHelper.SPECIAL_PAGE.equals(pageAction)){<br />
//如果页数为空，则默认为1<br />
if (pageIndex == null)<br />
pageIndex = new Integer(1);<br />
ViewPageHelper.doAction(userPage,pageAction,pageIndex.intValue());<br />
}else{<br />
ViewPageHelper.doAction(userPage,pageAction);<br />
} <br />
}<br />
<br />
//从分页对象中获得当前页数据<br />
List userInfoList = userPage.getPageData();<br />
<br />
ModelAndView mav = new ModelAndView(userInfoListView); <br />
mav.addObject(this.userInfoListKey,userInfoList);<br />
request.getSession().setAttribute(ViewPageHelper.SESSION_PAGE,userPage);<br />
return mav;<br />
}</span></font></p>
<p><font face="verdana, arial, helvetica" size="2"><span class="javascript" id="text6289050" style="font-size: 12px">4. jsp页面实现<br />
<br />
&lt;%@ page contentType="text/html;charset=utf-8" language="java" %&gt;<br />
&lt;%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %&gt;<br />
&lt;%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt" %&gt;<br />
&lt;%@ taglib prefix="tiles" uri="http://jakarta.apache.org/struts/tags-tiles" %&gt;<br />
&lt;%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %&gt;<br />
&lt;html&gt;<br />
&lt;head&gt;<br />
&lt;title&gt;显示所有员工&lt;/title&gt;<br />
<br />
&lt;SCRIPT language="javaScript"&gt;<br />
function pageNoChange(pageNo){<br />
location.href= "ehld.sample.getuserinfolist.do?page_action=SPECIAL_PAGE&amp;page_no="+pageNo.value;<br />
<br />
}<br />
&lt;/SCRIPT&gt;<br />
&lt;/head&gt;<br />
<br />
&lt;body&gt;<br />
&lt;table width="80%" border="0"&gt;<br />
&lt;tr&gt;<br />
&lt;td bgcolor="#F0FEFF"&gt;&lt;div align="left"&gt;&nbsp; 用户列表&lt;/div&gt;&lt;/td&gt;<br />
&lt;/tr&gt;<br />
&lt;/table&gt;<br />
&lt;br&gt;<br />
&lt;input name="adduser" type="submit" id="adduser" value="新增用户" onclick="location.href='ehld.sample.edituserinfo.do'"&gt;<br />
&lt;table width="80%" border="0"&gt;<br />
&lt;tr bgcolor="#58ED64"&gt;<br />
&lt;th width="25%"&gt;id&lt;/th&gt;<br />
&lt;th width="34%"&gt;姓名&lt;/th&gt;<br />
&lt;th colspan="2"&gt;操作&lt;/th&gt;<br />
&lt;/tr&gt;<br />
&lt;c:forEach items="${userInfoList}" var="userInfoDTO"&gt; <br />
&lt;tr bgcolor="#D6EBF8"&gt;<br />
&lt;td&gt;&lt;c:out value="${userInfoDTO.userID}"/&gt;&lt;/td&gt;<br />
&lt;td&gt;&lt;c:out value="${userInfoDTO.userName}"/&gt;&lt;/td&gt;<br />
&lt;td width="21%"&gt;&lt;a href="ehld.sample.edituserinfo.do?id=&lt;c:out value='${userInfoDTO.userID}'/&gt;"&gt;编辑&lt;/a&gt;&lt;/td&gt;<br />
&lt;td width="20%"&gt;&lt;a href="#"&gt;删除&lt;/a&gt;&lt;/td&gt;<br />
&lt;/tr&gt;<br />
&lt;/c:forEach&gt;<br />
&lt;/table&gt;<br />
&lt;c:if test="${session_page.firstPage}"&gt;<br />
首页<br />
&lt;/c:if&gt;<br />
&lt;c:if test="${! session_page.firstPage}"&gt;<br />
&lt;a href="ehld.sample.getuserinfolist.do?page_action=FIRST_PAGE"&gt;首页&lt;/a&gt;<br />
&lt;/c:if&gt;<br />
&lt;c:if test="${! session_page.hashPreviousPage}"&gt;<br />
上一页<br />
&lt;/c:if&gt;<br />
&lt;c:if test="${session_page.hashPreviousPage}"&gt;<br />
&lt;a href="ehld.sample.getuserinfolist.do?page_action=PREVIOUS_PAGE"&gt;上一页&lt;/a&gt;<br />
&lt;/c:if&gt;<br />
<br />
&lt;c:if test="${!session_page.hashNextPage}"&gt;<br />
下一页<br />
&lt;/c:if&gt;<br />
<br />
&lt;c:if test="${session_page.hashNextPage}"&gt;<br />
&lt;a href="ehld.sample.getuserinfolist.do?page_action=NEXT_PAGE"&gt;下一页&lt;/a&gt;<br />
&lt;/c:if&gt;<br />
<br />
&lt;c:if test="${session_page.lastPage}"&gt;<br />
尾页<br />
&lt;/c:if&gt;<br />
<br />
&lt;c:if test="${!session_page.lastPage}"&gt;<br />
&lt;a href="ehld.sample.getuserinfolist.do?page_action=LAST_PAGE"&gt;尾页&lt;/a&gt;<br />
&lt;/c:if&gt;<br />
<br />
共有&lt;c:out value="${session_page.pageCount}" /&gt;页,第<br />
<br />
&lt;select name = "pageNo" onChange = "java script:pageNoChange(this);"&gt;<br />
&lt;c:forEach begin="1" end = "${session_page.pageCount}" var = "pageIndex"&gt;<br />
&lt;option value="&lt;c:out value='${pageIndex}'/&gt;" &lt;c:if test = "${pageIndex ==session_page.pageIndex }"&gt;selected&lt;/c:if&gt;&gt;<br />
&lt;c:out value="${pageIndex}"/&gt;<br />
&lt;/option&gt;<br />
&lt;/c:forEach&gt;<br />
&lt;/select&gt;<br />
页<br />
&lt;/body&gt;<br />
&lt;/html&gt;</span></font></p>
<p><font face="verdana, arial, helvetica" size="2"><span class="javascript" id="text6289119" style="font-size: 12px">六、设计探讨<br />
1．通过提供queryTotalRows() 和queryPageList(int startRow, int rowCount)方法，交由用户具体的去实现，所以能够支持任何数据库。<br />
对于Ibatis用户可以使用queryForList()方法,对于用jdbc实现也可以有多种方法来支持各种数据库。<br />
Ms sql 可以使用top 关键字，来获得指定范围的数据<br />
ORACEL可以使用rowid 伪列来获得指定范围的数据<br />
具体怎么去读取数据，完全交由用户控制<br />
2.分页对象与具体的业务对象分离。分页对象如果不能与具体的业务对象分离那么就不可能实现分页对象的重用，不可以实现代码的最大的重用。这不符合oo的按职责来设计对象的原则。<br />
3. ViewPageHelper帮助类的使用有两个好处，统一为分页代码所需的字符参数进行定义，便于contrller和jsp页面代码的维护。第二便于代码重用，减少在contrller中的if分支句语。如果不使用帮助类，则在每个controller中都会产生大量相同的代码。<br />
4. final关键字的使用，protected final void doInit()用于分页对象的实始化，它读取并设置总记录数，计算总页数，默认为第一页等。为什么不在构造函数中来做它呢？如果在构造函数来做它，子类就不可以扩展了。像这样的初始化方法的位置应该由扩展类来灵活控制。声明为protected是不让它由外部对象来进行访问，但是子类又可以进行调用。声明为final是为了子类不能重写它，如果子类重写不当就会造成分页对象的执行逻辑错误。但是如果子类又想扩展它怎么办？子类重写protected void onInit()方法就可以了。这样就能保证父类的逻辑，又能够让子类进行扩展。<br />
5.异常处理的思考，queryTotalRows()和queryPageList方法都是要求由子类实现的抽象类，这两个类的特点都是可能会调用业务对象去实现相应的功能，业务对象可能会访问业务数据库等，可能会抛出任何Exception，但是分页对象类去调用queryTotalRows()和queryPageList的方法是不应该对这些Exception进行任何处理的，如果进行try&#8230;catch那么就会隐藏了异常的细节，这是十分可怕的。如果这些方法抛出异常，分页对象应该是不能处理的，不能处理的异常应该封装为运行时异常，所以就有了下面的实现 <br />
private List pageList(int startRow, int rowCount) throws ApplicationRuntimeException{<br />
try{<br />
return queryPageList(startRow, rowCount);<br />
}catch(Exception ex){<br />
throw new ApplicationRuntimeException(ex);<br />
}<br />
}<br />
<br />
private int totalRows() throws ApplicationRuntimeException{<br />
try{<br />
return queryTotalRows();<br />
}<br />
catch(Exception ex){<br />
throw new ApplicationRuntimeException(ex);<br />
}<br />
}<br />
<br />
分页对象内部调用pageList和totalRows方法，这样就很好的解决了异常的问题，把异常交由外部调用者去决定是否处理，而不是强制调用者去处理。<br />
<br />
5. 模板方法模式的使用，这是一个典型的模板方法模式的运用。在父类实现关键的算法代码，实现分页对象的处理逻辑，而把某些会发生改变的方法交由子类去实现，使得子类完全不用去关心父类的实现细节，子类只需要重写两个简单的方法就可以实现父类的功能。这就是模板方法带来的最大好处。模板方法模式在各种开源框架中有着广泛的运用，看看spring的源码就知道。子类只需要去实现自己最关心的细节，而父类实现那些不变的逻辑或算法。<br />
6. 针对接口编程，而不是针对类编程。接口可以实现多重继承，而类却不能。接口有比类获得更多的好处，更利于扩展。比如说分页接口，它可以让用户有更多不同的实现，完全不依赖于任何类。只需要为它定制了共同的行为就可以了。在使用委托的时候接口比抽像类更好用。比如在装饰模式的使用中，可能需要实现一个接口，而其中还要有一个本接口的引用。 如果是抽象类，则不可以实现。<br />
7. 通用框架应该具有灵活性，不应该依懒于任何具体的框架。如果通用框架依懒于某一技术细节，某一框架，那么它就有一定的局限性。所以通用分页不应该依懒于ibatis或hibernate 或spring的某一特点。更不应该依懒于sql或oralce某种数据库。</span></font></p>
<img src ="http://www.blogjava.net/liuzheng/aggbug/145904.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liuzheng/" target="_blank">刘铮 </a> 2007-09-17 16:41 <a href="http://www.blogjava.net/liuzheng/articles/145904.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java中inputstream的有关类的设计模式-the decorator pattern</title><link>http://www.blogjava.net/liuzheng/articles/144443.html</link><dc:creator>刘铮 </dc:creator><author>刘铮 </author><pubDate>Wed, 12 Sep 2007 04:02:00 GMT</pubDate><guid>http://www.blogjava.net/liuzheng/articles/144443.html</guid><wfw:comment>http://www.blogjava.net/liuzheng/comments/144443.html</wfw:comment><comments>http://www.blogjava.net/liuzheng/articles/144443.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liuzheng/comments/commentRss/144443.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liuzheng/services/trackbacks/144443.html</trackback:ping><description><![CDATA[<p>java中inputstream的有关类的设计模式-the decorator pattern<br />
<br />
inputstream中比较重要的decorator----BufferedInputStream<br />
它的构造函数为<code><strong>BufferedInputStream</strong>(InputStream&nbsp;in)</code> <br />
或<code><strong>BufferedInputStream</strong>(InputStream&nbsp;in, int&nbsp;size)</code> <br />
<br />
<br />
可以装饰继承了inputsream类的类<br />
<br />
自己完成的新的inputstream<br />
public class LowerCaseInputStream extends FilterInputStream {<br />
public LowerCaseInputStream(InputStream in) {<br />
super(in);<br />
}<br />
public int read() throws IOException {<br />
int c = super.read();<br />
return (c == -1 ? c : Character.toLowerCase((char)c));<br />
}<br />
public int read(byte[] b, int offset, int len) throws IOException {<br />
int result = super.read(b, offset, len);<br />
for (int i = offset; i &lt; offset+result; i++) {<br />
b[i] = (byte)Character.toLowerCase((char)b[i]);<br />
}<br />
return result;<br />
}<br />
} <br />
<br />
<br />
FiterInputStream 便是一种特殊的类，他满足装饰器（decorator）的条件，<br />
1。必须继承需要decorator的类：InputStream<br />
2。在此类中必须包含需要decorator的类的实例，这样的话此类就拥有decorator的类的功能还能扩展其他功能。<br />
FiterInputStream 的原代码</p>
<p>/*<br />
&nbsp;* @(#)FilterInputStream.java&nbsp;1.28 03/12/19<br />
&nbsp;*<br />
&nbsp;* Copyright 2004 Sun Microsystems, Inc. All rights reserved.<br />
&nbsp;* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.<br />
&nbsp;*/</p>
<p>package java.io;</p>
<p>/**<br />
&nbsp;* A &lt;code&gt;FilterInputStream&lt;/code&gt; contains<br />
&nbsp;* some other input stream, which it uses as<br />
&nbsp;* its&nbsp; basic source of data, possibly transforming<br />
&nbsp;* the data along the way or providing&nbsp; additional<br />
&nbsp;* functionality. The class &lt;code&gt;FilterInputStream&lt;/code&gt;<br />
&nbsp;* itself simply overrides all&nbsp; methods of<br />
&nbsp;* &lt;code&gt;InputStream&lt;/code&gt; with versions that<br />
&nbsp;* pass all requests to the contained&nbsp; input<br />
&nbsp;* stream. Subclasses of &lt;code&gt;FilterInputStream&lt;/code&gt;<br />
&nbsp;* may further override some of&nbsp; these methods<br />
&nbsp;* and may also provide additional methods<br />
&nbsp;* and fields.<br />
&nbsp;*<br />
&nbsp;* @author&nbsp; Jonathan Payne<br />
&nbsp;* @version 1.28, 12/19/03<br />
&nbsp;* @since&nbsp;&nbsp; JDK1.0<br />
&nbsp;*/<br />
public<br />
class FilterInputStream <span style="color: red">extends InputStream </span>{<br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * The input stream to be filtered. <br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; <span style="color: red">protected volatile InputStream in;</span>&nbsp;&nbsp;&nbsp; <br />
/**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * Creates a &lt;code&gt;FilterInputStream&lt;/code&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; * by assigning the&nbsp; argument &lt;code&gt;in&lt;/code&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; * to the field &lt;code&gt;this.in&lt;/code&gt; so as<br />
&nbsp;&nbsp;&nbsp;&nbsp; * to remember it for later use.<br />
&nbsp;&nbsp;&nbsp;&nbsp; *<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @param&nbsp;&nbsp; in&nbsp;&nbsp; the underlying input stream, or &lt;code&gt;null&lt;/code&gt; if <br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this instance is to be created without an underlying stream.<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; protected FilterInputStream(InputStream in) {<br />
&nbsp;this.in = in;<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * Reads the next byte of data from this input stream. The value <br />
&nbsp;&nbsp;&nbsp;&nbsp; * byte is returned as an &lt;code&gt;int&lt;/code&gt; in the range <br />
&nbsp;&nbsp;&nbsp;&nbsp; * &lt;code&gt;0&lt;/code&gt; to &lt;code&gt;255&lt;/code&gt;. If no byte is available <br />
&nbsp;&nbsp;&nbsp;&nbsp; * because the end of the stream has been reached, the value <br />
&nbsp;&nbsp;&nbsp;&nbsp; * &lt;code&gt;-1&lt;/code&gt; is returned. This method blocks until input data <br />
&nbsp;&nbsp;&nbsp;&nbsp; * is available, the end of the stream is detected, or an exception <br />
&nbsp;&nbsp;&nbsp;&nbsp; * is thrown. <br />
&nbsp;&nbsp;&nbsp;&nbsp; * &lt;p&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; * This method<br />
&nbsp;&nbsp;&nbsp;&nbsp; * simply performs &lt;code&gt;in.read()&lt;/code&gt; and returns the result.<br />
&nbsp;&nbsp;&nbsp;&nbsp; *<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @return&nbsp;&nbsp;&nbsp;&nbsp; the next byte of data, or &lt;code&gt;-1&lt;/code&gt; if the end of the<br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; stream is reached.<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @exception&nbsp; IOException&nbsp; if an I/O error occurs.<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @see&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; java.io.FilterInputStream#in<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; public int read() throws IOException {<br />
&nbsp;return in.read();<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * Reads up to &lt;code&gt;byte.length&lt;/code&gt; bytes of data from this <br />
&nbsp;&nbsp;&nbsp;&nbsp; * input stream into an array of bytes. This method blocks until some <br />
&nbsp;&nbsp;&nbsp;&nbsp; * input is available. <br />
&nbsp;&nbsp;&nbsp;&nbsp; * &lt;p&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; * This method simply performs the call<br />
&nbsp;&nbsp;&nbsp;&nbsp; * &lt;code&gt;read(b, 0, b.length)&lt;/code&gt; and returns<br />
&nbsp;&nbsp;&nbsp;&nbsp; * the&nbsp; result. It is important that it does<br />
&nbsp;&nbsp;&nbsp;&nbsp; * &lt;i&gt;not&lt;/i&gt; do &lt;code&gt;in.read(b)&lt;/code&gt; instead;<br />
&nbsp;&nbsp;&nbsp;&nbsp; * certain subclasses of&nbsp; &lt;code&gt;FilterInputStream&lt;/code&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; * depend on the implementation strategy actually<br />
&nbsp;&nbsp;&nbsp;&nbsp; * used.<br />
&nbsp;&nbsp;&nbsp;&nbsp; *<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @param&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b&nbsp;&nbsp; the buffer into which the data is read.<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @return&nbsp;&nbsp;&nbsp;&nbsp; the total number of bytes read into the buffer, or<br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;code&gt;-1&lt;/code&gt; if there is no more data because the end of<br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; the stream has been reached.<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @exception&nbsp; IOException&nbsp; if an I/O error occurs.<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @see&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; java.io.FilterInputStream#read(byte[], int, int)<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; public int read(byte b[]) throws IOException {<br />
&nbsp;return read(b, 0, b.length);<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * Reads up to &lt;code&gt;len&lt;/code&gt; bytes of data from this input stream <br />
&nbsp;&nbsp;&nbsp;&nbsp; * into an array of bytes. This method blocks until some input is <br />
&nbsp;&nbsp;&nbsp;&nbsp; * available. <br />
&nbsp;&nbsp;&nbsp;&nbsp; * &lt;p&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; * This method simply performs &lt;code&gt;in.read(b, off, len)&lt;/code&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp; * and returns the result.<br />
&nbsp;&nbsp;&nbsp;&nbsp; *<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @param&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b&nbsp;&nbsp;&nbsp;&nbsp; the buffer into which the data is read.<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @param&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; off&nbsp;&nbsp; the start offset of the data.<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @param&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; len&nbsp;&nbsp; the maximum number of bytes read.<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @return&nbsp;&nbsp;&nbsp;&nbsp; the total number of bytes read into the buffer, or<br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;code&gt;-1&lt;/code&gt; if there is no more data because the end of<br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; the stream has been reached.<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @exception&nbsp; IOException&nbsp; if an I/O error occurs.<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @see&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; java.io.FilterInputStream#in<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; public int read(byte b[], int off, int len) throws IOException {<br />
&nbsp;return in.read(b, off, len);<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * Skips over and discards &lt;code&gt;n&lt;/code&gt; bytes of data from the <br />
&nbsp;&nbsp;&nbsp;&nbsp; * input stream. The &lt;code&gt;skip&lt;/code&gt; method may, for a variety of <br />
&nbsp;&nbsp;&nbsp;&nbsp; * reasons, end up skipping over some smaller number of bytes, <br />
&nbsp;&nbsp;&nbsp;&nbsp; * possibly &lt;code&gt;0&lt;/code&gt;. The actual number of bytes skipped is <br />
&nbsp;&nbsp;&nbsp;&nbsp; * returned. <br />
&nbsp;&nbsp;&nbsp;&nbsp; * &lt;p&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; * This method<br />
&nbsp;&nbsp;&nbsp;&nbsp; * simply performs &lt;code&gt;in.skip(n)&lt;/code&gt;.<br />
&nbsp;&nbsp;&nbsp;&nbsp; *<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @param&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; n&nbsp;&nbsp; the number of bytes to be skipped.<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @return&nbsp;&nbsp;&nbsp;&nbsp; the actual number of bytes skipped.<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @exception&nbsp; IOException&nbsp; if an I/O error occurs.<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; public long skip(long n) throws IOException {<br />
&nbsp;return in.skip(n);<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * Returns the number of bytes that can be read from this input <br />
&nbsp;&nbsp;&nbsp;&nbsp; * stream without blocking. <br />
&nbsp;&nbsp;&nbsp;&nbsp; * &lt;p&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; * This method<br />
&nbsp;&nbsp;&nbsp;&nbsp; * simply performs &lt;code&gt;in.available()&lt;/code&gt; and<br />
&nbsp;&nbsp;&nbsp;&nbsp; * returns the result.<br />
&nbsp;&nbsp;&nbsp;&nbsp; *<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @return&nbsp;&nbsp;&nbsp;&nbsp; the number of bytes that can be read from the input stream<br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; without blocking.<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @exception&nbsp; IOException&nbsp; if an I/O error occurs.<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @see&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; java.io.FilterInputStream#in<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; public int available() throws IOException {<br />
&nbsp;return in.available();<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * Closes this input stream and releases any system resources <br />
&nbsp;&nbsp;&nbsp;&nbsp; * associated with the stream. <br />
&nbsp;&nbsp;&nbsp;&nbsp; * This<br />
&nbsp;&nbsp;&nbsp;&nbsp; * method simply performs &lt;code&gt;in.close()&lt;/code&gt;.<br />
&nbsp;&nbsp;&nbsp;&nbsp; *<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @exception&nbsp; IOException&nbsp; if an I/O error occurs.<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @see&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; java.io.FilterInputStream#in<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; public void close() throws IOException {<br />
&nbsp;in.close();<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * Marks the current position in this input stream. A subsequent <br />
&nbsp;&nbsp;&nbsp;&nbsp; * call to the &lt;code&gt;reset&lt;/code&gt; method repositions this stream at <br />
&nbsp;&nbsp;&nbsp;&nbsp; * the last marked position so that subsequent reads re-read the same bytes.<br />
&nbsp;&nbsp;&nbsp;&nbsp; * &lt;p&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; * The &lt;code&gt;readlimit&lt;/code&gt; argument tells this input stream to <br />
&nbsp;&nbsp;&nbsp;&nbsp; * allow that many bytes to be read before the mark position gets <br />
&nbsp;&nbsp;&nbsp;&nbsp; * invalidated. <br />
&nbsp;&nbsp;&nbsp;&nbsp; * &lt;p&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; * This method simply performs &lt;code&gt;in.mark(readlimit)&lt;/code&gt;.<br />
&nbsp;&nbsp;&nbsp;&nbsp; *<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @param&nbsp;&nbsp; readlimit&nbsp;&nbsp; the maximum limit of bytes that can be read before<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; the mark position becomes invalid.<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @see&nbsp;&nbsp;&nbsp;&nbsp; java.io.FilterInputStream#in<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @see&nbsp;&nbsp;&nbsp;&nbsp; java.io.FilterInputStream#reset()<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; public synchronized void mark(int readlimit) {<br />
&nbsp;in.mark(readlimit);<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * Repositions this stream to the position at the time the <br />
&nbsp;&nbsp;&nbsp;&nbsp; * &lt;code&gt;mark&lt;/code&gt; method was last called on this input stream. <br />
&nbsp;&nbsp;&nbsp;&nbsp; * &lt;p&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; * This method<br />
&nbsp;&nbsp;&nbsp;&nbsp; * simply performs &lt;code&gt;in.reset()&lt;/code&gt;.<br />
&nbsp;&nbsp;&nbsp;&nbsp; * &lt;p&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; * Stream marks are intended to be used in<br />
&nbsp;&nbsp;&nbsp;&nbsp; * situations where you need to read ahead a little to see what's in<br />
&nbsp;&nbsp;&nbsp;&nbsp; * the stream. Often this is most easily done by invoking some<br />
&nbsp;&nbsp;&nbsp;&nbsp; * general parser. If the stream is of the type handled by the<br />
&nbsp;&nbsp;&nbsp;&nbsp; * parse, it just chugs along happily. If the stream is not of<br />
&nbsp;&nbsp;&nbsp;&nbsp; * that type, the parser should toss an exception when it fails.<br />
&nbsp;&nbsp;&nbsp;&nbsp; * If this happens within readlimit bytes, it allows the outer<br />
&nbsp;&nbsp;&nbsp;&nbsp; * code to reset the stream and try another parser.<br />
&nbsp;&nbsp;&nbsp;&nbsp; *<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @exception&nbsp; IOException&nbsp; if the stream has not been marked or if the<br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mark has been invalidated.<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @see&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; java.io.FilterInputStream#in<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @see&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; java.io.FilterInputStream#mark(int)<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; public synchronized void reset() throws IOException {<br />
&nbsp;in.reset();<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * Tests if this input stream supports the &lt;code&gt;mark&lt;/code&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp; * and &lt;code&gt;reset&lt;/code&gt; methods. <br />
&nbsp;&nbsp;&nbsp;&nbsp; * This method<br />
&nbsp;&nbsp;&nbsp;&nbsp; * simply performs &lt;code&gt;in.markSupported()&lt;/code&gt;.<br />
&nbsp;&nbsp;&nbsp;&nbsp; *<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @return&nbsp; &lt;code&gt;true&lt;/code&gt; if this stream type supports the<br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;code&gt;mark&lt;/code&gt; and &lt;code&gt;reset&lt;/code&gt; method;<br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;code&gt;false&lt;/code&gt; otherwise.<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @see&nbsp;&nbsp;&nbsp;&nbsp; java.io.FilterInputStream#in<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @see&nbsp;&nbsp;&nbsp;&nbsp; java.io.InputStream#mark(int)<br />
&nbsp;&nbsp;&nbsp;&nbsp; * @see&nbsp;&nbsp;&nbsp;&nbsp; java.io.InputStream#reset()<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; public boolean markSupported() {<br />
&nbsp;return in.markSupported();<br />
&nbsp;&nbsp;&nbsp; }<br />
}<br />
</p>
<img src ="http://www.blogjava.net/liuzheng/aggbug/144443.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liuzheng/" target="_blank">刘铮 </a> 2007-09-12 12:02 <a href="http://www.blogjava.net/liuzheng/articles/144443.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JNDI的简单概念&amp;简单示例</title><link>http://www.blogjava.net/liuzheng/articles/143902.html</link><dc:creator>刘铮 </dc:creator><author>刘铮 </author><pubDate>Mon, 10 Sep 2007 02:43:00 GMT</pubDate><guid>http://www.blogjava.net/liuzheng/articles/143902.html</guid><wfw:comment>http://www.blogjava.net/liuzheng/comments/143902.html</wfw:comment><comments>http://www.blogjava.net/liuzheng/articles/143902.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liuzheng/comments/commentRss/143902.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liuzheng/services/trackbacks/143902.html</trackback:ping><description><![CDATA[<p>介绍JNDI的简单概念&amp;简单示例。<br />
<p align="center"><strong>JNDI: The Java Naming and Directory Interface</strong></p>
<font color="#000080"><br />
</font>&nbsp;<strong>什么是JNDI</strong><strong>？<br />
</strong>
<p>The Java Naming and Directory Interface是访问不同名字和目录服务的统一API接口。</p>
<p>不同的服务使用不同的名字格式。</p>
<p>Java程序需要以相同的格式访问数据库，文件，目录，对象和网络。</p>
<p>JNID有两部分接口：应用程序接口和提供服务的接口。在应用程序中使用API来访问名字或目录服务，在一个新的服务中使用SPI来提供服务。</p>
<strong>JNDI</strong><strong>结构<br />
</strong>
<p>名字服务（Naming Services）</p>
<p>名字服务提供一种方法，映射标识符到实体或对象。</p>
<p>你需要知道的几条基本条款：</p>
<p><strong>绑定：</strong>绑定是将一个不可分割的名字（"原子"名字）与一个对象联系起来。像DNS，我们用名字<a href="http://www.yahoo.com/">www.yahoo.com</a>与IP地址216.32.74.53联系起来，一个文件对象用文件名afile.txt联系起来。</p>
<p><strong>名字空间；</strong>名字空间包含一组名字，但名字空间内每个名字是唯一的。一个文件目录就是一个简单的名字空间，如目录C:\temp，在这个目录下，不能有两个相同名字的文件，但是，不同目录下的两个文件可能有相同的名字。</p>
<p><strong>复合名字：</strong>复合名字是用名字空间构成的唯一名字，有一个或多个"原子"名字构成，取决于所在的名字空间。文件路径就是一个复合名字，比如我们用C:\temp\myfile.txt，我们可以看到，这个名字由根目录名（C:\），临时目录名（temp）和一个文件名（myfile.txt）构成，这3个名字复合起来表示一个唯一的名字。</p>
<p><strong>组合名字：</strong>组合名字能跨越多个名字空间。一个URL就是一个组合名字，如果你看见<a href="http://www.npu.edu/index.htm">http://www.npu.edu/index.htm</a>，你使用http服务连接到服务器，然后使用另一个名字空间/index.htm来访问一个文件。</p>
<p><strong>目录服务</strong></p>
<p>目录服务提供一组分成等级的目录对象，具有可搜索的能力。</p>
<p>在目录服务中存储的对象可以是任何能用一组属性描述的对象，每个对象都可通过一组属性来描述该对象的能力。例如，一个Person对象可能有height，hair color，age，sex等属性。目录服务还可提供根据要求来搜索的能力，如我们可以使用Person的age属性，搜索20-25岁间的Person对象，目录服务将返回符合条件的Persion对象。这通常被称作基于内容的搜索。</p>
<br />
<p>在客户端使用JNDI：</p>
<p>u&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 创建一个java.util.Hashtable或者java.util.Properties的实例。</p>
<p>u&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 添加变量到Hashtable或Properties对象：</p>
<p>由naming server提供的JNDI class类名。</p>
<p>包含aming server位置的URL。</p>
<p>安全信任书。</p>
<p>u&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 通过Hashtable或Properites或jndi属性文件创建一个InitialContext对象。</p>
<p>&nbsp;</p>
<strong>示例：<br />
</strong>import java.util.*;<br />
import javax.naming.*;<br />
...<br />
env.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");<br />
env.put(Context.PROVIDER_URL,"t3://localhost:7001");<br />
InitialContext ctx = new InitialContext(env);<br />
<table cellspacing="0" cellpadding="0" border="1">
    <tbody>
        <tr>
            <td valign="top" width="175">
            <p>环境变量</p>
            </td>
            <td valign="top" width="264">
            <p>相应的常量</p>
            </td>
            <td valign="top" width="120">
            <p>说明</p>
            </td>
        </tr>
        <tr>
            <td valign="top" width="175">
            <p>java.naming.factory.initial</p>
            </td>
            <td valign="top" width="264">
            <p>Context.INITIAL_CONTEXT_FACTORY</p>
            </td>
            <td valign="top" width="120">
            <p>Context Factory</p>
            <p>类名，由服务提供商给出。</p>
            </td>
        </tr>
        <tr>
            <td valign="top" width="175">
            <p>java.naming.provider.url</p>
            </td>
            <td valign="top" width="264">
            <p>Context.PROVIDE_URL</p>
            </td>
            <td valign="top" width="120">
            <p>初始化地址。</p>
            </td>
        </tr>
        <tr>
            <td valign="top" width="175">
            <p>java.naming.security.</p>
            <p>principal</p>
            </td>
            <td valign="top" width="264">
            <p>Context.SECURITY_PRINCIPAL</p>
            </td>
            <td valign="top" width="120">
            <p>服务使用者信息。</p>
            </td>
        </tr>
        <tr>
            <td valign="top" width="175">
            <p>java.naming.security.</p>
            <p>credentials</p>
            </td>
            <td valign="top" width="264">
            <p>Context.SECURITY_CREDENTIAL</p>
            </td>
            <td valign="top" width="120">
            <p>口令。</p>
            </td>
        </tr>
    </tbody>
</table>
<strong>更多的配置示例：<br />
</strong>Hashtable env = new Hashtable();<br />
env.put (Context.INITIAL_CONTEXT_FACTORY, <br />
"weblogic.jndi.WLInitialContextFactory");<br />
env.put(Context.PROVIDER_URL, "t3://localhost:7001");<br />
env.put(Context.SECURITY_PRINCIPAL, "system");<br />
env.put(Context.SECURITY_CREDENTIALS, "password here");<br />
Properties env = new Properties();<br />
env.setProperties ("java.naming.factory.initial", <br />
"weblogic.jndi.WLInitialContextFactory");<br />
env.setProperties("java.naming.provider.url" , "t3://localhost:7001");<br />
env.setProperties("java.naming.security.principal" , "tommy");<br />
env.setProperties("java.naming.security.credentials" ,"password here");<br />
<strong>创建InitialContext</strong><strong>：<br />
</strong>Class Name: javax.naming.InitialContext<br />
Interfaces that it implements: javax.naming.Context<br />
Constructors:<br />
&nbsp;&nbsp;&nbsp; public InitialContext();<br />
&nbsp;&nbsp;&nbsp; public InitialContext(Hashtable configuration);<br />
&nbsp;&nbsp;&nbsp; public InitialContext(Properties configuration);<br />
<p>以上所有方法都可能抛出NamingException。</p>
<strong>一个Binding</strong><strong>示例：<br />
</strong>public static InitialContext getInitialContext() throws NamingException {<br />
&nbsp;&nbsp;&nbsp; Hashtable env = new Hashtable();<br />
&nbsp;&nbsp;&nbsp; env.put(Context.INITIAL_CONTEXT_FACTORY,<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;"weblogic.jndi.WLInitialContextFactory");<br />
&nbsp;&nbsp;&nbsp; env.put(Context.PROVIDER_URL,"t3://localhost:7001");<br />
&nbsp;&nbsp;&nbsp; InitialContext context = new InitialContext(env);<br />
&nbsp;&nbsp;&nbsp; return context;<br />
}<br />
//Obtain the initial context<br />
InitialContext initialContext = getInitialContext();<br />
//Create a Bank object.<br />
Bank myBank = new Bank();<br />
//Bind the object into the JNDI tree.<br />
initialContext.rebind("theBank",myBank);<br />
<strong>一个Lookup</strong><strong>示例：<br />
</strong>public static InitialContext getInitialContext() throws NamingException {<br />
&nbsp;&nbsp;&nbsp; Hashtable env = new Hashtable();<br />
&nbsp;&nbsp;&nbsp; env.put(Context.INITIAL_CONTEXT_FACTORY,<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;"weblogic.jndi.WLInitialContextFactory");<br />
&nbsp;&nbsp;&nbsp; env.put(Context.PROVIDER_URL,"t3://localhost:7001");<br />
&nbsp;&nbsp;&nbsp; InitialContext context = new InitialContext(env);<br />
&nbsp;&nbsp;&nbsp; return context;<br />
}<br />
//Obtain the initial context<br />
InitialContext initialContext = getInitialContext();<br />
//Lookup an existing Bank object.<br />
<span>Bank myBank = (Bank) initialContext.lookup("theBank");<br />
</span><strong>可能发生的NamingException</strong><strong>：<br />
</strong>AuthenticationException<br />
CommunicationException<br />
InvalidNameException<br />
NameNotFoundException<br />
NoInitialContextException<br />
<strong>枚举所有名字对象：<br />
</strong>NamingEnumeration Declaration:<br />
public interface NamingEnumeration extends Enumeration {<br />
&nbsp;&nbsp;&nbsp; public boolean hashMore() throws NamingException;<br />
&nbsp;&nbsp;&nbsp; public Object next() throws NamingException;<br />
&nbsp;&nbsp;&nbsp; public void close() throws NamingException; //jndi 1.2<br />
}<br />
try {<br />
&nbsp;&nbsp;&nbsp; ...<br />
&nbsp;&nbsp;&nbsp; NamingEnumeration enum = ctx.list("");<br />
&nbsp;&nbsp;&nbsp; while (enum.hasMore()) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NameClassPair ncp = (NameClassPair) enum.next();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("JNDI name is:" + ncp.getName());<br />
&nbsp;&nbsp;&nbsp; }<br />
}<br />
catch (NamingException e) {...}<br />
<strong>最后的示例：<br />
</strong>import java.util.*;<br />
import javax.naming.*;<br />
import javax.naming.directory.*;<br />
import java.io.*;<br />
public class ListAll {<br />
&nbsp;&nbsp;&nbsp; public static void main(java.lang.String[] args) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Hashtable env = new Hashtable();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; env.put(Context.INITIAL_CONTEXT_FACTORY,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "weblogic.jndi.WLInitialContextFactory");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; env.put(Context.PROVIDER_URL, "t3://localhost:7001");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; InitialContext ctx = new InitialContext(env);<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; NamingEnumeration enum = ctx.listBindings("");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; while(enum.hasMore()) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Binding binding = (Binding) enum.next();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Object obj = (Object) binding.getObject();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(obj);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (NamingException e) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(e);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; } // end main<br />
<p>} </p>
<img src ="http://www.blogjava.net/liuzheng/aggbug/143902.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liuzheng/" target="_blank">刘铮 </a> 2007-09-10 10:43 <a href="http://www.blogjava.net/liuzheng/articles/143902.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JAVA动态代理学习心得</title><link>http://www.blogjava.net/liuzheng/articles/143197.html</link><dc:creator>刘铮 </dc:creator><author>刘铮 </author><pubDate>Thu, 06 Sep 2007 08:18:00 GMT</pubDate><guid>http://www.blogjava.net/liuzheng/articles/143197.html</guid><wfw:comment>http://www.blogjava.net/liuzheng/comments/143197.html</wfw:comment><comments>http://www.blogjava.net/liuzheng/articles/143197.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liuzheng/comments/commentRss/143197.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liuzheng/services/trackbacks/143197.html</trackback:ping><description><![CDATA[&nbsp;
<p class="MsoNormal"><span lang="EN-US" style="font-size: 14pt">JAVA</span><span style="font-size: 14pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">动态代理学习心得</span><span lang="EN-US" style="font-size: 14pt"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 21pt; text-indent: -21pt; mso-list: l0 level1 lfo1; tab-stops: list 21.0pt"><span lang="EN-US" style="font-size: 14pt; mso-fareast-font-family: 'Times New Roman'"><span style="mso-list: Ignore">1.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-size: 14pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">所有的额外新添加的方法要放到</span><span lang="EN-US" style="font-size: 14pt">InvocationHandler</span><span style="font-size: 14pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的实现类中</span><span lang="EN-US" style="font-size: 14pt"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 21pt; text-indent: -21pt; mso-list: l0 level1 lfo1; tab-stops: list 21.0pt"><span lang="EN-US" style="font-size: 14pt; mso-fareast-font-family: 'Times New Roman'"><span style="mso-list: Ignore">2.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span lang="EN-US" style="font-size: 14pt">Proxy</span><span style="font-size: 14pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">类都与</span><span lang="EN-US" style="font-size: 14pt">InvocationHandler</span><span style="font-size: 14pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">相联系的，也就是说</span><span lang="EN-US" style="font-size: 14pt">Proxy</span><span style="font-size: 14pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">类的中的方法调用都会被重新分配到实例的</span><span lang="EN-US" style="font-size: 14pt">InvoctionHandler</span><span style="font-size: 14pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">中的</span><span lang="EN-US" style="font-size: 14pt">invoke</span><span style="font-size: 14pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法中，传递了</span><span lang="EN-US" style="font-size: 14pt">reflect</span><span style="font-size: 14pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">中的</span><span lang="EN-US" style="font-size: 14pt">method</span><span style="font-size: 14pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">类</span><span lang="EN-US" style="font-size: 14pt"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 21pt; text-indent: -21pt; mso-list: l0 level1 lfo1; tab-stops: list 21.0pt"><span lang="EN-US" style="font-size: 14pt; mso-fareast-font-family: 'Times New Roman'"><span style="mso-list: Ignore">3.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-size: 14pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">创建</span><span lang="EN-US" style="font-size: 14pt">Java</span><span style="font-size: 14pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">动态代理类的步骤：</span><span lang="EN-US" style="font-size: 14pt"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 42pt; text-indent: -21pt; mso-list: l0 level2 lfo1; tab-stops: list 42.0pt"><span lang="EN-US" style="font-size: 14pt; mso-fareast-font-family: 'Times New Roman'"><span style="mso-list: Ignore">a)<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-size: 14pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">实现</span><span lang="EN-US" style="font-size: 14pt">InvocationHandler</span><span style="font-size: 14pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">接口</span><span lang="EN-US" style="font-size: 14pt"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 42pt; text-indent: -21pt; mso-list: l0 level2 lfo1; tab-stops: list 42.0pt"><span lang="EN-US" style="font-size: 14pt; mso-fareast-font-family: 'Times New Roman'"><span style="mso-list: Ignore">b)<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-size: 14pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">通过</span><span lang="EN-US" style="font-size: 14pt">Proxy.newProxyInstance</span><span style="font-size: 14pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">得到一个</span><span lang="EN-US" style="font-size: 14pt">Proxy</span><span style="font-size: 14pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">类的实例</span><span lang="EN-US" style="font-size: 14pt"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 21pt"><span style="font-size: 14pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">一般的写法如下：</span><span lang="EN-US" style="font-size: 14pt"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 21pt"><span>public class XXXHandler implements InvocationHandler {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 21pt"><span>private Object originalObject;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 21pt"><span>public Object bind(Object obj) {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 21pt"><span>this.originalObject = obj;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 21pt"><span>return Proxy.newProxyInstance(<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 21pt"><span lang="EN-US" style="font-size: 14pt">obj.getClass().getClassLoader(),<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 21pt"><span lang="EN-US" style="font-size: 14pt">obj.getClass().getInterfaces(),<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 21pt"><span lang="EN-US" style="font-size: 14pt">this)<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 21pt"><span lang="EN-US" style="font-size: 14pt">}<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 21pt"><span>public Object invoke(Object proxy, Method method, Object[] args)<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 21pt"><span>throws Throwable {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 21pt"><span lang="EN-US" style="font-size: 14pt">method.invoke(originalObject, args);<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 21pt"><span lang="EN-US" style="font-size: 14pt">}<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left: 21pt; text-indent: -21pt; mso-list: l0 level1 lfo1; tab-stops: list 21.0pt"><span lang="EN-US" style="font-size: 14pt; mso-fareast-font-family: 'Times New Roman'"><span style="mso-list: Ignore">4.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-size: 14pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">这样调用</span><span lang="EN-US" style="font-size: 14pt">XXXHandler</span><span style="font-size: 14pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">：代理目标的接口类</span><span lang="EN-US" style="font-size: 14pt">= XXXHandler</span><span style="font-size: 14pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的实例</span><span lang="EN-US" style="font-size: 14pt">.bind(</span><span style="font-size: 14pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">代理目标的实现类</span><span lang="EN-US" style="font-size: 14pt">)<o:p></o:p></span></p>
<img src ="http://www.blogjava.net/liuzheng/aggbug/143197.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liuzheng/" target="_blank">刘铮 </a> 2007-09-06 16:18 <a href="http://www.blogjava.net/liuzheng/articles/143197.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JAVA  学习目标和资料</title><link>http://www.blogjava.net/liuzheng/articles/139100.html</link><dc:creator>刘铮 </dc:creator><author>刘铮 </author><pubDate>Fri, 24 Aug 2007 06:48:00 GMT</pubDate><guid>http://www.blogjava.net/liuzheng/articles/139100.html</guid><wfw:comment>http://www.blogjava.net/liuzheng/comments/139100.html</wfw:comment><comments>http://www.blogjava.net/liuzheng/articles/139100.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liuzheng/comments/commentRss/139100.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liuzheng/services/trackbacks/139100.html</trackback:ping><description><![CDATA[<strong>本文将告诉你学习Java需要达到的30个目标，希望能够对你的学习有所帮助。对比一下自己，你已经掌握了这30条中的多少条了呢？ <br><br><!---->　　1.你需要精通面向对象分析与设计(OOA/OOD)、涉及模式(GOF，J2EEDP)以及综合模式。你应该十分了解UML，尤其是class，object，interaction以及statediagrams。<br><br><!---->　　2.你需要学习JAVA语言的基础知识以及它的核心类库(collections，serialization，streams，networking， multithreading，reflection，event，handling，NIO，localization，以及其他)。<br><br><!---->　　3.你应该了解JVM，classloaders，classreflect，以及垃圾回收的基本工作机制等。你应该有能力反编译一个类文件并且明白一些基本的汇编指令。<br><br><!---->　　4.如果你将要写客户端程序，你需要学习WEB的小应用程序(applet)，必需掌握GUI设计的思想和方法，以及桌面程序的SWING，AWT， SWT。你还应该对UI部件的JAVABEAN组件模式有所了解。JAVABEANS也被应用在JSP中以把业务逻辑从表现层中分离出来。<br><br><!---->　　5.你需要学习java数据库技术，如JDBCAPI并且会使用至少一种persistence/ORM构架，例如Hibernate，JDO， CocoBase，TopLink，InsideLiberator(国产JDO红工厂软件)或者iBatis。<br>　　6.你还应该了解对象关系的阻抗失配的含义，以及它是如何影响业务对象的与关系型数据库的交互，和它的运行结果，还需要掌握不同的数据库产品运用，比如:oracle，mysql，mssqlserver。<br><br><!---->　　7.你需要学习JAVA的沙盒安全模式(classloaders，bytecodeverification，managers，policyandpermissions，<br>codesigning， digitalsignatures，cryptography，certification，Kerberos，以及其他)还有不同的安全/认证 API，例如JAAS(JavaAuthenticationandAuthorizationService)，JCE (JavaCryptographyExtension)，JSSE(JavaSecureSocketExtension)，以及JGSS (JavaGeneralSecurityService)。<br><br><!---->　　8.你需要学习Servlets，JSP，以及JSTL(StandardTagLibraries)和可以选择的第三方TagLibraries。<br><br><!---->　　9.你需要熟悉主流的网页框架，例如JSF，Struts，Tapestry，Cocoon，WebWork，以及他们下面的涉及模式，如MVC/MODEL2。<br><br><!---->　　10.你需要学习如何使用及管理WEB服务器，例如tomcat，resin，Jrun，并且知道如何在其基础上扩展和维护WEB程序。<br><br><!---->　　11.你需要学习分布式对象以及远程API，例如RMI和RMI/IIOP。<br><br><!---->　　12.你需要掌握各种流行中间件技术标准和与java结合实现，比如Tuxedo、CROBA，当然也包括javaEE本身。<br><br><!---->　　13.你需要学习最少一种的XMLAPI，例如JAXP(JavaAPIforXMLProcessing)，JDOM(JavaforXMLDocumentObjectModel)，DOM4J，或JAXR(JavaAPIforXMLRegistries)。<br><br><!---->　　14.你应该学习如何利用JAVAAPI和工具来构建WebService。例如JAX-RPC(JavaAPIforXML/RPC)，SAAJ (SOAPwithAttachmentsAPIforJava)，JAXB(JavaArchitectureforXMLBinding)，JAXM(JavaAPIforXMLMessaging)， JAXR(JavaAPIforXMLRegistries)，或者JWSDP(JavaWebServicesDeveloperPack)。<br><br><!---->　　15.你需要学习一门轻量级应用程序框架，例如Spring，PicoContainer，Avalon，以及它们的IoC/DI风格(setter，constructor，interfaceinjection)。<br><br><!---->　　16.你需要熟悉不同的J2EE技术，例如JNDI(JavaNamingandDirectoryInterface)，JMS (JavaMessageService)，JTA/JTS(JavaTransactionAPI/JavaTransactionService)，JMX (JavaManagementeXtensions)，以及JavaMail。<br><br><!---->　　17.你需要学习企业级JavaBeans(EJB)以及它们的不同组件模式：Stateless/StatefulSessionBeans，EntityBeans(包含Bean- ManagedPersistence[BMP]或者Container-ManagedPersistence[CMP]和它的EJB-QL)，或者 Message-DrivenBeans(MDB)。<br><br><!---->　　18.你需要学习如何管理与配置一个J2EE应用程序服务器，如WebLogic，JBoss等，并且利用它的附加服务，例如簇类，连接池以及分布式处理支援。你还需要了解如何在它上面封装和配置应用程序并且能够监控、调整它的性能。<br><br><!---->　　19.你需要熟悉面向方面的程序设计以及面向属性的程序设计(这两个都被很容易混淆的缩写为AOP)，以及他们的主流JAVA规格和执行。例如AspectJ和AspectWerkz。<br><br><!---->　　20.你需要熟悉对不同有用的API和frame work等来为你服务。例如Log4J(logging/tracing)，Quartz (scheduling)，JGroups(networkgroupcommunication)，JCache(distributedcaching)， Lucene(full-textsearch)，JakartaCommons等等。<br><br><!---->　　21.如果你将要对接或者正和旧的系统或者本地平台，你需要学习JNI (JavaNativeInterface) and JCA (JavaConnectorArchitecture)。<br><br><!---->　　22.你需要熟悉JINI技术以及与它相关的分布式系统，比如掌握CROBA。<br><br><!---->　　23.你需要JavaCommunityProcess(JCP)以及他的不同JavaSpecificationRequests(JSRs)，例如Portlets(168)，JOLAP(69)，DataMiningAPI(73)，等等。<br><br><!---->　　24.你应该熟练掌握一种JAVAIDE例如sunOne，netBeans，IntelliJIDEA或者Eclipse。(有些人更喜欢VI或EMACS来编写文件。随便你用什么了：)<br><br><!---->　　25.JAVA(精确的说是有些配置)是冗长的，它需要很多的人工代码(例如EJB)，所以你需要熟悉代码生成工具，例如XDoclet。<br><br><!---->　　26.你需要熟悉一种单元测试体系(JNunit)，并且学习不同的生成、部署工具(Ant，Maven)。<br><br><!---->　　27.你需要熟悉一些在JAVA开发中经常用到的软件工程过程。例如RUP(RationalUnifiedProcess)andAgilemethodologies。<br><br><!---->　　28.你需要能够深入了解加熟练操作和配置不同的操作系统，比如GNU/linux，sunsolaris，macOS等，做为跨平台软件的开发者。<br><br><!---->　　29.你还需要紧跟java发展的步伐，比如现在可以深入的学习javaME，以及各种java新规范，技术的运用，如新起的web富客户端技术。<br><br><!---->　　30.你必需要对opensource有所了解，因为至少java的很多技术直接是靠开源来驱动发展的，如java3D技术。</strong>
<p class=postfoot>posted @ <a title=permalink href="http://www.blogjava.net/topquan/archive/2007/07/07/128783.html"><font color=#0000ff>2007-07-07 15:46</font></a> topquan 阅读(80) | <a title="comments, pingbacks, trackbacks" href="http://www.blogjava.net/topquan/archive/2007/07/07/128783.html#FeedBack"><font color=#0000ff>评论 (0)</font></a> |&nbsp;<a href="http://www.blogjava.net/topquan/admin/EditPosts.aspx?postid=128783"><font color=#0000ff>编辑</font></a>&nbsp;<a href="http://www.blogjava.net/topquan/AddToFavorite.aspx?id=128783"><font color=#0000ff>收藏</font></a> </p>
<div class=post>
<h2><a id=_2db2653f9f3e_HomePageDays_ctl00_DayList_ctl01_TitleUrl href="http://www.blogjava.net/topquan/archive/2006/08/05/61890.html"><font color=#0000ff>My Favorite Java Site</font></a></h2>
<p>1.<a href="http://www.theserverside.com/"><font color=#366900>TheServerside.com</font></a>&nbsp; 依然是地位无可动摇的CCTV1。</p>
<p>2.<a href="http://www.infoq.com/"><font color=#366900>InfoQ.com</font></a> Floyd Marinescu 在离开 TSS 后另起炉灶，2006年中最重要推荐。视野不再局限于Java 而是包括Java,.Net, Ruby ,SOA, Agile方法等热门话题。</p>
<p>3.<a href="http://java.sys-con.com/"><font color=#366900>JDJ的电子杂志</font></a>&nbsp;在JDJ首页的最底处订阅，文章质量不低于5-7的传统三强。</p>
<p>4.<a href="http://www.swik.net/"><font color=#366900>SWik.net</font></a>&nbsp; 收集了大量OpenSource Project的资源聚合。其中如Spring，Hibernate的更新度非常高，出现什么和Spring有关的blog,article,project都会马上被聚合。</p>
<p>5.<a href="http://www-128.ibm.com/developerworks/java/"><font color=#366900>IBM DeveloperWorks</font></a>&nbsp;传统、稳定的Java文章来源地。</p>
<p>6.<a href="http://www.javaworld.com/"><font color=#366900>JavaWorld</font></a> 传统、稳定的Java文章来源地。</p>
<p>7.<a href="http://www.onjava.com/"><font color=#366900>OnJava</font></a>&nbsp; 传统、稳定的Java文章来源地。</p>
<p>8.<a href="http://artima.com/"><font color=#366900>Artima.com</font></a>&nbsp;类似于TSS而略逊，其中<a href="http://www.artima.com/spotlight/"><font color=#366900>Spotlight </font></a>文章值得关注，而<a href="http://www.artima.com/news/community.jsp?forum=136"><font color=#366900>Java News</font></a>是聚合了所有其他Java站点的大聚合。</p>
<p>9.<a href="http://www.javalobby.org/"><font color=#366900>JavaLobby</font></a>&nbsp; 站内的<a href="http://www.javalobby.org/forumRSS/17.xml"><font color=#366900>Announcements</font></a>&nbsp;是大大小小Java&nbsp; Project的发布声明区，<a href="http://www.javalobby.org/forumRSS/18032.xml"><font color=#366900>Trips and Tricks</font></a>&nbsp;有很多的Tips。</p>
<p>10. <a href="http://www.nofluffjuststuff.com/blogs_summary.jsp"><font color=#366900>No Fluff Just Stuff 的Blogs 聚合</font></a> 一直缺一个所有优秀Java Blogger的rss总聚合，NFJS这里勉强算一个。<br><br>11.&nbsp;<a title=JBOSS官方网 style="COLOR: #003300" href="http://www.jboss.com/">JBOSS 官方网站</a> JBOSS被RedHat收购后，在各方面都有所加强，出现了高质量的产品</p>
</div>
<img src ="http://www.blogjava.net/liuzheng/aggbug/139100.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liuzheng/" target="_blank">刘铮 </a> 2007-08-24 14:48 <a href="http://www.blogjava.net/liuzheng/articles/139100.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>