蜜臀久久99精品久久一区二区 ,91精品国产乱码,国产精品伦一区二区三级视频http://www.aygfsteel.com/liuzheng/category/25219.htmlzh-cnWed, 02 Apr 2008 14:18:04 GMTWed, 02 Apr 2008 14:18:04 GMT60Date 和 Calender 的轉(zhuǎn)化http://www.aygfsteel.com/liuzheng/articles/190386.html劉錚 劉錚 Wed, 02 Apr 2008 07:40:00 GMThttp://www.aygfsteel.com/liuzheng/articles/190386.htmlhttp://www.aygfsteel.com/liuzheng/comments/190386.htmlhttp://www.aygfsteel.com/liuzheng/articles/190386.html#Feedback0http://www.aygfsteel.com/liuzheng/comments/commentRss/190386.htmlhttp://www.aygfsteel.com/liuzheng/services/trackbacks/190386.html  1.計算某一月份的最大天數(shù)

Calendar time=Calendar.getInstance();
time.clear();
time.set(Calendar.YEAR,year); //year 為 int
time.set(Calendar.MONTH,i-1);//注意,Calendar對象默認一月為0
int day=time.getActualMaximum(Calendar.DAY_OF_MONTH);//本月份的天數(shù)
注:在使用set方法之前,必須先clear一下,否則很多信息會繼承自系統(tǒng)當前時間

2.Calendar和Date的轉(zhuǎn)化

(1) Calendar轉(zhuǎn)化為Date
Calendar cal=Calendar.getInstance();
Date date=cal.getTime();

(2) Date轉(zhuǎn)化為Calendar
Date date=new Date();
Calendar cal=Calendar.getInstance();
cal.setTime(date);

3.格式化輸出日期時間 (這個用的比較多)

Date date=new Date();
SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String time=df.format(date);
System.out.println(time);

4.計算一年中的第幾星期

(1)計算某一天是一年中的第幾星期
Calendar cal=Calendar.getInstance();
cal.set(Calendar.YEAR, 2006);
cal.set(Calendar.MONTH, 8);
cal.set(Calendar.DAY_OF_MONTH, 3);
int weekno=cal.get(Calendar.WEEK_OF_YEAR);

(2)計算一年中的第幾星期是幾號
SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd");
Calendar cal=Calendar.getInstance();
cal.set(Calendar.YEAR, 2006);
cal.set(Calendar.WEEK_OF_YEAR, 1);
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
System.out.println(df.format(cal.getTime()));
輸出:
2006-01-02

5.add()和roll()的用法(不太常用)

(1)add()方法
SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd");
Calendar cal=Calendar.getInstance();
cal.set(Calendar.YEAR, 2006);
cal.set(Calendar.MONTH, 8);
cal.set(Calendar.DAY_OF_MONTH, 3);
cal.add(Calendar.DATE, -4);
Date date=cal.getTime();
System.out.println(df.format(date));
cal.add(Calendar.DATE, 4);
date=cal.getTime();
System.out.println(df.format(date));
輸出:
2006-08-30
2006-09-03
(2)roll方法
cal.set(Calendar.YEAR, 2006);
cal.set(Calendar.MONTH, 8);
cal.set(Calendar.DAY_OF_MONTH, 3);
cal.roll(Calendar.DATE, -4);
date=cal.getTime();
System.out.println(df.format(date));
cal.roll(Calendar.DATE, 4);
date=cal.getTime();
System.out.println(df.format(date));
輸出:
2006-09-29
2006-09-03
可見,roll()方法在本月內(nèi)循環(huán),一般使用add()方法;

6.計算兩個任意時間中間的間隔天數(shù)(這個比較常用)
(1)傳進Calendar對象
public int getIntervalDays(Calendar startday,Calendar endday)...{
if(startday.after(endday))...{
Calendar cal=startday;
startday=endday;
endday=cal;
}
long sl=startday.getTimeInMillis();
long el=endday.getTimeInMillis();

long ei=el-sl;
return (int)(ei/(1000*60*60*24));
}
(2)傳進Date對象

public int getIntervalDays(Date startday,Date endday)...{
if(startday.after(endday))...{
Date cal=startday;
startday=endday;
endday=cal;
}
long sl=startday.getTime();
long el=endday.getTime();
long ei=el-sl;
return (int)(ei/(1000*60*60*24));
}
(3)改進精確計算相隔天數(shù)的方法
public int getDaysBetween (Calendar d1, Calendar d2) ...{
if (d1.after(d2)) ...{
java.util.Calendar swap = d1;
d1 = d2;
d2 = swap;
}
int days = d2.get(Calendar.DAY_OF_YEAR) - d1.get(Calendar.DAY_OF_YEAR);
int y2 = d2.get(Calendar.YEAR);
if (d1.get(Calendar.YEAR) != y2) ...{
d1 = (Calendar) d1.clone();
do ...{
days += d1.getActualMaximum(Calendar.DAY_OF_YEAR);//得到當年的實際天數(shù)
d1.add(Calendar.YEAR, 1);
} while (d1.get(Calendar.YEAR) != y2);
}
return days;
}
注意:通過上面的方法可以衍生出求任何時間,如要查出郵箱三周之內(nèi)收到的郵件(得到當前系統(tǒng)時間-再得到三周前時間)用收件的時間去匹配 最好裝化成 long去比較
如:1年前日期(注意毫秒的轉(zhuǎn)換)
java.util.Date myDate=new java.util.Date();
long myTime=(myDate.getTime()/1000)-60*60*24*365;
myDate.setTime(myTime*1000);
String mDate=formatter.format(myDate);

7. String 和 Date ,Long 之間相互轉(zhuǎn)換 (最常用)

字符串轉(zhuǎn)化成時間類型(字符串可以是任意類型,只要和SimpleDateFormat中的格式一致即可)
通常我們?nèi)r間跨度的時候,會substring出具體時間--long-比較

java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("M/dd/yyyy hh:mm:ss a",java.util.Locale.US);
java.util.Date d = sdf.parse("5/13/2003 10:31:37 AM");
long dvalue=d.getTime();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String mDateTime1=formatter.format(d);

8. 通過時間求時間

年月周求日期
SimpleDateFormat formatter2 = new SimpleDateFormat("yyyy-MM F E");
java.util.Date date2= formatter2.parse("2003-05 5 星期五");
SimpleDateFormat formatter3 = new SimpleDateFormat("yyyy-MM-dd");
String mydate2=formatter3.format(date2);

求是星期幾
mydate= myFormatter.parse("2001-1-1");
SimpleDateFormat formatter4 = new SimpleDateFormat("E");
String mydate3=formatter4.format(mydate);

9. java 和 具體的數(shù)據(jù)庫結(jié)合

在開發(fā)web應用中,針對不同的數(shù)據(jù)庫日期類型,我們需要在我們的程序中對日期類型做各種不同的轉(zhuǎn)換。若對應數(shù)據(jù)庫數(shù)據(jù)是oracle的Date類型,即只需要年月日的,可以選擇使用java.sql.Date類型,若對應的是MSsqlserver 數(shù)據(jù)庫的DateTime類型,即需要年月日時分秒的,選擇java.sql.Timestamp類型
你可以使用dateFormat定義時間日期的格式,轉(zhuǎn)一個字符串即可

class Datetest{
*method 將字符串類型的日期轉(zhuǎn)換為一個timestamp(時間戳記java.sql.Timestamp)
*@param dateString 需要轉(zhuǎn)換為timestamp的字符串
*@return dataTime timestamp

public final static java.sql.Timestamp string2Time(String dateString)
throws java.text.ParseException {
DateFormat dateFormat;
dateFormat = new SimpleDateFormat("yyyy-MM-dd kk:mm:ss.SSS", Locale.ENGLISH);//設(shè)定格式
//dateFormat = new SimpleDateFormat("yyyy-MM-dd kk:mm:ss", Locale.ENGLISH);
dateFormat.setLenient(false);
java.util.Date timeDate = dateFormat.parse(dateString);//util類型
java.sql.Timestamp dateTime = new java.sql.Timestamp(timeDate.getTime());//Timestamp類型,timeDate.getTime()返回一個long型
return dateTime;
}

*method 將字符串類型的日期轉(zhuǎn)換為一個Date(java.sql.Date
*@param dateString 需要轉(zhuǎn)換為Date的字符串
*@return dataTime Date

public final static java.sql.Date string2Date(String dateString)
throws java.lang.Exception {
DateFormat dateFormat;
dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH);
dateFormat.setLenient(false);
java.util.Date timeDate = dateFormat.parse(dateString);//util類型
java.sql.Date dateTime = new java.sql.Date(timeDate.getTime());//sql類型
return dateTime;
}

public static void main(String[] args){
Date da = new Date();
注意:這個地方da.getTime()得到的是一個long型的值
System.out.println(da.getTime());

由日期date轉(zhuǎn)換為timestamp

第一種方法:使用new Timestamp(long)
Timestamp t = new Timestamp(new Date().getTime());
System.out.println(t);

第二種方法:使用Timestamp(int year,int month,int date,int hour,int minute,int second,int nano)
Timestamp tt = new Timestamp(Calendar.getInstance().get(
Calendar.YEAR) - 1900, Calendar.getInstance().get(
Calendar.MONTH), Calendar.getInstance().get(
Calendar.DATE), Calendar.getInstance().get(
Calendar.HOUR), Calendar.getInstance().get(
Calendar.MINUTE), Calendar.getInstance().get(
Calendar.SECOND), 0);
System.out.println(tt);

try {
String sToDate = "2005-8-18";//用于轉(zhuǎn)換成java.sql.Date的字符串
String sToTimestamp = "2005-8-18 14:21:12.123";//用于轉(zhuǎn)換成java.sql.Timestamp的字符串
Date date1 = string2Date(sToDate);
Timestamp date2 = string2Time(sToTimestamp);
System.out.println("Date:"+date1.toString());//結(jié)果顯示
System.out.println("Timestamp:"+date2.toString());//結(jié)果顯示
}catch(Exception e) {
e.printStackTrace();
}
}
}

劉錚 2008-04-02 15:40 發(fā)表評論
]]>
Jakarta Commons HttpClient 學習筆記(轉(zhuǎn))http://www.aygfsteel.com/liuzheng/articles/180506.html劉錚 劉錚 Mon, 18 Feb 2008 09:49:00 GMThttp://www.aygfsteel.com/liuzheng/articles/180506.htmlhttp://www.aygfsteel.com/liuzheng/comments/180506.htmlhttp://www.aygfsteel.com/liuzheng/articles/180506.html#Feedback0http://www.aygfsteel.com/liuzheng/comments/commentRss/180506.htmlhttp://www.aygfsteel.com/liuzheng/services/trackbacks/180506.html1、HttpClient的功能

  1. 基于標準,純正java,實現(xiàn)了http1.0和1.1。
  2. 在一個可擴展的OO框架內(nèi),實現(xiàn)了HTTP的全部方法(GET, POST,
    PUT, DELETE, HEAD, OPTIONS, and TRACE)
  3. 支持HTTPS(ssl上的HTTP)的加密操作
  4. 透明地穿過HTTP代理建立連接
  5. 通過CONNECT方法,利用通過建立穿過HTTP代理的HTTPS連接
  6. 利用本地Java socket,透明地穿過SOCKS(版本5和4)代理建立連接
  7. 支持利用Basic、Digest和NTLM加密的認證
  8. 支持用于上傳大文件的Multi-Part表單POST方法
  9. 插件式安全socket實現(xiàn),易于使用第三方的解決方案
  10. 連接管理,支持多線程應用,支持設(shè)定單個主機總連接和最高連接數(shù)量,自動檢測和關(guān)閉失效連接
  11. 直接將請求信息流送到服務(wù)器的端口
  12. 直接讀取從服務(wù)器的端口送出的應答信息
  13. 支持HTTP/1.0中用KeepAlive和HTTP/1.1中用persistance設(shè)置的持久連接
  14. 直接訪問由服務(wù)器送出的應答代碼和頭部信息
  15. 可設(shè)置連接超時時間

  16. HttpMethods 實現(xiàn)Command Pattern,以允許并行請求或高效連接復用
  17. 遵循the Apache Software License協(xié)議,源碼免費可得

2、預備工作


  對jre1.3.*,如果要HttpClient支持https,則需要下載并安裝java.sun.com/products/jsse/">jsse和java.sun.com/products/jce/">jce.安裝的步驟如下:
1)下載jsse和jce.
2)檢查CLASSPATH中沒有與jsse和jce相關(guān)的jar包
3)將 US_export_policy.jar、local_policy.jar、jsse.jar、jnet.jar、jce1_2_x.jar、sunjce_provider.jar、jcert.jar復制到目錄:
UNIX:$JDK_HOME/jre/lib/ext
Windows:%JDK_HOME%\jre\lib\ext
4)修改下述目錄下的java.security文件
UNIX:$JDK_HOME/jre/lib/security/
Windows:%JDK_HOME%\jre\lib\security\
5)

#
# List of providers and their preference orders:
#
security.provider.1=sun.security.provider.Sun
security.provider.2=com.sun.rsajca.Provider
改為:
#
# List of providers and their preference orders:
#
security.provider.1=com.sun.crypto.provider.SunJCE
security.provider.2=sun.security.provider.Sun
security.provider.3=com.sun.rsajca.Provider
security.provider.4=com.sun.net.ssl.internal.ssl.Provider

  HttpClient還要求安裝commons-logging,下面跟httpclient一塊安裝。

3、取得源碼


cvs -d :pserver:anoncvs@cvs.apache.org:/home/cvspublic login
password: anoncvs
cvs -d :pserver:anoncvs@cvs.apache.org:/home/cvspublic checkout jakarta-commons/logging
cvs -d :pserver:anoncvs@cvs.apache.org:/home/cvspublic checkout jakarta-commons/httpclient

  編譯:
cd jakarta-commons/logging
ant dist
cp dis/*.jar ../httpclient/lib/
cd ../httpclient
ant dist

4、使用HttpClient編程的基本步聚


  1. 創(chuàng)建 HttpClient 的一個實例.
  2. 創(chuàng)建某個方法(DeleteMethod,EntityEnclosingMethod,ExpectContinueMethod,GetMethod,HeadMethod,MultipartPostMethod,OptionsMethod,PostMethod,PutMethod,TraceMethod)的一個實例,一般可用要目標URL為參數(shù)。
  3. 讓 HttpClient 執(zhí)行這個方法.
  4. 讀取應答信息.
  5. 釋放連接.
  6. 處理應答.

  在執(zhí)行方法的過程中,有兩種異常,一種是HttpRecoverableException,表示偶然性錯誤發(fā)生,一般再試可能成功,另一種是IOException,嚴重錯誤。
  這兒有這個教程中的一個例程,可以java">下載。

5、認證


  HttpClient三種不同的認證方案: Basic, Digest and NTLM. 這些方案可用于服務(wù)器或代理對客戶端的認證,簡稱服務(wù)器認證或代理認證
1)服務(wù)器認證(Server Authentication)
  HttpClient處理服務(wù)器認證幾乎是透明的,僅需要開發(fā)人員提供登錄信息(login credentials)。登錄信息保存在HttpState類的實例中,可以通過 setCredentials(String realm, Credentials cred)和getCredentials(String realm)來獲取或設(shè)置。注意,設(shè)定對非特定站點訪問所需要的登錄信息,將realm參數(shù)置為null. HttpClient內(nèi)建的自動認證,可以通過HttpMethod類的setDoAuthentication(boolean doAuthentication)方法關(guān)閉,而且這次關(guān)閉只影響HttpMethod當前的實例。
  搶先認證(Preemptive Authentication)可以通過下述方法打開.
client.getState().setAuthenticationPreemptive(true);
  在這種模式時,HttpClient會主動將basic認證應答信息傳給服務(wù)器,即使在某種情況下服務(wù)器可能返回認證失敗的應答,這樣做主要是為了減少連接的建立。為使每個新建的 HttpState實例都實行搶先認證,可以如下設(shè)置系統(tǒng)屬性。
setSystemProperty(Authenticator.PREEMPTIVE_PROPERTY, "true");

Httpclient實現(xiàn)的搶先認證遵循rfc2617.
2)代理認證(proxy authentication)
  除了登錄信息需單獨存放以外,代理認證服務(wù)器認證幾乎一致。用 setProxyCredentials(String realm, Credentials cred)和 getProxyCredentials(String realm)設(shè)、取登錄信息。
3)認證方案(authentication schemes)
  Basic
  是HTTP中規(guī)定最早的也是最兼容(?)的方案,遺憾的是也是最不安全的一個方案,因為它以明碼傳送用戶名和密碼。它要求一個UsernamePasswordCredentials實例,可以指定服務(wù)器端的訪問空間或采用默認的登錄信息。
  Digest
  是在HTTP1.1中增加的一個方案,雖然不如Basic得到的軟件支持多,但還是有廣泛的使用。Digest方案比Basic方案安全得多,因它根本就不通過網(wǎng)絡(luò)傳送實際的密碼,傳送的是利用這個密碼對從服務(wù)器傳來的一個隨機數(shù)(nonce)的加密串。它要求一個UsernamePasswordCredentials實例,可以指定服務(wù)器端的訪問空間或采用默認的登錄信息。
  NTLM
  這是HttpClient支持的最復雜的認證協(xié)議。它M$設(shè)計的一個私有協(xié)議,沒有公開的規(guī)范說明。一開始由于設(shè)計的缺陷,NTLM的安全性比Digest差,后來經(jīng)過一個ServicePack補丁后,安全性則比較Digest高。NTLM需要一個NTCredentials實例. 注意,由于NTLM不使用訪問空間(realms)的概念,HttpClient利用服務(wù)器的域名作訪問空間的名字。還需要注意,提供給NTCredentials的用戶名,不要用域名的前綴 - 如: "adrian" 是正確的,而 "DOMAIN\adrian" 則是錯的.
  NTLM認證的工作機制與basic和digest有很大的差別。這些差別一般由HttpClient處理,但理解這些差別有助避免在使用NTLM認證時出現(xiàn)錯誤。
  1. 從HttpClientAPI的角度來看,NTLM與其它認證方式一樣的工作,差別是需要提供'NTCredentials'實例而不是'UsernamePasswordCredentials'(其實,前者只是擴展了后者)
  2. 對NTLM認證,訪問空間是連接到的機器的域名,這對多域名主機會有一些麻煩.只有HttpClient連接中指定的域名才是認證用的域名。建議將realm設(shè)為null以使用默認的設(shè)置。
  3. NTLM只是認證了一個連接而不是一請求,所以每當一個新的連接建立就要進行一次認證,且在認證的過程中保持連接是非常重要的。 因此,NTLM不能同時用于代理認證服務(wù)器認證,也不能用于http1.0連接或服務(wù)器不支持持久連接的情況。

6、重定向


  由于技術(shù)限制,以及為保證2.0發(fā)布版API的穩(wěn)定,HttpClient還不能自動處重定向,但對重定向到同一主機、同一端口且采用同一協(xié)議的情況HttpClient可以支持。不能自動的處理的情況,包括需要人工交互的情況,或超出httpclient的能力。
  當服務(wù)器重定向指令指到不同的主機時,HttpClient只是簡單地將重定向狀態(tài)碼作為應答狀態(tài)。所有的300到399(包含兩端)的返回碼,都表示是重定向應答。常見的有:
  1. 301 永久移動. HttpStatus.SC_MOVED_PERMANENTLY
  2. 302 臨時移動. HttpStatus.SC_MOVED_TEMPORARILY
  3. 303 See Other. HttpStatus.SC_SEE_OTHER
  4. 307 臨時重定向. HttpStatus.SC_TEMPORARY_REDIRECT

  當收到簡單的重定向時,程序應從HttpMethod對象中抽取新的URL并將其下載。另外,限制一下重定向次數(shù)是個好的主意,這可以避免遞歸循環(huán)。新的URL可以從頭字段Location中抽取,如下:
String redirectLocation;
Header locationHeader = method.getResponseHeader("location");
if (locationHeader != null) {
redirectLocation = locationHeader.getValue();
} else {
// The response is invalid and did not provide the new location for
// the resource. Report an error or possibly handle the response
// like a 404 Not Found error.
}

特殊重定向:
  1. 300 多重選擇. HttpStatus.SC_MULTIPLE_CHOICES
  2. 304 沒有改動. HttpStatus.SC_NO T_MODIFIED
  3. 305 使用代理. HttpStatus.SC_USE_PROXY
  

7、字符編碼(character encoding)


  一個HTTP協(xié)議的請求或應答的頭部(在http協(xié)議中,數(shù)據(jù)包分為兩部分,一部分是頭部,由一些名值對構(gòu)成,一部分是主體(body),是真正傳辦理的數(shù)據(jù)(如HTML頁面等)),必須以US-ASCII編碼,這是因為頭部不傳數(shù)據(jù)而只描述被要傳輸?shù)臄?shù)據(jù)的一些信息,一個例外是cookie,它是數(shù)據(jù)但是通過頭部進行傳輸?shù)模运惨肬S-ASCII編碼。
  HTTP數(shù)據(jù)包的主體部分,可以用任何一種方式進行編碼,默認是ISO-8859-1,具體可以用頭部字段Content-Type指定。可以利用 addRequestHeader方法,設(shè)定編碼方式;用 getResponseCharSet取得編碼方式。對HTML或XML等類型的文檔,它們的本身的Content-Type也可以指定編碼方式,主要區(qū)分兩者的作用范圍以得到正確實的解碼。
  URL的編碼標準,由RFC1738指定為,只能是由可打印8位/字節(jié)的us-ascii字符組成,80-ff不是us-ascii字符,而00-1F是控制字符,這兩個區(qū)域中用的字符都須加以編碼(encoded)。
  

8、Cookies


   HttpClient能自動管理cookie,包括允許服務(wù)器設(shè)置cookie并在需要的時候自動將cookie返回服務(wù)器,它也支持手工設(shè)置cookie后發(fā)送到服務(wù)器端。不幸的是,對如何處理cookie,有幾個規(guī)范互相沖突:Netscape Cookie 草案, RFC2109, RFC2965,而且還有很大數(shù)量的軟件商的cookie實現(xiàn)不遵循任何規(guī)范. 為了處理這種狀況,HttpClient提供了策略驅(qū)動的cookie管理方式。HttpClient支持的cookie規(guī)范有:
  1. Netscape cookie草案,是最早的cookie規(guī)范,基于rfc2109。盡管這個規(guī)范與rc2109有較大的差別,這樣做可以與一些服務(wù)器兼容。
  2. rfc2109,是w3c發(fā)布的第一個官方cookie規(guī)范。理論上講,所有的服務(wù)器在處理cookie(版本1)時,都要遵循此規(guī)范,正因如此,HttpClient將其設(shè)為默認的規(guī)范。遺憾的是,這個規(guī)范太嚴格了,以致很多服務(wù)器不正確的實施了該規(guī)范或仍在作用Netscape規(guī)范。在這種情況下,應使用兼容規(guī)范。
  3. 兼容性規(guī)范,設(shè)計用來兼容盡可能多的服務(wù)器,即使它們并沒有遵循標準規(guī)范。當解析cookie出現(xiàn)問題時,應考慮采用兼容性規(guī)范。

   RFC2965規(guī)范暫時沒有被HttpClient支持(在以后的版本為會加上),它定義了cookie版本2,并說明了版本1cookie的不足,RFC2965有意有久取代rfc2109.
  在HttpClient中,有兩種方法來指定cookie規(guī)范的使用,
  1. HttpClient client = new HttpClient();
    client.getState().setCookiePolicy(CookiePolicy.COMPATIBILITY);
    這種方法設(shè)置的規(guī)范只對當前的HttpState有效,參數(shù)可取值CookiePolicy.COMPATIBILITY,CookiePolicy.NETSCAPE_DRAFT或CookiePolicy.RFC2109。
  2. System.setProperty("apache.commons.httpclient.cookiespec", "COMPATIBILITY");
    此法指的規(guī)范,對以后每個新建立的HttpState對象都有效,參數(shù)可取值"COMPATIBILITY","NETSCAPE_DRAFT"或"RFC2109"。
      常有不能解析cookie的問題,但更換到兼容規(guī)范大都能解決。
  

9、使用HttpClient遇到問題怎么辦?


  1. 用一個瀏覽器訪問服務(wù)器,以確認服務(wù)器應答正常
  2. 如果在使代理,關(guān)掉代理試試
  3. 另找一個服務(wù)器來試試(如果運行著不同的服務(wù)器軟件更好)
  4. 檢查代碼是否按教程中講的思路編寫
  5. 設(shè)置log級別為debug,找出問題出現(xiàn)的原因
  6. 打開wiretrace,來追蹤客戶端與服務(wù)器的通信,以確實問題出現(xiàn)在什么地方
  7. 用telnet或netcat手工將信息發(fā)送到服務(wù)器,適合于猜測已經(jīng)找到了原因而進行試驗時
  8. 將netcat以監(jiān)聽方式運行,用作服務(wù)器以檢查httpclient如何處理應答的。
  9. 利用最新的httpclient試試,bug可能在最新的版本中修復了
  10. 向郵件列表求幫助
  11. 向bugzilla報告bug.
  

10、SSL


  借助Java Secure Socket Extension (JSSE),HttpClient全面支持Secure Sockets Layer (SSL)或IETF Transport Layer Security (TLS)協(xié)議上的HTTP。JSSE已經(jīng)jre1.4及以后的版本中,以前的版本則需要手工安裝設(shè)置,具體過程參見java.sun.com/products/jsse/doc/guide/API_users_guide.html#Installation">Sun網(wǎng)站或本學習筆記。
  HttpClient中使用SSL非常簡單,參考下面兩個例子:
HttpClient httpclient = new HttpClient();
GetMethod httpget = new GetMethod("https://www.verisign.com/");
httpclient.executeMethod(httpget);
System.out.println(httpget.getStatusLine().toString());
,如果通過需要授權(quán)的代理,則如下:
HttpClient httpclient = new HttpClient();
httpclient.getHostConfiguration().setProxy("myproxyhost", 8080);
httpclient.getState().setProxyCredentials("my-proxy-realm", " myproxyhost",
new UsernamePasswordCredentials("my-proxy-username", "my-proxy-password"));
GetMethod httpget = new GetMethod("https://www.verisign.com/");
httpclient.executeMethod(httpget);
System.out.println(httpget.getStatusLine().toString());

  在HttpClient中定制SSL的步驟如下:
  1. 提供了一個實現(xiàn)了org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory接口的socket factory。這個 socket factory負責打一個到服務(wù)器的端口,使用標準的或第三方的SSL函數(shù)庫,并進行象連接握手等初始化操作。通常情況下,這個初始化操作在端口被創(chuàng)建時自動進行的。
  2. 實例化一個org.apache.commons.httpclient.protocol.Protocol對象。創(chuàng)建這個實例時,需要一個合法的協(xié)議類型(如https),一個定制的socket factory,和一個默認的端中號(如https的443端口).
    Protocol myhttps = new Protocol("https", new MySSLSocketFactory(), 443);
    然后,這個實例可被設(shè)置為協(xié)議的處理器。
    HttpClient httpclient = new HttpClient();
    httpclient.getHostConfiguration().setHost("www.whatever.com", 443, myhttps);
    GetMethod httpget = new GetMethod("/");
    httpclient.executeMethod(httpget);

  3. 通過調(diào)用Protocol.registerProtocol方法,將此定制的實例,注冊為某一特定協(xié)議的默認的處理器。由此,可以很方便地定制自己的協(xié)議類型(如myhttps)。
    Protocol.registerProtocol("myhttps",
    new Protocol("https", new MySSLSocketFactory(), 9443));
    ...
    HttpClient httpclient = new HttpClient();
    GetMethod httpget = new GetMethod("myhttps://www.whatever.com/");
    httpclient.executeMethod(httpget);
    如果想用自己定制的處理器取代https默認的處理器,只需要將其注冊為"https"即可。
    Protocol.registerProtocol("https",
    new Protocol("https", new MySSLSocketFactory(), 443));
    HttpClient httpclient = new HttpClient();
    GetMethod httpget = new GetMethod("https://www.whatever.com/");
    httpclient.executeMethod(httpget);

  已知的限制和問題
  1. 持續(xù)的SSL連接在Sun的低于1.4JVM上不能工作,這是由于JVM的bug造成。
  2. 通過代理訪問服務(wù)器時,非搶先認證( Non-preemptive authentication)會失敗,這是由于HttpClient的設(shè)計缺陷造成的,以后的版本中會修改。

  遇到問題的處理
  很多問題,特別是在jvm低于1.4時,是由jsse的安裝造成的。
  下面的代碼,可作為最終的檢測手段。
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.Socket; import javax.net.ssl.SSLSocketFactory; public class Test {

public static final String TARGET_HTTPS_SERVER = "www.verisign.com";
public static final int TARGET_HTTPS_PORT = 443;

public static void main(String[] args) throws Exception {

Socket socket = SSLSocketFactory.getDefault().
createSocket(TARGET_HTTPS_SERVER, TARGET_HTTPS_PORT);
try {
Writer out = new OutputStreamWriter(
socket.getOutputStream(), "ISO-8859-1");
out.write("GET / HTTP/1.1\r\n");
out.write("Host: " + TARGET_HTTPS_SERVER + ":" +
TARGET_HTTPS_PORT + "\r\n");
out.write("Agent: SSL-TEST\r\n");
out.write("\r\n");
out.flush();
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream(), "ISO-8859-1"));
String line = null;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
} finally {
socket.close();
}
}
}

  

11、httpclient的多線程處理


  使用多線程的主要目的,是為了實現(xiàn)并行的下載。在httpclient運行的過程中,每個http協(xié)議的方法,使用一個HttpConnection實例。由于連接是一種有限的資源,每個連接在某一時刻只能供一個線程和方法使用,所以需要確保在需要時正確地分配連接。HttpClient采用了一種類似jdbc連接池的方法來管理連接,這個管理工作由 MultiThreadedHttpConnectionManager完成。
MultiThreadedHttpConnectionManager connectionManager =
new MultiThreadedHttpConnectionManager();
HttpClient client = new HttpClient(connectionManager);
此是,client可以在多個線程中被用來執(zhí)行多個方法。每次調(diào)用HttpClient.executeMethod() 方法,都會去鏈接管理器申請一個連接實例,申請成功這個鏈接實例被簽出(checkout),隨之在鏈接使用完后必須歸還管理器。管理器支持兩個設(shè)置:
maxConnectionsPerHost 每個主機的最大并行鏈接數(shù),默認為2
maxTotalConnections 客戶端總并行鏈接最大數(shù),默認為20

  管理器重新利用鏈接時,采取早歸還者先重用的方式(least recently used approach)。
  由于是使用HttpClient的程序而不是HttpClient本身來讀取應答包的主體,所以HttpClient無法決定什么時間連接不再使用了,這也就要求在讀完應答包的主體后必須手工顯式地調(diào)用releaseConnection()來釋放申請的鏈接。
MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
HttpClient client = new HttpClient(connectionManager);
...
// 在某個線程中。
GetMethod get = new GetMethod("http://jakarta.apache.org/");
try {
client.executeMethod(get);
// print response to stdout
System.out.println(get.getResponseBodyAsStream());
} finally {
// be sure the connection is released back to the connection
// manager
get.releaseConnection();
}
對每一個HttpClient.executeMethod須有一個method.releaseConnection()與之匹配.

12、HTTP方法


  HttpClient支持的HTTP方法有8種,下面分述之。

  1、Options

  HTTP方法Options用來向服務(wù)器發(fā)送請求,希望獲得針對由請求URL(request url)標志的資源在請求/應答的通信過程可以使用的功能選項。通過這個方法,客戶端可以在采取具體行動之前,就可對某一資源決定采取什么動作和/或以及一些必要條件,或者了解服務(wù)器提供的功能。這個方法最典型的應用,就是用來獲取服務(wù)器支持哪些HTTP方法。
  HttpClient中有一個類叫OptionsMethod,來支持這個HTTP方法,利用這個類的getAllowedMethods方法,就可以很簡單地實現(xiàn)上述的典型應用。
OptionsMethod options = new OptionsMethod("http://jakarta.apache.org");
// 執(zhí)行方法并做相應的異常處理
...
Enumeration allowedMethods = options.getAllowedMethods();
options.releaseConnection();

  2、Get

   HTTP方法GET用來取回請求URI(request-URI)標志的任何信息(以實體(entity)的形式),"get"這個單詞本意就是”獲取“的意思。如果請求URI指向的一個數(shù)據(jù)處理過程,那這個過程生成的數(shù)據(jù),在應答中以實體的形式被返回,而不是將這個過程的代碼的返回。
  如果HTTP包中含有If-ModifiedSince, If-Unmodified-Since, If-Match, If-None-Match, 或 If-Range等頭字段,則GET也就變成了”條件GET“,即只有滿足上述字段描述的條件的實體才被取回,這樣可以減少一些非必需的網(wǎng)絡(luò)傳輸,或者減少為獲取某一資源的多次請求(如第一次檢查,第二次下載)。(一般的瀏覽器,都有一個臨時目錄,用來緩存一些網(wǎng)頁信息,當再次瀏覽某個頁面的時候,只下載那些修改過的內(nèi)容,以加快瀏覽速度,就是這個道理。至于檢查,則常用比GET更好的方法HEAD來實現(xiàn)。)如果HTTP包中含有Range頭字段,那么請求URI指定的實體中,只有決定范圍條件的那部分才被取回來。(用過多線程下載工具的朋友,可能比較容易理解這一點)
  這個方法的典型應用,用來從web服務(wù)器下載文檔。HttpClient定義了一個類叫GetMethod來支持這個方法,用GetMethod類中g(shù)etResponseBody, getResponseBodyAsStream 或 getResponseBodyAsString函數(shù)就可以取到應答包包體中的文檔(如HTML頁面)信息。這這三個函數(shù)中,getResponseBodyAsStream通常是最好的方法,主要是因為它可以避免在處理下載的文檔之前緩存所有的下載的數(shù)據(jù)。
GetMethod get = new GetMethod("http://jakarta.apache.org");
// 執(zhí)行方法,并處理失敗的請求.
...
InputStream in = get.getResponseBodyAsStream();
// 利用輸入流來處理信息。
get.releaseConnection();

  對GetMethod的最常見的不正確的使用,是沒有將全部的應答主體的數(shù)據(jù)讀出來。還有,必須注意要手工明確地將鏈接釋放。

  3、Head

  HTTP的Head方法,與Get方法完全一致,唯一的差別是服務(wù)器不能在應答包中包含主體(message-body),而且一定不能包含主體。使用這個方法,可以使得客戶無需將資源下載回就可就以得到一些關(guān)于它的基本信息。這個方法常用來檢查超鏈的可訪問性以及資源最近有沒有被修改。
  HTTP的head方法最典型的應用,是獲取資源的基本信息。HttpClient定義了HeadMethod類支持這個方法,HeadMethod類與其它*Method類一樣,用 getResponseHeaders()取回頭部信息,而沒有自己的特殊方法。
HeadMethod head = new HeadMethod("http://jakarta.apache.org");
// 執(zhí)行方法,并處理失敗的請求.
...
// 取回應答包的頭字段信息.
Header[] headers = head.getResponseHeaders(); // 只取回最后修改日期字段的信息.
String lastModified = head.getResponseHeader("last-modified").getValue();


  4、Post

  Post在英文有“派駐”的意思,HTTP方法POST就是要求服務(wù)器接受請求包中的實體,并將其作為請求URI的下屬資源。從本質(zhì)上說,這意味著服務(wù)器要保存這個實體信息,而且通常由服務(wù)器端的程序進行處理。Post方法的設(shè)計意圖,是要以一種統(tǒng)一的方式實現(xiàn)下列功能:
  1. 對已有的資源做評注
  2. 將信息發(fā)布到BBS、新聞組、郵件列表,或類似的文章組中
  3. 將一塊數(shù)據(jù),提交給數(shù)據(jù)處理進程
  4. 通過追加操作,來擴展一個數(shù)據(jù)庫
  這些都操作期待著在服務(wù)器端產(chǎn)生一定的“副作用”,如修改了數(shù)據(jù)庫等。
  HttpClient定義PostMethod類以支持該HTTP方法,在httpclient中,使用post方法有兩個基本的步驟:為請求包準備數(shù)據(jù),然后讀取服務(wù)器來的應答包的信息。通過調(diào)用 setRequestBody()函數(shù),來為請求包提供數(shù)據(jù),它可以接收三類參數(shù):輸入流、名值對數(shù)組或字符串。至于讀取應答包需要調(diào)用 getResponseBody* 那一系列的方法,與GET方法處理應答包的方法相同。
  常見問題是,沒有將全部應答讀取(無論它對程序是否有用),或沒有釋放鏈接資源。

劉錚 2008-02-18 17:49 發(fā)表評論
]]>
用command-chain完成的For循環(huán)http://www.aygfsteel.com/liuzheng/articles/176927.html劉錚 劉錚 Tue, 22 Jan 2008 02:24:00 GMThttp://www.aygfsteel.com/liuzheng/articles/176927.htmlhttp://www.aygfsteel.com/liuzheng/comments/176927.htmlhttp://www.aygfsteel.com/liuzheng/articles/176927.html#Feedback0http://www.aygfsteel.com/liuzheng/comments/commentRss/176927.htmlhttp://www.aygfsteel.com/liuzheng/services/trackbacks/176927.htmlpackage nl.enovation.commons.command;

import java.util.Collection;

import org.apache.commons.chain.Command;
import org.apache.commons.chain.Context;

public class ForeachCommand implements Command {
    private String collectionProperty;
    private String instanceProperty;
    private Command command;
   
    @SuppressWarnings("unchecked")
    public boolean execute(Context context) throws Exception {
        Collection<? extends Object> collection = (Collection<? extends Object>) context.get(collectionProperty);
        if (collection != null) {
            for(Object object : collection) {
                context.put(instanceProperty, object);
                if (PROCESSING_COMPLETE == command.execute(context)) {
                    return PROCESSING_COMPLETE;
                } // else continue
            }
        }
        return CONTINUE_PROCESSING;
    }

    public String getCollectionProperty() {
        return collectionProperty;
    }

    public void setCollectionProperty(String collectionProperty) {
        this.collectionProperty = collectionProperty;
    }

    public String getInstanceProperty() {
        return instanceProperty;
    }

    public void setInstanceProperty(String instanceProperty) {
        this.instanceProperty = instanceProperty;
    }

    public Command getCommand() {
        return command;
    }

    public void setCommand(Command command) {
        this.command = command;
    }

}



劉錚 2008-01-22 10:24 發(fā)表評論
]]>
文件處理http://www.aygfsteel.com/liuzheng/articles/176807.html劉錚 劉錚 Mon, 21 Jan 2008 09:44:00 GMThttp://www.aygfsteel.com/liuzheng/articles/176807.htmlhttp://www.aygfsteel.com/liuzheng/comments/176807.htmlhttp://www.aygfsteel.com/liuzheng/articles/176807.html#Feedback0http://www.aygfsteel.com/liuzheng/comments/commentRss/176807.htmlhttp://www.aygfsteel.com/liuzheng/services/trackbacks/176807.htmlpackage nl.enovation.ems.transferlink.client.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

public class FileUtil {


 public static void moveFile(File source, String path) throws IOException {
  if(!source.renameTo(new File(path, source.getName()))){
   throw new IOException(
     "Can't move file "
     + source.getName()
     + " to "
     + path);
  }
 }
 
 public static File moveFile(File source, File path) throws IOException {
  File newFile = new File(path, source.getName());
  if(!source.renameTo(newFile)){
   throw new IOException(
     "Can't move file "
     + source.getName()
     + " to "
     + path);
  }
  return newFile;
 }
 
 public static void moveFile(File source, File path, boolean uniqueFileName) throws IOException {
  String fileName = source.getName();
  File file = new File(path, fileName);
  int count = 1;
  while(true) {
   if(file.exists()) {
    String newFileName = null;
    int idx = fileName.lastIndexOf(".");
    if(idx > 0) {
     newFileName = fileName.substring(0, idx) + "." + count + fileName.substring(idx); 
    } else {
     newFileName = fileName + "." + count;
    }
    file = new File(path, newFileName);
    count++;
   } else {
    break;
   }
  }
  if(!source.renameTo(file)){
   //try {
   // copyFile(source, file);
   // deleteFile(source);
   //}
   //catch (IOException e)
   //{
    throw new IOException(
      "Can't move file "
      + source.getName() //+ " (" + source.getAbsolutePath() + ")"
      + " to "
      + path);
     //+"("+e.getMessage()+")");
     // + " (" + file.getAbsolutePath() + ")");
   //}
  }
 }
 
 public static void moveFiles(File sourceDir, File destDir) throws IOException {
  java.io.File[] list=sourceDir.listFiles();
  for (int i = 0; i < list.length; i++) {
   if (!list[i].isDirectory()) {
    if(!list[i].renameTo(new File(destDir, list[i].getName()))) {
     throw new IOException(
       "Can't move file "
       + list[i].getName()
       + " to "
       + destDir.getAbsolutePath());
    }
   }
  }
 }
 
 /**
  * Copy a File (source) to a File (destination)
  * @param source
  * @param dest
  * @throws IOException
  */
 public static void copyFile(File source, File dest) throws IOException {
      FileChannel in = null, out = null;
      try {         
           in = new FileInputStream(source).getChannel();
           out = new FileOutputStream(dest).getChannel();

           long size = in.size();
           MappedByteBuffer buf = in.map(FileChannel.MapMode.READ_ONLY, 0, size);
           out.write(buf);

      } finally {
           if (in != null)     
            in.close();
           if (out != null)    
            out.close();
      }
 }
 
 /**
  * Write an input stream to a file.
  * @param source
  * @param dest
  * @param size
  * @throws IOException
  */
 public static int writeFile(InputStream source, File dest, long buffer) throws IOException {
  int bytesWrote = 0;
  FileChannel out = null;
  ReadableByteChannel in = null;
  ByteBuffer data = ByteBuffer.allocate((int) buffer);
  try {
   in = Channels.newChannel(source);
   out = new FileOutputStream(dest).getChannel();
   
   int read = in.read(data);
   while(read > 0) {
    bytesWrote += read;
    data.flip();
    out.write(data);
    data.clear();
    read = in.read(data);
   }

  } finally {
   if(out != null)
    out.close();
   if(in != null)
    in.close();
  }
  return bytesWrote;
 }
 
 public static void delete(java.io.File path) throws IOException {
  if (path.isDirectory()) {
   deleteDirectory(path);
  } else {
   deleteFile(path);
  }
 }
 
 protected static void deleteDirectory(java.io.File path) throws IOException {
  java.io.File[] list = path.listFiles();
  for (int i = 0; i < list.length; i++) {
   if (list[i].isDirectory()) {
    deleteDirectory(list[i]);
    if (!list[i].delete()) {
     throw new IOException("Can't delete directory '"+list[i]+"'.");
    }
   } else {
    deleteFile(list[i]);
   }
  }
 }
 
 protected static void deleteFile(java.io.File path) throws IOException {
  if (!path.delete()) {
   throw new IOException("Can't delete file '"+path+"'.");
  }
 }
 
 // TODO optimize ... read and write with buffers?!
 //@SuppressWarnings("unchecked")
 public static Collection splitFile(File file, int splitlen, File tmpDir) throws IOException
 {
  long leng = 0;
  int count = 1, read = 0;
  byte [] buffer = new byte[8196];
  
  String fileName  = file.getName();
  Collection files = new ArrayList();  
  RandomAccessFile infile = new RandomAccessFile(file, "r");
  read = infile.read(buffer);
  while(read != -1)
  {
   file = new File(tmpDir, fileName + ".lms.sp" + count);
   RandomAccessFile outfile = new RandomAccessFile(file, "rw");
   while( read != -1 && leng < splitlen)
   {
    outfile.write(buffer, 0, read);
    leng += read;
    read = infile.read(buffer);
   }
   leng = 0;
   outfile.close();
   file.deleteOnExit();
   files.add(file);
   count++;
  }
  return files;
 }
 
 public static File joinFile(String fileName, File tmpDir) throws IOException
 {
  int count = 1, read = 0;
  byte [] buffer = new byte[8196];
  
  File destFile = new File(tmpDir, fileName);
  RandomAccessFile outfile = new RandomAccessFile(destFile, "rw");
  while(true)
  {
   File readFile = new File(tmpDir, fileName + ".lms.sp" + count);
   if (readFile.exists())
   {
    RandomAccessFile infile = new RandomAccessFile(readFile, "r");
    read = infile.read(buffer);
    while(read != -1)
    {
     outfile.write(buffer, 0, read);
     read = infile.read(buffer);
    }
    infile.close();
    readFile.delete();
    count++;
   }
   else
   {
    break;
   }
  }
  outfile.close();
  return destFile;
 }
 
 public static boolean isComplete(String fileName, File dir, int parts) {
  int counter = 1;
  int matched = 0;
  File[] list = dir.listFiles();
  for (int i = 0; i < list.length; i++) {
   if (!list[i].isDirectory()) {
    String f = list[i].getName();
    String f2 = fileName + ".lms.sp";
    if(f.startsWith(f2)) {
     matched++;
    }
    counter++;
   }
  }
  if(matched == parts) {
   return true;
  } else {
   return false;
  }
  
 }
 
 public static File zipFile(File file, File dir) throws IOException {
  WritableByteChannel out = null;
  ReadableByteChannel in = null;
  FileInputStream source = new FileInputStream(file);
  File dest = new File(dir, file.getName() + ".zip");
  ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(dest));
  dest.deleteOnExit();
  int buffer = 4096;
  ByteBuffer data = ByteBuffer.allocate(buffer);
  try {
   zos.putNextEntry(new ZipEntry(file.getName()));

   in = Channels.newChannel(source);
   out = Channels.newChannel(zos);
   
   int read = in.read(data);
   while(read > 0) {
    data.flip();
    out.write(data);
    data.clear();
    read = in.read(data);
   }
   
   zos.closeEntry();
  } finally {
   if(zos != null) {
    zos.finish();
   }
   if(out != null)
    out.close();
   if(in != null)
    in.close();
  }
  return dest;
 }
 
 public static File unzipFile(File file, File dir) throws IOException {
  WritableByteChannel out = null;
  ReadableByteChannel in = null;
  ZipEntry entry = null;
  ZipFile zipFile = null;
  int buffer = 4096;
  ByteBuffer data = ByteBuffer.allocate(buffer);
  File unzippedFile = null;
  try {
   zipFile = new ZipFile(file, ZipFile.OPEN_READ);
   Enumeration zipFileEntries = zipFile.entries();
      
   // Process each entry
   if (zipFileEntries.hasMoreElements()) {
    // grab a zip file entry
    entry = (ZipEntry) zipFileEntries.nextElement();
    String currentEntry = entry.getName();
    InputStream input = zipFile.getInputStream(entry);
    unzippedFile = new File(dir, currentEntry);
    FileOutputStream output = new FileOutputStream(unzippedFile);
    
    in = Channels.newChannel(input);
    out = Channels.newChannel(output);

    int read = in.read(data);
    while(read > 0) {
     data.flip();
     out.write(data);
     data.clear();
     read = in.read(data);
    }
   }
  } finally {
   if(file != null)
    file.delete();
   if(zipFile != null)
    zipFile.close();
   if(out != null)
    out.close();
   if(in != null)
    in.close();
  }
  return unzippedFile;
 }
}


不過最好使用Apache Common 的IO組件。
里面有個FileUtils,提供了很多很好的方法。
可以參考:
 

http://commons.apache.org/io/apidocs/index.html



劉錚 2008-01-21 17:44 發(fā)表評論
]]>
有關(guān)JAXB對xsd中的時間數(shù)據(jù)類型的處理http://www.aygfsteel.com/liuzheng/articles/173389.html劉錚 劉錚 Mon, 07 Jan 2008 09:09:00 GMThttp://www.aygfsteel.com/liuzheng/articles/173389.htmlhttp://www.aygfsteel.com/liuzheng/comments/173389.htmlhttp://www.aygfsteel.com/liuzheng/articles/173389.html#Feedback0http://www.aygfsteel.com/liuzheng/comments/commentRss/173389.htmlhttp://www.aygfsteel.com/liuzheng/services/trackbacks/173389.html使用xjc 將xsd中的時間數(shù)據(jù):time datetime 等等轉(zhuǎn)化為XMLGregorianCalendar的類
處理XMLGregorianCalendar可以使用DatatypeFactory的工廠類進行創(chuàng)建,其中有個newXMLGregorianCalendar(GregorianCalendar cal)
          根據(jù) GregorianCalendar 創(chuàng)建 XMLGregorianCalendar
newXMLGregorianCalendar(int year, int month, int day, int hour, int minute, int second, int millisecond, int timezone)
          java.util.GregorianCalendar 實例需要轉(zhuǎn)換為 XMLGregorianCalendar 實例的值空間的構(gòu)造方法。



劉錚 2008-01-07 17:09 發(fā)表評論
]]>
標準的讀取文件的方法,讀取整個文件http://www.aygfsteel.com/liuzheng/articles/172271.html劉錚 劉錚 Wed, 02 Jan 2008 10:02:00 GMThttp://www.aygfsteel.com/liuzheng/articles/172271.htmlhttp://www.aygfsteel.com/liuzheng/comments/172271.htmlhttp://www.aygfsteel.com/liuzheng/articles/172271.html#Feedback0http://www.aygfsteel.com/liuzheng/comments/commentRss/172271.htmlhttp://www.aygfsteel.com/liuzheng/services/trackbacks/172271.html         File f=new File("d:"+File.separator+"1.txt");
        BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream(f)));
        StringBuffer whole=new StringBuffer();
        String line=new String();
        for (line=br.readLine(); line!=null; line=br.readLine()) {
            whole.append(line);
           
        }
        System.out.println(whole.toString());
    }
使用readLine()對整個文件或者Read流進行字符掃描


public void test1() throws IOException{
        File f=new File("d:"+File.separator+"1.txt");

        BufferedInputStream br=new BufferedInputStream(new FileInputStream(f));
        StringBuffer whole=new StringBuffer();
        int line;
        for (line=br.read(); line!=-1; line=br.read()) {
            whole.append(line);
           
        }
        System.out.println(whole.toString());
    }

使用read()對整個文件或者Read流進行字節(jié)的掃描



劉錚 2008-01-02 18:02 發(fā)表評論
]]>
java多線程中sleep()和join()的區(qū)別 http://www.aygfsteel.com/liuzheng/articles/167243.html劉錚 劉錚 Wed, 12 Dec 2007 07:21:00 GMThttp://www.aygfsteel.com/liuzheng/articles/167243.htmlhttp://www.aygfsteel.com/liuzheng/comments/167243.htmlhttp://www.aygfsteel.com/liuzheng/articles/167243.html#Feedback0http://www.aygfsteel.com/liuzheng/comments/commentRss/167243.htmlhttp://www.aygfsteel.com/liuzheng/services/trackbacks/167243.htmlIf 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 Interrupt method. Thread.Sleep(System.Threading.Timeout.Infinite)

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’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.

When Join is called and no parameter is passed in, the current thread will wait indefinitely for the thread to end. When Join is called with a timeout value, the Join method will block for at most that period of time and then return a value indicating if the thread of interest ended. A key difference is that Join is called on a different thread while Sleep is called on the current thread. Join also causes the current thread to pause for a period of time, but with the idea that it is waiting for some other thread to terminate. At the point the thread being joined terminates, the Join method returns.



劉錚 2007-12-12 15:21 發(fā)表評論
]]>
java多線程的中止http://www.aygfsteel.com/liuzheng/articles/166419.html劉錚 劉錚 Sun, 09 Dec 2007 03:35:00 GMThttp://www.aygfsteel.com/liuzheng/articles/166419.htmlhttp://www.aygfsteel.com/liuzheng/comments/166419.htmlhttp://www.aygfsteel.com/liuzheng/articles/166419.html#Feedback0http://www.aygfsteel.com/liuzheng/comments/commentRss/166419.htmlhttp://www.aygfsteel.com/liuzheng/services/trackbacks/166419.html
在run方法中加入
public void run(){
    while(flag){
    ......
    }
}
再加入
public void shutDown(){
    flag=false;
}

以后使用shutDown進行關(guān)閉線程,而不用廢棄了的stop方法,因為stop方法太粗暴了,立馬停止線程的話,對已經(jīng)打開的資源不能進行處理。

劉錚 2007-12-09 11:35 發(fā)表評論
]]>
java 5 中的enum的深入學習心得http://www.aygfsteel.com/liuzheng/articles/165741.html劉錚 劉錚 Thu, 06 Dec 2007 02:55:00 GMThttp://www.aygfsteel.com/liuzheng/articles/165741.htmlhttp://www.aygfsteel.com/liuzheng/comments/165741.htmlhttp://www.aygfsteel.com/liuzheng/articles/165741.html#Feedback0http://www.aygfsteel.com/liuzheng/comments/commentRss/165741.htmlhttp://www.aygfsteel.com/liuzheng/services/trackbacks/165741.htmlThe full enum syntax actually provides quite a bit more power and flexibility:
  • You can define your own fields, methods, and constructors for the enumerated type.

  • 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.

  • Although an enum may not extend anything, it may implement one or more interfaces.

  • Most esoterically, individual enumerated values can have their own class bodies that override methods defined by the type.

Rather than formally specifying the syntax for each of these advanced enum declarations, we'll demonstrate the syntax in the examples that follow.

 
for example:
 
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; }
}


劉錚 2007-12-06 10:55 發(fā)表評論
]]>
java 5中枚舉類型學習http://www.aygfsteel.com/liuzheng/articles/165597.html劉錚 劉錚 Wed, 05 Dec 2007 09:17:00 GMThttp://www.aygfsteel.com/liuzheng/articles/165597.htmlhttp://www.aygfsteel.com/liuzheng/comments/165597.htmlhttp://www.aygfsteel.com/liuzheng/articles/165597.html#Feedback0http://www.aygfsteel.com/liuzheng/comments/commentRss/165597.htmlhttp://www.aygfsteel.com/liuzheng/services/trackbacks/165597.html Tiger 中的一個重要新特性是枚舉構(gòu)造,它是一種新的類型,允許用常量來表示特定的數(shù)據(jù) 片斷,而且全部都以類型安全的形式來表示。Tiger 專家、developerWorks 的多產(chǎn)作者 Brett McLaughlin將解釋枚舉的定義,介紹如何在應用程序中運用枚舉,以及它為什么能夠讓您拋棄所有舊的
public static final 代碼。

  您已經(jīng)知道,Java 代碼的兩個基本的構(gòu)造塊是類 和接口。現(xiàn)在 Tiger 又引入了枚舉,一般簡稱它為 enum。這個新類型允許您表示特定的數(shù)據(jù)點,這些數(shù)據(jù)點只接受分配時預先定 義的值集合。
 當然,熟練的程序員可以用靜態(tài)常量實現(xiàn)這項功能,如清單 1 所示:



清單 1. public static final 的常量

public class OldGrade {

 public static final int A = 1;
 public static final int B = 2;
 public static final int C = 3;
 public static final int D = 4;
 public static final int F = 5;
 public static final int INCOMPLETE = 6;
}



說明:我要感謝 O"Reilly 媒體公司,該公司允許在本文中使用我撰寫的 Java 1.5 Tiger:
A Developer"s Notebook 一書中“枚舉”這一章中的代碼示例(請參閱參考資料)。

然后您就可以讓類接受像 OldGrade.B 這樣的常量,但是在這樣做的時候,請記住這類常量
是 Java 中 int 類型的常量,這意味著該方法可以接受任何 int 類型的值,即使它和
OldGrade 中定的所有級別都不對應。因此,您需要檢測上界和下界,在出現(xiàn)無效值的時候,可能還
要包含一個 IllegalArgumentException。而且,如果后來又添加另外一個級別(例如
OldGrade.WITHDREW_PASSING),那么必須改變所有代碼中的上界,才能接受這個新值。

換句話說,在使用這類帶有整型常量的類時,該解決方案也許可行,但并不是非常有效。幸
運的是,枚舉提供了更好的方法。

定義枚舉
清單 2 使用了一個可以提供與清單 1 相似的功能的枚舉:

清單 2. 簡單的枚舉類型

package com.oreilly.tiger.ch03;

public enum Grade {
 A, B, C, D, F, INCOMPLETE
};



在這里,我使用了新的關(guān)鍵字 enum,為 enum 提供了一個名稱,并指定了允許的值。然后
,Grade 就變成了一個枚舉類型,您可以按清單 3 所示的方法使用它:

清單 3. 使用枚舉類型

package com.oreilly.tiger.ch03;

public class Student {

 private String firstName;
 private String lastName;
 private Grade grade;

 public Student(String firstName, String lastName) {
  this.firstName = firstName;
  this.lastName = lastName;
 }

 public void setFirstName(String firstName) {
  this.firstName = firstName;
 }

 public String getFirstName() {
  return firstName;
 }

 public void setLastName(String lastName) {
  this.lastName = lastName;
 }

 public String getLastName() {
  return lastName;
 }

 public String getFullName() {
  return new StringBuffer(firstName)
      .append(" ")
      .append(lastName)
      .toString();
 }

 public void assignGrade(Grade grade) {
  this.grade = grade;
 }

 public Grade getGrade() {
  return grade;
 }
}



用以前定義過的類型建立一個新的枚舉(grade)之后,您就可以像使用其他成員變量一樣
使用它了。當然,枚舉只能分配枚舉值中的一個(例如,A、C 或 INCOMPLETE)。而且,在
assignGrade() 中是沒有進行錯誤檢測的代碼,也沒有考慮邊界情況,請注意這是如何做到


使用枚舉值
迄今為止,您所看到的示例都相當簡單,但是枚舉類型提供的東西遠不止這些。您可以逐個
遍歷枚舉值,也可以在 switch 語句中使用枚舉值,枚舉是非常有價值的。

遍歷枚舉值
下面我們用一個示例顯示如何遍歷枚舉類型的值。清單 4 所示的這項技術(shù),適用于調(diào)試、
快速打印任務(wù)以及把枚舉加載到集合(我很快將談到)中的工具:

清單 4. 遍歷枚舉值

public void listGradeValues(PrintStream out) throws IOException {
 for (Grade g : Grade.values()) {
  out.println("Allowed value: "" + g + """);
 }
}



運行這段代碼,將得到清單 5 所示的輸出:

清單 5. 迭代操作的輸出

Allowed Value: "A"
Allowed Value: "B"
Allowed Value: "C"
Allowed Value: "D"
Allowed Value: "F"
Allowed Value: "INCOMPLETE"



這里有許多東西。首先,我使用了 Tiger 的新的 for/in 循環(huán)(也叫作 foreach 或 增強
的 for)。另外,您可以看到 values() 方法返回了一個由獨立的 Grade 實例構(gòu)成的數(shù)組
,每個數(shù)組都有一個枚舉類型的值。換句話說,values() 的返回值是 Grade[]。

在枚舉間切換
能夠在枚舉的值之間移動很好,但是更重要的是根據(jù)枚舉的值進行決策。您當然可以寫一堆
if (grade.equals(Grade.A)) 類型的語句,但那是在浪費時間。Tiger 能夠很方便地把枚
舉支持添加到過去的好東西 switch 語句上,所以它很容易使用,而且適合您已知的內(nèi)容。
清單 6
向?qū)⒄故救绾谓鉀Q這個難題:

清單 6. 在枚舉之間切換

public void testSwitchStatement(PrintStream out) throws IOException {
 StringBuffer outputText = new StringBuffer(student1.getFullName());

 switch (student1.getGrade()) {
  case A:
   outputText.append(" excelled with a grade of A");
   break;
  case B: // fall through to C
  case C:
   outputText.append(" passed with a grade of ")
        .append(student1.getGrade().toString());
   break;
  case D: // fall through to F
  case F:
   outputText.append(" failed with a grade of ")
        .append(student1.getGrade().toString());
   break;
  case INCOMPLETE:
   outputText.append(" did not complete the class.");
   break;
 }

 out.println(outputText.toString());
}



在這里,枚舉值被傳遞到 switch 語句中(請記住,getGrade() 是作為 Grade 的實例返回
的),而每個 case 子句將處理一個特定的值。該值在提供時沒有枚舉前綴,這意味著不用
將代碼寫成 case Grade.A,只需將其寫成 case A 即可。如果您不這么做,編譯器不會接
受有前綴的值。

現(xiàn)在,您應該已經(jīng)了解使用 switch 語句時的基本語法,但是還有一些事情您需要知道。
在使用 switch 之前進行計劃
正如您所期待的,在使用枚舉和 switch 時,您可以使用 default 語句。清單 7 顯示了這
個用法:

清單 7. 添加一個 default 塊

public void testSwitchStatement(PrintStream out) throws IOException {
 StringBuffer outputText = new StringBuffer(student1.getFullName());

 switch (student1.getGrade()) {
  case A:
   outputText.append(" excelled with a grade of A");
   break;
  case B: // fall through to C
  case C:
   outputText.append(" passed with a grade of ")
        .append(student1.getGrade().toString());
   break;
  case D: // fall through to F
  case F:
   outputText.append(" failed with a grade of ")
        .append(student1.getGrade().toString());
   break;
  case INCOMPLETE:
   outputText.append(" did not complete the class.");
   break;
  default:
   outputText.append(" has a grade of ")
        .append(student1.getGrade().toString());
   break;
 }

 out.println(outputText.toString());
}



研究以上代碼可以看出,任何沒有被 case 語句處理的枚舉值都會被 default 語句處理。
這項技術(shù)您應當堅持采用。原因是:假設(shè) Grade 枚舉被您的小組中其他程序員修改(而且
他忘記告訴您這件事)成清單 8 所示的版本:

清單 8. 給 Grade 枚舉添加一個值

package com.oreilly.tiger.ch03;

public enum Grade {
 A, B, C, D, F, INCOMPLETE,
 WITHDREW_PASSING, WITHDREW_FAILING
};



現(xiàn)在,如果使用清單 6 的代碼所示的新版 Grade,那么這兩個新值會被忽略。更糟的是,
您甚至看不到錯誤!在這種情況下,存在某種能夠通用的 default 語句是非常重要的。清
單 7 無法很好地處理這些值,但是它會提示您還有其他值,您需要處理這些值。一旦完成處理,
您就會有一個繼續(xù)運行的應用程序,而且它不會忽略這些值,甚至還會指導您下一步的動作
。所以這是一個良好的編碼習慣。

枚舉和集合
您所熟悉的使用 public static final 方法進行編碼的那些東西,可能已經(jīng)轉(zhuǎn)而采用枚舉
的值作為映射的鍵。如果您不知道其中的含義,請參見清單 9,它是一個公共錯誤信息的示
例,在使用 Ant 的 build 文件時,可能會彈出這樣的消息,如下所示:

清單 9. Ant 狀態(tài)碼

package com.oreilly.tiger.ch03;

public enum AntStatus {
 INITIALIZING,
 COMPILING,
 COPYING,
 JARRING,
 ZIPPING,
 DONE,
 ERROR
}



為每個狀態(tài)碼分配一些人們能讀懂的錯誤信息,從而允許人們在 Ant 提供某個代碼時查找
合適的錯誤信息,將這些信息顯示在控制臺上。這是映射(Map)的一個絕好用例,在這里
,每個映射(Map)的鍵都是一個枚舉值,而每個值都是鍵的錯誤信息。清單 10 演示了該
映射的工作方式:

清單 10. 枚舉的映射(Map)

public void testEnumMap(PrintStream out) throws IOException {
 // Create a map with the key and a String message
 EnumMap<AntStatus, String> antMessages =
  new EnumMap<AntStatus, String>(AntStatus.class);

 // Initialize the map
 antMessages.put(AntStatus.INITIALIZING, "Initializing Ant...");
 antMessages.put(AntStatus.COMPILING,  "Compiling Java classes...");
 antMessages.put(AntStatus.COPYING,   "Copying files...");
 antMessages.put(AntStatus.JARRING,   "JARring up files...");
 antMessages.put(AntStatus.ZIPPING,   "ZIPping up files...");
 antMessages.put(AntStatus.DONE,     "Build complete.");
 antMessages.put(AntStatus.ERROR,    "Error occurred.");

 // Iterate and print messages
 for (AntStatus status : AntStatus.values() ) {
  out.println("For status " + status + ", message is: " +
        antMessages.get(status));
 }
}



該代碼使用了泛型(generics)(請參閱參考資料)和新的 EnumMap 構(gòu)造來建立新映射。
而且,枚舉值是通過其 Class 對象提供的,同時提供的還有映射值的類型(在該例中,它
只是一個簡單的字符串)。該方法的輸出如清單 11 所示:

枚舉的 Class 對象
您可能已經(jīng)注意到,清單 10 中的示例代碼實際上表明 Tiger 把枚舉當作類,這可以從
AntStatus 的 Class 對象那里得到證明,該對象不僅可用,而且正被實際使用。這是真的
。歸根到底, Tiger 還是把枚舉看成是特殊的類類型。有關(guān)枚舉的具體實現(xiàn)細節(jié),請參閱
Java 5.0 Tiger: A Developer"s Notebook 的第三章(請參閱參考資料)。


清單 11. 清單 10 的輸出

[echo] Running AntStatusTester...
[java] For status INITIALIZING, message is: Initializing Ant...
[java] For status COMPILING, message is: Compiling Java classes...
[java] For status COPYING, message is: Copying files...
[java] For status JARRING, message is: JARring up files...
[java] For status ZIPPING, message is: ZIPping up files...
[java] For status DONE, message is: Build complete.
[java] For status ERROR, message is: Error occurred.



更進一步枚舉也可以與集合結(jié)合使用,而且非常像新的 EnumMap 構(gòu)造,Tiger 提供了一套新的
EnumSet實現(xiàn),允許您使用位操作符。另外,可以為枚舉添加方法,用它們實現(xiàn)接口,定義叫作特定
值的類的實體,在該實體中,特定的代碼被附加到枚舉的具體值上。這些特性超出了本文的
范圍,但是在其他地方,有詳細介紹它們的文檔(請參閱參考資料)。

使用枚舉,但是不要濫用
學習任何新版語言的一個危險就是瘋狂使用新的語法結(jié)構(gòu)。如果這樣做,那么您的代碼就會
突然之間有 80% 是泛型、標注和枚舉。所以,應當只在適合使用枚舉的地方才使用它。那
么,枚舉在什么地方適用呢?一條普遍規(guī)則是,任何使用常量的地方,例如目前用 switch
代碼切換常量的地方。如果只有單獨一個值(例如,鞋的最大尺寸,或者籠子中能裝猴子的
最大數(shù)目),則還是把這個任務(wù)留給常量吧。但是,如果定義了一組值,而這些值中的任何
一個都可以用于特定的數(shù)據(jù)類型,那么將枚舉用在這個地方最適合不過。


劉錚 2007-12-05 17:17 發(fā)表評論
]]>
利用jakarta Commons組件收發(fā)郵件http://www.aygfsteel.com/liuzheng/articles/162544.html劉錚 劉錚 Fri, 23 Nov 2007 02:13:00 GMThttp://www.aygfsteel.com/liuzheng/articles/162544.htmlhttp://www.aygfsteel.com/liuzheng/comments/162544.htmlhttp://www.aygfsteel.com/liuzheng/articles/162544.html#Feedback0http://www.aygfsteel.com/liuzheng/comments/commentRss/162544.htmlhttp://www.aygfsteel.com/liuzheng/services/trackbacks/162544.html

Telnet to port 25 of a SMTP server, and you will see the server respond with a numeric code (220). SMTPReply.isPositiveCompletion( ) returns true 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 SMTPReply.SERVICE_READY. The following example uses getReplyCode( ) and SMTPReply.isPositiveCompletion() to test the connection to the SMTP server:

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( );

Instead of sendSimpleMessage( ), the previous example sets a sender address and two recipient addresses using setSender( ) and addRecipient(). The message body is then written to a Writer returned by sendMessageData(). When the Writer is closed, the message is sent by calling completePendingCommand(). completePendingCommand( ) returns true if the message has been queued for delivery.

收郵件:

Use Commons Net POP3Client to check a POP3 mailbox for incoming mail. The following example connects to the POP3 server www.discursive.com, logs in as tobrien@discursive.com, and prints each message in the mailbox:

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 < 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( );


劉錚 2007-11-23 10:13 發(fā)表評論
]]>
使用J2SE API讀取Properties文件的六種方法http://www.aygfsteel.com/liuzheng/articles/157562.html劉錚 劉錚 Thu, 01 Nov 2007 09:54:00 GMThttp://www.aygfsteel.com/liuzheng/articles/157562.htmlhttp://www.aygfsteel.com/liuzheng/comments/157562.htmlhttp://www.aygfsteel.com/liuzheng/articles/157562.html#Feedback0http://www.aygfsteel.com/liuzheng/comments/commentRss/157562.htmlhttp://www.aygfsteel.com/liuzheng/services/trackbacks/157562.html   
  1.使用java.util.Properties類的load()方法
  
  示例: InputStream in = lnew BufferedInputStream(new FileInputStream(name));
  Properties p = new Properties();
  p.load(in);
  
  2.使用java.util.ResourceBundle類的getBundle()方法
  
  示例: ResourceBundle rb = ResourceBundle.getBundle(name, Locale.getDefault());
  
  3.使用java.util.PropertyResourceBundle類的構(gòu)造函數(shù)
  
  示例: InputStream in = new BufferedInputStream(new FileInputStream(name));
  ResourceBundle rb = new PropertyResourceBundle(in);
  
  4.使用class變量的getResourceAsStream()方法
  
  示例: InputStream in = JProperties.class.getResourceAsStream(name);
  Properties p = new Properties();
  p.load(in);
  
  5.使用class.getClassLoader()所得到的java.lang.ClassLoader的getResourceAsStream()方法
  
  示例: InputStream in = JProperties.class.getClassLoader().getResourceAsStream(name); bitsCN.nET中國網(wǎng)管博客
  Properties p = new Properties();
  p.load(in);
  
  6.使用java.lang.ClassLoader類的getSystemResourceAsStream()靜態(tài)方法
  
  示例: InputStream in = ClassLoader.getSystemResourceAsStream(name);
  Properties p = new Properties();
  p.load(in);
  
  補充
  
  Servlet中可以使用javax.servlet.ServletContext的getResourceAsStream()方法
  
  示例:InputStream in = context.getResourceAsStream(path);
  Properties p = new Properties();
  p.load(in);
  
  完整的示例,可以參考附件文件
  
  如何上傳文件,誰知道請告訴以下。 只好把source都貼上來了
  
  JProperties.java文件
  
  /**
  ** This program is free software.
  **
  ** You may redistribute it and/or modify it under the terms of the GNU
  ** General Public License as published by the Free Software Foundation.
  ** Version 2 of the license should be included with this distribution in
  ** the file LICENSE, as well as License.html. If the license is not 09hr.com網(wǎng)管求職
  ** included with this distribution, you may find a copy at the FSF web
  ** site at 'www.gnu.org' or 'www.fsf.org', or you may write to the
  ** Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139 USA.
  **
  ** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,
  ** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR
  ** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY
  ** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR
  ** REDISTRIBUTION OF THIS SOFTWARE.
  **/
  
  package com.kindani;
  
  //import javax.servlet.ServletContext;
  import java.util.*;
  import java.io.InputStream;
  import java.io.IOException;
  import java.io.BufferedInputStream;
  import java.io.FileInputStream;
  
  /**
  * 使用J2SE API読取Properties文件的六種方法
  * User: SYNFORM
  * Date: 2005/07/12
  * Time: 18:40:55
  * To change this template use File | Settings | File Templates.

bitsCN_com


  */
  public class JProperties {
  
  public final static int BY_PROPERTIES = 1;
  public final static int BY_RESOURCEBUNDLE = 2;
  public final static int BY_PROPERTYRESOURCEBUNDLE = 3;
  public final static int BY_CLASS = 4;
  public final static int BY_CLASSLOADER = 5;
  public final static int BY_SYSTEM_CLASSLOADER = 6;
  
  public final static Properties loadProperties(final String name, final int type) throws IOException {
  Properties p = new Properties();
  InputStream in = null;
  if (type == BY_PROPERTIES) {
  in = new BufferedInputStream(new FileInputStream(name));
  assert (in != null);
  p.load(in);
  } else if (type == BY_RESOURCEBUNDLE) {
  ResourceBundle rb = ResourceBundle.getBundle(name, Locale.getDefault());
  assert (rb != null);
  p = new ResourceBundleAdapter(rb);
  } else if (type == BY_PROPERTYRESOURCEBUNDLE) {
  in = new BufferedInputStream(new FileInputStream(name));
  assert (in != null);

DL.bitsCN.com網(wǎng)管軟件下載


  ResourceBundle rb = new PropertyResourceBundle(in);
  p = new ResourceBundleAdapter(rb);
  } else if (type == BY_CLASS) {
  assert (JProperties.class.equals(new JProperties().getClass()));
  in = JProperties.class.getResourceAsStream(name);
  assert (in != null);
  p.load(in);
  //    return new JProperties().getClass().getResourceAsStream(name);
  } else if (type == BY_CLASSLOADER) {
  assert (JProperties.class.getClassLoader().equals(new JProperties().getClass().getClassLoader()));
  in = JProperties.class.getClassLoader().getResourceAsStream(name);
  assert (in != null);
  p.load(in);
  //     return new JProperties().getClass().getClassLoader().getResourceAsStream(name);
  } else if (type == BY_SYSTEM_CLASSLOADER) {
  in = ClassLoader.getSystemResourceAsStream(name);
  assert (in != null);
  p.load(in);
  }
  
  if (in != null) {
  in.close();
  }
  return p;
  
  }
   09hr.com網(wǎng)管求職
  // ---------------------------------------------- servlet used
  /*
  public static Properties loadProperties(ServletContext context, String path) throws IOException {
  assert (context != null);
  InputStream in = context.getResourceAsStream(path);
  assert (in != null);
  Properties p = new Properties();
  p.load(in);
  in.close();
  return p;
  }
  */
  
  // ---------------------------------------------- support class
  
  /**
  * ResourceBundle Adapter class.
  */
  public static class ResourceBundleAdapter extends Properties {
  public ResourceBundleAdapter(ResourceBundle rb) {
  assert (rb instanceof java.util.PropertyResourceBundle);
  this.rb = rb;
  java.util.Enumeration e = rb.getKeys();
  while (e.hasMoreElements()) {
  Object o = e.nextElement();
  this.put(o, rb.getObject((String) o));
  }
  }
  
  private ResourceBundle rb = null;
  
  public ResourceBundle getBundle(String baseName) {

BBS.bitsCN.com國內(nèi)最早的網(wǎng)管論壇


  return ResourceBundle.getBundle(baseName);
  }
  
  public ResourceBundle getBundle(String baseName, Locale locale) {
  return ResourceBundle.getBundle(baseName, locale);
  }
  
  public ResourceBundle getBundle(String baseName, Locale locale, ClassLoader loader) {
  return ResourceBundle.getBundle(baseName, locale, loader);
  }
  
  public Enumeration<String> getKeys() {
  return rb.getKeys();
  }
  
  public Locale getLocale() {
  return rb.getLocale();
  }
  
  public Object getObject(String key) {
  return rb.getObject(key);
  }
  
  public String getString(String key) {
  return rb.getString(key);
  }
  
  public String[] getStringArray(String key) {
  return rb.getStringArray(key);
  }
  
  protected Object handleGetObject(String key) {
  return ((PropertyResourceBundle) rb).handleGetObject(key);
  }
  
  }
  
  }
Play.bitsCN.com小游戲

  
  
  JPropertiesTest.java文件
  
  /**
  ** This program is free software.
  **
  ** You may redistribute it and/or modify it under the terms of the GNU
  ** General Public License as published by the Free Software Foundation.
  ** Version 2 of the license should be included with this distribution in
  ** the file LICENSE, as well as License.html. If the license is not
  ** included with this distribution, you may find a copy at the FSF web
  ** site at 'www.gnu.org' or 'www.fsf.org', or you may write to the
  ** Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139 USA.
  **
  ** THIS

劉錚 2007-11-01 17:54 發(fā)表評論
]]>
Java 的讀寫問題http://www.aygfsteel.com/liuzheng/articles/157546.html劉錚 劉錚 Thu, 01 Nov 2007 09:28:00 GMThttp://www.aygfsteel.com/liuzheng/articles/157546.htmlhttp://www.aygfsteel.com/liuzheng/comments/157546.htmlhttp://www.aygfsteel.com/liuzheng/articles/157546.html#Feedback0http://www.aygfsteel.com/liuzheng/comments/commentRss/157546.htmlhttp://www.aygfsteel.com/liuzheng/services/trackbacks/157546.html
File aFile = new File("input.data");
InputStream is = new FileInputStream(aFile);
byte[] data = new byte[aFile.length()];
is.read(data);

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 java.io.InputStream gives us the following information:


public int read(byte[] b) throws IOException

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. . .

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:


ByteArrayOutputStream buffer = new ByteArrayOutputStream();
File aFile = new File("input.data");
InputStream is = new FileInputStream(aFile);
byte[] temp = new byte[1024];
int read;

while((read = is.read(temp)) > 0){
   buffer.write(temp, 0, read);
}
           
byte[] data = buffer.toByteArray();
// process the data array . . .



劉錚 2007-11-01 17:28 發(fā)表評論
]]>
內(nèi)部類的作用http://www.aygfsteel.com/liuzheng/articles/155015.html劉錚 劉錚 Mon, 22 Oct 2007 07:59:00 GMThttp://www.aygfsteel.com/liuzheng/articles/155015.htmlhttp://www.aygfsteel.com/liuzheng/comments/155015.htmlhttp://www.aygfsteel.com/liuzheng/articles/155015.html#Feedback0http://www.aygfsteel.com/liuzheng/comments/commentRss/155015.htmlhttp://www.aygfsteel.com/liuzheng/services/trackbacks/155015.html
Java內(nèi)部類是Java言語的一個很重要的概念,《Java編程思想》花了很大的篇幅來講述這個概念。但是我們在實踐中很少用到它,雖然我們在很多時候會被動的使用到它,但它仍然像一個幕后英雄一樣,不為我們所知,不為我們所用。
本文不試圖來講述Java內(nèi)部類的今生前世、來龍去脈,這些在網(wǎng)絡(luò)上都已經(jīng)汗牛充棟。如果讀者想了解這些,可以在網(wǎng)絡(luò)上搜索來學習。Java內(nèi)部類總是躲在它的外部類里,像一個幕后英雄一樣。但是幕后英雄也有用武之地,在很多時候,恰當?shù)氖褂肑ava內(nèi)部類能起到讓人拍案叫絕的作用。本文試圖談一談讓這個幕后英雄也有用武之地的四個場景,希望引起大家對使用Java內(nèi)部類的興趣。
以下的文字,要求大家熟悉Java內(nèi)部類的概念后來閱讀。
 
 
場景一:當某個類除了它的外部類,不再被其他的類使用時
我們說這個內(nèi)部類依附于它的外部類而存在,可能的原因有:1、不可能為其他的類使用;2、出于某種原因,不能被其他類引用,可能會引起錯誤。等等。這個場景是我們使用內(nèi)部類比較多的一個場景。下面我們以一個大家熟悉的例子來說明。
在我們的企業(yè)級Java項目開發(fā)過程中,數(shù)據(jù)庫連接池是一個我們經(jīng)常要用到的概念。雖然在很多時候,我們都是用的第三方的數(shù)據(jù)庫連接池,不需要我們親自來做這個數(shù)據(jù)庫連接池。但是,作為我們Java內(nèi)部類使用的第一個場景,這個數(shù)據(jù)庫連接池是一個很好的例子。為了簡單起見,以下我們就來簡單的模擬一下數(shù)據(jù)庫連接池,在我們的例子中,我們只實現(xiàn)數(shù)據(jù)庫連接池的一些簡單的功能。如果想完全實現(xiàn)它,大家不妨自己試一試。
首先,我們定義一個接口,將數(shù)據(jù)庫連接池的功能先定義出來,如下:
public interface Pool extends TimerListener
{
        //初始化連接池
        public boolean init();
        //銷毀連接池
        public void destory();
        //取得一個連接
        public Connection getConn();
        //還有一些其他的功能,這里不再列出
        ……
}
有了這個功能接口,我們就可以在它的基礎(chǔ)上實現(xiàn)數(shù)據(jù)庫連接池的部分功能了。我們首先想到這個數(shù)據(jù)庫連接池類的操作對象應該是由Connection對象組成的一個數(shù)組,既然是數(shù)組,我們的池在取得Connection的時候,就要對數(shù)組元素進行遍歷,看看Connection對象是否已經(jīng)被使用,所以數(shù)組里每一個Connection對象都要有一個使用標志。我們再對連接池的功能進行分析,會發(fā)現(xiàn)每一個Connection對象還要一個上次訪問時間和使用次數(shù)。
通過上面的分析,我們可以得出,連接池里的數(shù)組的元素應該是由對象組成,該對象的類可能如下:
public class PoolConn
{
        private Connection conn;
        private boolean isUse;
        private long lastAccess;
        private int useCount;
        ……
}
下面的省略號省掉的是關(guān)于四個屬性的一些get和set方法。我們可以看到這個類的核心就是Connection,其他的一些屬性都是Connection的一些標志。可以說這個類只有在連接池這個類里有用,其他地方用不到。這時候,我們就該考慮是不是可以把這個類作為一個內(nèi)部類呢?而且我們把它作為一個內(nèi)部類以后,可以把它定義成一個私有類,然后將它的屬性公開,這樣省掉了那些無謂的get和set方法。下面我們就試試看:
public class ConnectPool implements Pool
{
        //存在Connection的數(shù)組
        private PoolConn[] poolConns;
        //連接池的最小連接數(shù)
        private int min;
        //連接池的最大連接數(shù)
        private int max;
        //一個連接的最大使用次數(shù)
        private int maxUseCount;
        //一個連接的最大空閑時間
        private long maxTimeout;
        //同一時間的Connection最大使用個數(shù)
        private int maxConns;
        //定時器
        private Timer timer;
        public boolean init()
        {
               try
               {
                      ……
                      this.poolConns = new PoolConn[this.min];
                      for(int i=0;i<this.min;i++)
                      {
                             PoolConn poolConn = new PoolConn();
                             poolConn.conn = ConnectionManager.getConnection();
                             poolConn.isUse = false;
                             poolConn.lastAccess = new Date().getTime();
                             poolConn.useCount = 0;
                             this.poolConns[i] = poolConn;
}
……
return true;
               }
               catch(Exception e)
               {
                      return false;
}
}
……
private class PoolConn
{
       public Connection conn;
       public boolean isUse;
public long lastAccess;
       public int useCount;
}
}
因為本文不是專題來講述數(shù)據(jù)庫連接池的,所以在上面的代碼中絕大部分的內(nèi)容被省略掉了。PoolConn類不大可能被除了ConnectionPool類的其他類使用到,把它作為ConnectionPool的私有內(nèi)部類不會影響到其他類。同時,我們可以看到,使用了內(nèi)部類,使得我們可以將該內(nèi)部類的數(shù)據(jù)公開,ConnectionPool類可以直接操作PoolConn類的數(shù)據(jù)成員,避免了因set和get方法帶來的麻煩。
上面的一個例子,是使用內(nèi)部類使得你的代碼得到簡化和方便。還有些情況下,你可能要避免你的類被除了它的外部類以外的類使用到,這時候你卻不得不使用內(nèi)部類來解決問題。
 
場景二:解決一些非面向?qū)ο蟮恼Z句塊
這些語句塊包括if…else if…else語句,case語句,等等。這些語句都不是面向?qū)ο蟮模o我們造成了系統(tǒng)的擴展上的麻煩。我們可以看看,在模式中,有多少模式是用來解決由if語句帶來的擴展性的問題。
Java編程中還有一個困擾我們的問題,那就是try…catch…問題,特別是在JDBC編程過程中。請看下面的代碼:
……
try
         {
                String[] divisionData = null;
                conn = manager.getInstance().getConnection();
                stmt = (OracleCallableStatement)conn.prepareCall("{ Call PM_GET_PRODUCT.HEADER_DIVISION(?, ?) }");
                stmt.setLong(1 ,productId.longValue() );
                stmt.registerOutParameter(2, oracle.jdbc.OracleTypes.CURSOR); ;
                stmt.execute();
                ResultSet rs = stmt.getCursor(2);
                int i = 0 ;
                String strDivision = "";
                while( rs.next() )
                {
                             strDivision += rs.getString("DIVISION_ID") + "," ;
                  }
                  int length = strDivision.length() ;
                  if(length != 0 )
                  {
                         strDivision = strDivision.substring(0,length - 1);
                  }
                  divisionData = StringUtil.split(strDivision, ",") ;
                  map.put("Division", strDivision ) ;
                  LoggerAgent.debug("GetHeaderProcess","getDivisionData","getValue + " + strDivision +" " + productId) ;
       }catch(Exception e)
        {
                       LoggerAgent.error("GetHeaderData", "getDivisionData",
                                                     "SQLException: " + e);
                       e.printStackTrace() ;
 
       }finally
        {
                       manager.close(stmt);
                       manager.releaseConnection(conn);
        }
這是我們最最常用的一個JDBC編程的代碼示例。一個系統(tǒng)有很多這樣的查詢方法,這段代碼一般分作三段:try關(guān)鍵字括起來的那段是用來做查詢操作的,catch關(guān)鍵字括起來的那段需要做兩件事,記錄出錯的原因和事務(wù)回滾(如果需要的話),finally關(guān)鍵字括起來的那段用來釋放數(shù)據(jù)庫連接。
我們的煩惱是:try關(guān)鍵字括起來的那段是變化的,每個方法的一般都不一樣。而catch和finally關(guān)鍵字括起來的那兩段卻一般都是不變的,每個方法的那兩段都是一樣的。既然后面那兩段是一樣的,我們就非常希望將它們提取出來,做一個單獨的方法,然后讓每一個使用到它們的方法調(diào)用。但是,try…catch…finally…是一個完整的語句段,不能把它們分開。這樣的結(jié)果,使得我們不得不在每一個數(shù)據(jù)層方法里重復的寫相同的catch…finally…這兩段語句。
既然不能將那些討厭的try…catch…finally…作為一個公用方法提出去,那么我們還是需要想其他的辦法來解決這個問題。不然我們老是寫那么重復代碼,真是既繁瑣,又不容易維護。
我們?nèi)菀紫氲剑热籧atch…finally…這兩段代碼不能提出來,那么我們能不能將try…里面的代碼提出去呢?唉喲,try…里面的代碼是可變的呢。怎么辦?
既然try…里面的代碼是可變的,這意味著這些代碼是可擴展的,是應該由用戶來實現(xiàn)的,對于這樣的可擴展內(nèi)容,我們很容易想到用接口來定義它們,然后由用戶去實現(xiàn)。這樣以來我們首先定義一個接口:
public interface DataManager
{
        public void manageData();
}
我們需要用戶在manageData()方法中實現(xiàn)他們對數(shù)據(jù)層訪問的代碼,也就是try…里面的代碼。
然后我們使用一個模板類來實現(xiàn)所有的try…catch…finally…語句的功能,如下:
public class DataTemplate
{
        public void execute(DataManager dm)
        {
               try
               {
                      dm.manageData();
}
catch(Exception e)
{
       LoggerAgent.error("GetHeaderData", "getDivisionData",
                        "SQLException: " + e);
       e.printStackTrace() ;
 
}finally
{
       manager.close(stmt);
       manager.releaseConnection(conn);
}
}
}
這樣,一個模板類就完成了。我們也通過這個模板類將catch…finally…兩段代碼提出來了。我們來看看使用了這個模板類的數(shù)據(jù)層方法是怎么實現(xiàn)的:
new DataTemplate().execute(new DataManager()
{
        public void manageData()
        {
                String[] divisionData = null;
                conn = manager.getInstance().getConnection();
                stmt = (OracleCallableStatement)conn.prepareCall("{ Call PM_GET_PRODUCT.HEADER_DIVISION(?, ?) }");
                stmt.setLong(1 ,productId.longValue() );
                stmt.registerOutParameter(2, oracle.jdbc.OracleTypes.CURSOR); ;
                stmt.execute();
                ResultSet rs = stmt.getCursor(2);
                int i = 0 ;
                String strDivision = "";
                while( rs.next() )
                {
                             strDivision += rs.getString("DIVISION_ID") + "," ;
}
                  int length = strDivision.length() ;
                  if(length != 0 )
                  {
                         strDivision = strDivision.substring(0,length - 1);
                  }
                  divisionData = StringUtil.split(strDivision, ",") ;
                  map.put("Division", strDivision ) ;
                  LoggerAgent.debug("GetHeaderProcess","getDivisionData","getValue + " + strDivision +" " + productId) ;
}
});
注意:本段代碼僅供思路上的參考,沒有經(jīng)過上機測試。
我們可以看到,正是這個實現(xiàn)了DataManager接口得匿名內(nèi)部類的使用,才使得我們解決了對try…catch…finally…語句的改造。這樣,第一為我們解決了令人痛苦的重復代碼;第二也讓我們在數(shù)據(jù)層方法的編碼中,直接關(guān)注對數(shù)據(jù)的操作,不用關(guān)心那些必需的但是與數(shù)據(jù)操作無關(guān)的東西。
我們現(xiàn)在來回想一下Spring框架的數(shù)據(jù)層,是不是正是使用了這種方法呢?
 
 
場景之三:一些多算法場合
假如我們有這樣一個需求:我們的一個方法用來對數(shù)組排序并且依次打印各元素,對數(shù)組排序方法有很多種,用哪種方法排序交給用戶自己確定。
對于這樣一個需求,我們很容易解決。我們決定給哪些排序算法定義一個接口,具體的算法實現(xiàn)由用戶自己完成,只要求他實現(xiàn)我們的接口就行。
public interface SortAlgor
{
        public void sort(int[] is);
}
這樣,我們再在方法里實現(xiàn)先排序后打印,代碼如下:
public void printSortedArray(int[] is,SortAlgor sa)
{
        ……
       sa.sort(is);
        for(int i=0;i<is.length;i++)
        {
               System.out.print(is[i]+” “);
}
System.out.println();
}
客戶端對上面方法的使用如下:
int[] is = new int[]{3,1,4,9,2};
printSortedArray(is,new SortAlgor()
{
        public void sort(is)
        {
               int k = 0;
               for(int i=0;i<is.length;i++)
               {
                     for(int j=i+1;j<is.length;j++)
                      {
                             if(is[i]>is[j])
                             {
                                    k = is[i];
                                    is[i] = is[j];
                                    is[j] = k;
                             }
                      }
               }
}
});
這樣的用法很多,我們都或多或少的被動的使用過。如在Swing編程中,我們經(jīng)常需要對組件增加監(jiān)聽器對象,如下所示:
spinner2.addChangeListener(new ChangeListener()
{
public void stateChanged(ChangeEvent e)
{
System.out.println("Source: " + e.getSource());
}
}
);
在Arrays包里,對元素為對象的數(shù)組的排序:
Arrays.sort(emps,new Comparator(){
        Public int compare(Object o1,Object o2)
        {
               return ((Employee)o1).getServedYears()-((Employee)o2).getServedYears();
}
});
這樣的例子還有很多,JDK教會了我們很多使用內(nèi)部類的方法。隨時我們都可以看一看API,看看還會在什么地方使用到內(nèi)部類呢?
 
 
 
場景之四:適當使用內(nèi)部類,使得代碼更加靈活和富有擴展性
適當?shù)氖褂脙?nèi)部類,可以使得你的代碼更加靈活和富有擴展性。當然,在這里頭起作用的還是一些模式的運行,但如果不配以內(nèi)部類的使用,這些方法的使用效果就差遠了。不信?請看下面的例子:
我們記得簡單工廠模式的作用就是將客戶對各個對象的依賴轉(zhuǎn)移到了工廠類里。很顯然,簡單工廠模式并沒有消除那些依賴,只是簡單的將它們轉(zhuǎn)移到了工廠類里。如果有新的對象增加進來,則我們需要修改工廠類。所以我們需要對工廠類做進一步的改造,進一步消除它對具體類的依賴。以前我們提供過一個使用反射來消除依賴的方法;這里,我們將提供另外一種方法。
這種方法是將工廠進一步抽象,而將具體的工廠類交由具體類的創(chuàng)建者來實現(xiàn),這樣,工廠類和具體類的依賴的問題就得到了解決。而工廠的使用者則調(diào)用抽象的工廠來獲得具體類的對象。如下。
我們以一個生產(chǎn)形體的工廠為例,下面是這些形體的接口:
package polyFactory;
 
public interface Shape {
public void draw();
public void erase();
 
}
 
通過上面的描述,大家都可能已經(jīng)猜到,這個抽象的工廠肯定使用的是模板方法模式。如下:
package polyFactory;
 
import java.util.HashMap;
import java.util.Map;
 
 
public abstract class ShapeFactory {
protected abstract Shape create();
private static Map factories = new HashMap();
public static void addFactory(String id,ShapeFactory f)
{
       factories.put(id,f);
}
public static final Shape createShape(String id)
{
       if(!factories.containsKey(id))
        {
               try
               {
                      Class.forName("polyFactory."+id);
               }
               catch(ClassNotFoundException e)
               {
                      throw new RuntimeException("Bad shape creation : "+id);
               }
        }
        return ((ShapeFactory)factories.get(id)).create();
}
}
不錯,正是模板方法模式的運用。這個類蠻簡單的:首先是一個create()方法,用來產(chǎn)生具體類的對象,留交各具體工廠實現(xiàn)去實現(xiàn)。然后是一個Map類型的靜態(tài)變量,用來存放具體工廠的實現(xiàn)以及他們的ID號。接著的一個方法使用來增加一個具體工廠的實現(xiàn)。最后一個靜態(tài)方法是用來獲取具體對象,里面的那個Class.forName……的作用是調(diào)用以ID號為類名的類的一些靜態(tài)的東西。
下面,我們來看具體的類的實現(xiàn):
package polyFactory;
 
public class Circle implements Shape {
 
 
public void draw() {
        // TODO Auto-generated method stub
       System.out.println("the circle is drawing...");
}
 
 
public void erase() {
        // TODO Auto-generated method stub
       System.out.println("the circle is erasing...");
}
private static class Factory extends ShapeFactory
{
       protected Shape create()
        {
               return new Circle();
        }
}
static {ShapeFactory.addFactory("Circle",new Factory());}
 
}
這個類的其他的地方也平常得很。但就是后面的那個內(nèi)部類Factory用得好。第一呢,這個類只做一件事,就是產(chǎn)生一個Circle對象,與其他類無關(guān),就這一個條也就滿足了使用內(nèi)部類的條件。第二呢,這個Factory類需要是靜態(tài)的,這也得要求它被使用內(nèi)部類,不然,下面的ShapeFacotry.addFactory就沒辦法add了。而最后的那個靜態(tài)的語句塊是用來將具體的工廠類添加到抽象的工廠里面去。在抽象工廠里調(diào)用Class.forName就會執(zhí)行這個靜態(tài)的語句塊了。
下面仍然是一個具體類:
package polyFactory;
 
 
public class Square implements Shape {
 
public void draw() {
        // TODO Auto-generated method stub
       System.out.println("the square is drawing...");
}
 
public void erase() {
        // TODO Auto-generated method stub
       System.out.println("the square is erasing...");
}
private static class Factory extends ShapeFactory
{
       protected Shape create()
        {
               return new Square();
        }
}
static {ShapeFactory.addFactory("Square",new Factory());}
 
}
最后,我們來測試一下:
String[] ids = new String[]{"Circle","Square","Square","Circle"};
        for(int i=0;i<ids.length;i++)
        {
               Shape shape = ShapeFactory.createShape(ids[i]);
               shape.draw();
               shape.erase();
        }
測試結(jié)果為:
the circle is drawing...
the circle is erasing...
the square is drawing...
the square is erasing...
the square is drawing...
the square is erasing...
the circle is drawing...
the circle is erasing...
       這個方法是巧妙地使用了內(nèi)部類,將具體類的實現(xiàn)和它的具體工廠類綁定起來,由具體類的實現(xiàn)者在這個內(nèi)部類的具體工廠里去產(chǎn)生一個具體類的對象,這當然容易得多。雖然需要每一個具體類都創(chuàng)建一個具體工廠類,但由于具體工廠類是一個內(nèi)部類,這樣也不會隨著具體類的增加而不斷增加新的工廠類,使得代碼看起來很臃腫,這也是本方法不得不使用內(nèi)部類的一個原因吧。


劉錚 2007-10-22 15:59 發(fā)表評論
]]>
有關(guān)類中的重構(gòu)問題http://www.aygfsteel.com/liuzheng/articles/153827.html劉錚 劉錚 Thu, 18 Oct 2007 04:07:00 GMThttp://www.aygfsteel.com/liuzheng/articles/153827.htmlhttp://www.aygfsteel.com/liuzheng/comments/153827.htmlhttp://www.aygfsteel.com/liuzheng/articles/153827.html#Feedback0http://www.aygfsteel.com/liuzheng/comments/commentRss/153827.htmlhttp://www.aygfsteel.com/liuzheng/services/trackbacks/153827.html
例如:
public class Bookshelf {
private int capacity = 20;
private Collection content;
public void add(Book book) {
if(content.size() + 1 <= capacity)
{
content.add(book);
} else {
throw new
IllegalOperationException(
“The bookshelf has reached
its limit.”);
}
}
}
We can refactor the code, extracting the constraint in a separate
method.
public class Bookshelf {
private int capacity = 20;
private Collection content;
public void add(Book book) {
if(isSpaceAvailable()) {
content.add(book);
} else {
throw new
IllegalOperationException(
“The bookshelf has reached
its limit.”);
}
}
private boolean isSpaceAvailable() {
return content.size() < capacity;
}
}

劉錚 2007-10-18 12:07 發(fā)表評論
]]>
在java中使用DOM對XML的解析http://www.aygfsteel.com/liuzheng/articles/153013.html劉錚 劉錚 Mon, 15 Oct 2007 08:22:00 GMThttp://www.aygfsteel.com/liuzheng/articles/153013.htmlhttp://www.aygfsteel.com/liuzheng/comments/153013.htmlhttp://www.aygfsteel.com/liuzheng/articles/153013.html#Feedback0http://www.aygfsteel.com/liuzheng/comments/commentRss/153013.htmlhttp://www.aygfsteel.com/liuzheng/services/trackbacks/153013.html
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();

You can now read a document from a file:

File f = . . .
Document doc = builder.parse(f);

Alternatively, you can use a URL:

URL u = . . .
Document doc = builder.parse(u);

You can even specify an arbitrary input stream:

InputStream in = . . .
Document doc = builder.parse(in);

Element root = doc.getDocumentElement();

注意如果使用這種解析方法的話:
會有空格產(chǎn)生
NodeList children = root.getChildNodes();
for (int i = 0; i < children.getLength(); i++)
{
Node child = children.item(i);
. . .
}

如果避免空格產(chǎn)生


If you expect only subelements, then you can ignore the whitespace:

for (int i = 0; i < children.getLength(); i++)
{
Node child = children.item(i);
if (child instanceof Element)
{
Element childElement = (Element) child;
. . .
}
}

      Text textNode = (Text) childElement.getFirstChild();
      String text = textNode.getData().trim();
getData()方法可以得到textNode中的值



劉錚 2007-10-15 16:22 發(fā)表評論
]]>
分頁通用技術(shù)http://www.aygfsteel.com/liuzheng/articles/145904.html劉錚 劉錚 Mon, 17 Sep 2007 08:41:00 GMThttp://www.aygfsteel.com/liuzheng/articles/145904.htmlhttp://www.aygfsteel.com/liuzheng/comments/145904.htmlhttp://www.aygfsteel.com/liuzheng/articles/145904.html#Feedback0http://www.aygfsteel.com/liuzheng/comments/commentRss/145904.htmlhttp://www.aygfsteel.com/liuzheng/services/trackbacks/145904.html首先聲明以下是轉(zhuǎn)載的,感謝原作者

通用分頁實現(xiàn)及其OO設(shè)計探討

本來是打算拿到it168投稿的!!那邊的速度太慢了!先貼出來先!!

分頁是一種常用的頁面數(shù)據(jù)顯示技術(shù),分頁能夠通過減少頁面數(shù)據(jù)處理量從而提高了系統(tǒng)的性能。分頁應該是做WEB開發(fā)必須掌握的一個小技術(shù)。而分頁卻是復雜的,倒不是它的技術(shù)有多復雜;而是有太多的重復代碼,這些代碼都難以重用。能不能實現(xiàn)一個通用的分頁框架?每次只需要去覆寫一兩個方法,通過少量的代碼就能實現(xiàn)分頁的功能?

一般分頁應該要具有的功能有
1. 靈活的設(shè)置分頁大小。可以動態(tài)的設(shè)置分頁大小,而不是寫死到代碼中。
2. 自動計算總頁數(shù)。根據(jù)分頁大小和總記錄數(shù)自動計算總頁數(shù)。
3. 獲得當前頁的頁號。
4. 獲得當前頁的總記錄數(shù)。一般是最后一頁的時候可能會小于分頁大小。
5. 判斷當前頁是否為第一頁。
6. 判斷當前頁是否為最后一頁。
7. 判斷當前頁是否有上一頁。
8. 判斷當前頁是否有下一頁。
9. 獲得當前頁的數(shù)據(jù)列表。
10. 獲得當前頁的第一條記錄的索引號
11. 獲得當前頁的最后一條記錄的索引號。
二、常用的分頁技術(shù)
目前常用的分頁技術(shù)有兩種:
1. 第一次訪問是讀取所有記錄,放入session中,然后每次從session對象中讀取當前頁的數(shù)據(jù)
2. 每次都訪問數(shù)據(jù)庫,從數(shù)據(jù)庫中讀取當前頁的記錄。
這兩種方法都各有優(yōu)缺點,當數(shù)據(jù)量比較少時,第一種方法無疑是要快一些,因為減少與數(shù)據(jù)庫的連接訪問。而當數(shù)據(jù)量比較大時,比如查詢結(jié)果可能會是上萬條,那么內(nèi)存的開銷是十分大的,放到session中還有一個問題是能不能及時的清除無用的對象。而且這么大數(shù)據(jù)量在網(wǎng)絡(luò)中傳輸也會使系統(tǒng)變得很慢。
第二種方法就是專門解決這個問題的,它每次訪問數(shù)據(jù)庫,只讀取當前頁所需的記錄,大大的減少網(wǎng)絡(luò)傳輸量;它不會把頁數(shù)據(jù)放到session中,大大提高服務(wù)器的性能。
所以第二種方式要優(yōu)于第一種方法。Session不要亂用,要用也僅僅是存放一些公共變量,相對于占用空間比較少的對象。不適合存放大量的數(shù)據(jù),否則在很多個用戶同時訪問時那么系統(tǒng)會很慢,因為服務(wù)器內(nèi)存被銷耗的很厲害

三、通用分頁框架需要解決的問題
作為一個通用分頁框架,
1. 應該不依賴于任何其它框架
2. 應該支持多種數(shù)據(jù)庫
3. 應該可以應用于任何web框架中,如:struts,spring等。
4. 應該把數(shù)據(jù)訪問的具體實現(xiàn)留給用戶去實現(xiàn)。
5. 應該實現(xiàn)關(guān)鍵的算法和過程,如:計算總頁數(shù),所需的實始化動作。
6. 應該減化Contrller控制器的代碼,以往的分頁技術(shù)在Contrller中存在太多的if…else代碼。十分難懂,應該由一個輔助類來實現(xiàn)。
7. 應該減化jsp頁面的代碼,頁面應該沒有任何與分頁相關(guān)的計算。應該由分頁對象來實現(xiàn)。
8. 應該支持兩種分頁方式,采用session或不采用session由用戶控制。

四、具體實現(xiàn)
1.通用分頁接口。定義接口可以有更多不同的實現(xiàn),接口只聲明了分頁應該具有的公共行為。
ViewPage.java
/**
* 分頁接口
* @author ex_yuanguangdong
*
*/
public interface ViewPage {



/**
* 獲取總頁數(shù)
* @return 總頁數(shù)
*/
public int getPageCount();


/**
* 獲得頁面大小
* @return 頁面大小
*/
public int getPageSize();


/**
* 設(shè)置頁面大小
* @param size
*/
public void setPageSize(int size);
/**
* 獲得當前頁數(shù)據(jù)
* @return 數(shù)據(jù)列表
*/
public List getPageData();


/**
* 獲得當前頁索引號
* @return 當前頁索引號
*/
public int getPageIndex();

/**
* 獲得當前頁記錄總數(shù)
* @return 當前頁記錄總數(shù)
*/
public int getPageRows();

/**
* 是否有下一頁
* @return
*/
public boolean getHashNextPage();


/**
* 是否有上一頁
* @return
*/
public boolean getHashPreviousPage();

/**
* 轉(zhuǎn)到尾頁
*
*/
public void gotoLastPage();
/**
* 轉(zhuǎn)到首頁
*
*/
public void gotoFirstPage();

/**
* 是否首頁
* @return
*/
public boolean isFirstPage();

/**
* 是否尾頁
* @return
*/
public boolean isLastPage();

/**
* 轉(zhuǎn)到上一頁
*
*/
public void gotoPreviousPage();

/**
* 轉(zhuǎn)到下一頁
*
*/
public void gotoNextPage();

/**
* 轉(zhuǎn)到指定頁面,pageIndex小于1時,轉(zhuǎn)到第一頁;pageIndex大于總頁數(shù)時,轉(zhuǎn)到最尾頁
* @param pageIndex 指定的頁號
*/
public void gotoPage(int pageIndex);

/**
* 獲取當前頁第一條記錄的記錄號
* @return int 當前頁第一條記錄的記錄號
*/
public int getPageFirstRecord();

/**
* 獲取當前頁最后一條記錄的記錄號
* @return int 當前頁最后一條記錄的記錄號
*/
public int getPageLastRecord();

}

2. 分頁抽像實現(xiàn)類,實現(xiàn)關(guān)鍵的算法
AbstractViewPage.java
/**
* 分頁默認抽象實現(xiàn)
* 初始時,分頁類有下列默認值:
* 分頁大小為-1,為不分頁;
* 總頁數(shù)為1頁
* 當前頁為第一頁
* 總記錄數(shù)為0條
* 當前頁數(shù)據(jù)列表為沒有任何記錄的列表
* @author ex_yuanguangdong
*
*/
public abstract class AbstractViewPage implements ViewPage {

//-----------------------------------------
//私有靜態(tài)常量
//-----------------------------------------

private static final int DEFAULT_PAGE_INDEX = 1;

private static final int DEFALT_PAGE_COUNT = 1;

private static final int DEFAULT_PAGE_SIZE = -1;

private static final int DEFAULT_ROWS = 0;

//-----------------------------------------
//私有成員變量
//-----------------------------------------

/**當前頁索引號**/
private int pageIndex = DEFAULT_PAGE_INDEX;
/**總頁數(shù)**/
private int pageCount =DEFALT_PAGE_COUNT;

/**分頁大小**/
private int pageSize = DEFAULT_PAGE_SIZE ;

/**數(shù)據(jù)總記錄數(shù)**/
private int rows = DEFAULT_ROWS;


//------------------------------------------
//本地成員變量getter,setter方法
//------------------------------------------


/**
* 設(shè)置新頁號,只有大于等于1而且小于等于總頁數(shù)并且不為當前頁時,才允許設(shè)置
* @param pageIndex The pageIndex to set.
*/
private void setPageIndex(int newPageIndex) {

if( newPageIndex >= this.DEFAULT_PAGE_INDEX && newPageIndex <= this.getPageCount() && newPageIndex != this.pageIndex) {
this.pageIndex = newPageIndex;
}

}

/**
* @return Returns the rows.
*/
private int getRows() {
return rows;
}

/**
* @param rows The rows to set.
*/
private void setRows(int rows) {
this.rows = rows;
}
/**
* @param pageCount The pageCount to set.
*/
private void setPageCount(int pageCount) {
this.pageCount = pageCount;
}



//--------------------------------------
//實現(xiàn)Page接口方法
//--------------------------------------


/**
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#getPageData()
*/
public List getPageData() {
List pageList =null;

//獲得當前頁數(shù)據(jù)
pageList = this.pageList(this.getPageFirstRecord(), this.getPageRows());
//保證不返回null
if(pageList == null) {
pageList =new ArrayList();
}
return pageList;

}

/**
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#getPageIndex()
*/
public int getPageIndex() {
return this.pageIndex;
}
/**
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#isFirstPage()
*/
public boolean isFirstPage() {

return this.DEFAULT_PAGE_INDEX ==this.pageIndex;
}
/**
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#isLastPage()
*/
public boolean isLastPage() {
//當前頁索引為總頁數(shù)時為最后一頁
return this.pageIndex == this.pageCount;
}

/**
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#getHashNextPage()
*/
public boolean getHashNextPage() {
//當前頁索引號小于總頁數(shù)
return this.pageIndex < this.pageCount ;
}

/**
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#getHashPreviousPage()
*/
public boolean getHashPreviousPage() {
//當前頁索引號大于默認的初始頁號,這里為1
return this.pageIndex > this.DEFAULT_PAGE_INDEX ;
}



/**
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#getPageCount()
*/
public int getPageCount() {

return this.pageCount;
}



/**
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#getPageSize()
*/
public int getPageSize() {

return this.pageSize;
}

/**
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#getPageRows()
*/
public int getPageRows() {
//當頁面大小為-1 時,返回總記錄數(shù)
if(this.DEFAULT_PAGE_SIZE == this.pageSize ) {
return this.rows;
}

//不為最后一頁時,返回pageSize
if(!this.isLastPage()) {
return this.pageSize;
}
//最后一頁時
return this.rows - (this.pageSize * (this.pageCount -1));
}



/**
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#getPageFirstRecord()
*/
public int getPageFirstRecord() {

//頁大小為-1 時
if(this.DEFAULT_PAGE_SIZE== this.pageSize ) {
return 0;
}
return (this.pageIndex -1)* this.pageSize;
}

/**
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#getPageLastRecord()
*/
public int getPageLastRecord() {
//頁大小為-1時,返回總記錄數(shù)
if(this.DEFAULT_PAGE_SIZE == this.pageSize) {
return this.rows;
}
return this.getPageFirstRecord() + this.getPageRows() ;
}
/**
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#gotoFirstPage()
*/
public void gotoFirstPage() {
this.gotoPage(this.DEFAULT_PAGE_INDEX);

}

/**
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#gotoLastPage()
*/
public void gotoLastPage() {
this.gotoPage(this.getPageCount());

}

/**
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#gotoPreviousPage()
*/
public void gotoPreviousPage() {
this.gotoPage(this.getPageIndex() -1);

}

/**
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#gotoNextPage()
*/
public void gotoNextPage() {
this.gotoPage(this.getPageIndex() + 1);

}

/**
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#gotoPage(int)
*/
public void gotoPage(int newPageIndex) {
if( newPageIndex >= this.DEFAULT_PAGE_INDEX && newPageIndex <= this.getPageCount() ) {
this.setPageIndex(newPageIndex);
}

}
/**
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#setPageSize(int)
*/
public void setPageSize(int size) {
if(size < 1) {
size = 1;
}

this.pageSize = size;

//進行初始化
this.doInit();
}

//-----------------------------------
//輔助方法
//-----------------------------------


/**
* 分頁初始化方法,為了保證總是能正確的初始化,所以聲明為final ,為了讓子類可以調(diào)用聲明為protected
*
*/
protected final void doInit() {
int rows = 0;

//獲得總記錄數(shù)
rows= totalRows();

//設(shè)置總記錄數(shù)
this.setRows(rows);
//設(shè)置新的總頁數(shù)

//計算并設(shè)置總頁數(shù)
int pages = calculatePageCount();
this.setPageCount(pages);

//轉(zhuǎn)到第一頁
this.gotoPage(this.DEFAULT_PAGE_INDEX);

onInit();
}
/**
* 記算總頁數(shù)
* @return 總頁數(shù)
*/
private int calculatePageCount() {

//總記錄數(shù)為0條,則返回的總頁數(shù)為1
if(this.getRows() == 0) {
return this.DEFALT_PAGE_COUNT;
}

//如果頁面大小為-1,則返回的總頁數(shù)為1
if(this.DEFAULT_PAGE_SIZE == this.getPageSize() ) {
return this.DEFALT_PAGE_COUNT;
}

return this.getRows() / this.getPageSize() + ( this.getRows() % this.getPageSize() ==0 ? 0 :1);
}


/**
* 獲得總記錄數(shù),調(diào)用queryTotalRows(),將異常封裝為non-checked 異常
* @return 總記錄數(shù)
* @throws ApplicationRuntimeException
*/
private int totalRows() throws ApplicationRuntimeException{
try{
return queryTotalRows();
}
catch(Exception ex){
throw new ApplicationRuntimeException(ex);
}
}
/**
* 獲得當前頁數(shù)據(jù),調(diào)用queryPageList()方法,將異常封裝為non-checked異常
* @param startRow 開始記錄號
* @param rowCount 記錄總數(shù)
* @return 當前頁數(shù)據(jù)
* @throws ApplicationRuntimeException
*/
private List pageList(int startRow, int rowCount) throws ApplicationRuntimeException{
try{
return queryPageList(startRow, rowCount);
}catch(Exception ex){
throw new ApplicationRuntimeException(ex);
}
}


//-----------------------------------------
//子類實現(xiàn)的方法
//-----------------------------------------

/**
* 初始化附加方法,由子類擴展
*/
protected void onInit() {

}


/**
* 查詢獲得總記錄數(shù),由子類具體實現(xiàn)
* @return 總記錄數(shù)
* @throws Exception
*/
protected abstract int queryTotalRows() throws Exception;

/**
* 查詢當前頁數(shù)據(jù),從startRow 開始的rowCount條記錄
* @param startRow 開始記錄號
* @param rowCount 記錄總數(shù)
* @return 當前頁數(shù)據(jù)
* @throws Exception
*/
protected abstract List queryPageList(int startRow, int rowCount) throws Exception;

}

3. 分頁輔助類
ViewPageHelper.java/**
* 分頁輔助類,用于減化Controller中的代碼
* @author yuanguangdong
* date: Oct 22, 2006
*/
public class ViewPageHelper {
private static final int FIRST_PAGE_VALUE = 1;

private static final int PREVIOUS_PAGE_VALUE = 2;

private static final int NEXT_PAGE_VALUE = 3;

private static final int LAST_PAGE_VALUE = 4;

private static final int SPECIAL_PAGE_VALUE = 5;

public static final String FIRST_PAGE = "FIRST_PAGE";

public static final String PREVIOUS_PAGE = "PREVIOUS_PAGE";

public static final String NEXT_PAGE = "NEXT_PAGE";

public static final String LAST_PAGE = "LAST_PAGE";

public static final String SPECIAL_PAGE = "SPECIAL_PAGE";

/**分頁動作參數(shù)名**/
public static final String PAGE_ACTION = "page_action";

/**分頁對象屬性名**/
public static final String SESSION_PAGE = "session_page";

/**頁號參數(shù)名**/
public static final String PAGE_NO = "page_no";

private static Map actionMap = new HashMap();
static {
actionMap.put(FIRST_PAGE, new Integer(FIRST_PAGE_VALUE));
actionMap.put(PREVIOUS_PAGE, new Integer(PREVIOUS_PAGE_VALUE));
actionMap.put(NEXT_PAGE, new Integer(NEXT_PAGE_VALUE));
actionMap.put(LAST_PAGE, new Integer(LAST_PAGE_VALUE));
actionMap.put(SPECIAL_PAGE, new Integer(SPECIAL_PAGE_VALUE));
}
/**
* 執(zhí)行分頁動作
* @param page 分頁對象
* @param action 分頁動作參數(shù)
* @param pageIndex 頁號
*/
public static void doAction(ViewPage page, String action, int pageIndex) {
int actionIndex = 0;
if (page == null) {
throw new NullPointerException("Page對象null");
}
if (action == null || "".equals(action)) {
throw new IllegalArgumentException("無效的分頁動作參數(shù)null");
}
action = action.toUpperCase();
if (!actionMap.containsKey(action)) {
throw new UnsupportedOperationException("不支持的分頁動作參數(shù):" + action);
}
Integer index = (Integer) actionMap.get(action);
actionIndex = index.intValue();
switch (actionIndex) {
case FIRST_PAGE_VALUE:
page.gotoFirstPage();
break;
case PREVIOUS_PAGE_VALUE:
page.gotoPreviousPage();
break;
case NEXT_PAGE_VALUE:
page.gotoNextPage();
break;
case LAST_PAGE_VALUE:
page.gotoLastPage();
break;
case SPECIAL_PAGE_VALUE:
page.gotoPage(pageIndex);
}
}

public static void doAction(ViewPage page, String action){
doAction(page, action, 1);
}
}

五、應用通用分頁框架
1.繼承AbstractViewPage類,實現(xiàn)queryPageList(int startRow, int endRow)和
queryTotalRows()方法。

protected int queryTotalRows() throws Exception
獲得查詢條件的總記錄數(shù)

protected List queryPageList(int startRow, int rowCount)
用于查詢指定范圍的數(shù)據(jù)。startRow為開始記錄號, rowCount為查詢的記錄數(shù)

queryPageList(0,20)為查詢從第一條開始的20條記錄。

使用Ibatis可以由queryPageList調(diào)用queryForList()方法。

/**
* 用戶信息分頁內(nèi)部類
* @author yuanguangdong
* date: Oct 22, 2006
*/
class UserInfoPage extends AbstractViewPage{

//------------------------------------------------
//實現(xiàn)AbstractViewPage抽象類的抽象方法
//------------------------------------------------

/**
* @see com.prs.application.ehld.web.mvc.AbstractViewPage#getPageDate(int, int)
*/
protected List queryPageList(int startRow, int endRow) throws Exception {
return sampleAction.getUserInfoList(startRow, endRow);
}

/**
* @see com.prs.application.ehld.web.mvc.AbstractViewPage#getRows()
*/
protected int queryTotalRows() throws Exception {
return sampleAction.getUserCount();
}

}



3. 在Contrller中的實現(xiàn)
public ModelAndView listUser(HttpServletRequest request,
HttpServletResponse response) throws Exception {
String pageAction =
RequestUtils.getStringParameter(request,ViewPageHelper.PAGE_ACTION);
Integer pageIndex =
RequestUtils.getIntParameter(request,ViewPageHelper.PAGE_NO);
//聲明分頁對象
ViewPage userPage =
(ViewPage) request.getSession().getAttribute(ViewPageHelper.SESSION_PAGE);
//第一次請求
if(pageAction == null || userPage == null){
//構(gòu)建一個新的分頁對象
userPage = new UserInfoPage();
//設(shè)置分頁大小
userPage.setPageSize(2);
}else{

if(ViewPageHelper.SPECIAL_PAGE.equals(pageAction)){
//如果頁數(shù)為空,則默認為1
if (pageIndex == null)
pageIndex = new Integer(1);
ViewPageHelper.doAction(userPage,pageAction,pageIndex.intValue());
}else{
ViewPageHelper.doAction(userPage,pageAction);
}
}

//從分頁對象中獲得當前頁數(shù)據(jù)
List userInfoList = userPage.getPageData();

ModelAndView mav = new ModelAndView(userInfoListView);
mav.addObject(this.userInfoListKey,userInfoList);
request.getSession().setAttribute(ViewPageHelper.SESSION_PAGE,userPage);
return mav;
}

4. jsp頁面實現(xiàn)

<%@ page contentType="text/html;charset=utf-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt" %>
<%@ taglib prefix="tiles" uri="http://jakarta.apache.org/struts/tags-tiles" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<html>
<head>
<title>顯示所有員工</title>

<SCRIPT language="javaScript">
function pageNoChange(pageNo){
location.href= "ehld.sample.getuserinfolist.do?page_action=SPECIAL_PAGE&page_no="+pageNo.value;

}
</SCRIPT>
</head>

<body>
<table width="80%" border="0">
<tr>
<td bgcolor="#F0FEFF"><div align="left">  用戶列表</div></td>
</tr>
</table>
<br>
<input name="adduser" type="submit" id="adduser" value="新增用戶" onclick="location.href='ehld.sample.edituserinfo.do'">
<table width="80%" border="0">
<tr bgcolor="#58ED64">
<th width="25%">id</th>
<th width="34%">姓名</th>
<th colspan="2">操作</th>
</tr>
<c:forEach items="${userInfoList}" var="userInfoDTO">
<tr bgcolor="#D6EBF8">
<td><c:out value="${userInfoDTO.userID}"/></td>
<td><c:out value="${userInfoDTO.userName}"/></td>
<td width="21%"><a href="ehld.sample.edituserinfo.do?id=<c:out value='${userInfoDTO.userID}'/>">編輯</a></td>
<td width="20%"><a href="#">刪除</a></td>
</tr>
</c:forEach>
</table>
<c:if test="${session_page.firstPage}">
首頁
</c:if>
<c:if test="${! session_page.firstPage}">
<a href="ehld.sample.getuserinfolist.do?page_action=FIRST_PAGE">首頁</a>
</c:if>
<c:if test="${! session_page.hashPreviousPage}">
上一頁
</c:if>
<c:if test="${session_page.hashPreviousPage}">
<a href="ehld.sample.getuserinfolist.do?page_action=PREVIOUS_PAGE">上一頁</a>
</c:if>

<c:if test="${!session_page.hashNextPage}">
下一頁
</c:if>

<c:if test="${session_page.hashNextPage}">
<a href="ehld.sample.getuserinfolist.do?page_action=NEXT_PAGE">下一頁</a>
</c:if>

<c:if test="${session_page.lastPage}">
尾頁
</c:if>

<c:if test="${!session_page.lastPage}">
<a href="ehld.sample.getuserinfolist.do?page_action=LAST_PAGE">尾頁</a>
</c:if>

共有<c:out value="${session_page.pageCount}" />頁,第

<select name = "pageNo" onChange = "java script:pageNoChange(this);">
<c:forEach begin="1" end = "${session_page.pageCount}" var = "pageIndex">
<option value="<c:out value='${pageIndex}'/>" <c:if test = "${pageIndex ==session_page.pageIndex }">selected</c:if>>
<c:out value="${pageIndex}"/>
</option>
</c:forEach>
</select>

</body>
</html>

六、設(shè)計探討
1.通過提供queryTotalRows() 和queryPageList(int startRow, int rowCount)方法,交由用戶具體的去實現(xiàn),所以能夠支持任何數(shù)據(jù)庫。
對于Ibatis用戶可以使用queryForList()方法,對于用jdbc實現(xiàn)也可以有多種方法來支持各種數(shù)據(jù)庫。
Ms sql 可以使用top 關(guān)鍵字,來獲得指定范圍的數(shù)據(jù)
ORACEL可以使用rowid 偽列來獲得指定范圍的數(shù)據(jù)
具體怎么去讀取數(shù)據(jù),完全交由用戶控制
2.分頁對象與具體的業(yè)務(wù)對象分離。分頁對象如果不能與具體的業(yè)務(wù)對象分離那么就不可能實現(xiàn)分頁對象的重用,不可以實現(xiàn)代碼的最大的重用。這不符合oo的按職責來設(shè)計對象的原則。
3. ViewPageHelper幫助類的使用有兩個好處,統(tǒng)一為分頁代碼所需的字符參數(shù)進行定義,便于contrller和jsp頁面代碼的維護。第二便于代碼重用,減少在contrller中的if分支句語。如果不使用幫助類,則在每個controller中都會產(chǎn)生大量相同的代碼。
4. final關(guān)鍵字的使用,protected final void doInit()用于分頁對象的實始化,它讀取并設(shè)置總記錄數(shù),計算總頁數(shù),默認為第一頁等。為什么不在構(gòu)造函數(shù)中來做它呢?如果在構(gòu)造函數(shù)來做它,子類就不可以擴展了。像這樣的初始化方法的位置應該由擴展類來靈活控制。聲明為protected是不讓它由外部對象來進行訪問,但是子類又可以進行調(diào)用。聲明為final是為了子類不能重寫它,如果子類重寫不當就會造成分頁對象的執(zhí)行邏輯錯誤。但是如果子類又想擴展它怎么辦?子類重寫protected void onInit()方法就可以了。這樣就能保證父類的邏輯,又能夠讓子類進行擴展。
5.異常處理的思考,queryTotalRows()和queryPageList方法都是要求由子類實現(xiàn)的抽象類,這兩個類的特點都是可能會調(diào)用業(yè)務(wù)對象去實現(xiàn)相應的功能,業(yè)務(wù)對象可能會訪問業(yè)務(wù)數(shù)據(jù)庫等,可能會拋出任何Exception,但是分頁對象類去調(diào)用queryTotalRows()和queryPageList的方法是不應該對這些Exception進行任何處理的,如果進行try…catch那么就會隱藏了異常的細節(jié),這是十分可怕的。如果這些方法拋出異常,分頁對象應該是不能處理的,不能處理的異常應該封裝為運行時異常,所以就有了下面的實現(xiàn)
private List pageList(int startRow, int rowCount) throws ApplicationRuntimeException{
try{
return queryPageList(startRow, rowCount);
}catch(Exception ex){
throw new ApplicationRuntimeException(ex);
}
}

private int totalRows() throws ApplicationRuntimeException{
try{
return queryTotalRows();
}
catch(Exception ex){
throw new ApplicationRuntimeException(ex);
}
}

分頁對象內(nèi)部調(diào)用pageList和totalRows方法,這樣就很好的解決了異常的問題,把異常交由外部調(diào)用者去決定是否處理,而不是強制調(diào)用者去處理。

5. 模板方法模式的使用,這是一個典型的模板方法模式的運用。在父類實現(xiàn)關(guān)鍵的算法代碼,實現(xiàn)分頁對象的處理邏輯,而把某些會發(fā)生改變的方法交由子類去實現(xiàn),使得子類完全不用去關(guān)心父類的實現(xiàn)細節(jié),子類只需要重寫兩個簡單的方法就可以實現(xiàn)父類的功能。這就是模板方法帶來的最大好處。模板方法模式在各種開源框架中有著廣泛的運用,看看spring的源碼就知道。子類只需要去實現(xiàn)自己最關(guān)心的細節(jié),而父類實現(xiàn)那些不變的邏輯或算法。
6. 針對接口編程,而不是針對類編程。接口可以實現(xiàn)多重繼承,而類卻不能。接口有比類獲得更多的好處,更利于擴展。比如說分頁接口,它可以讓用戶有更多不同的實現(xiàn),完全不依賴于任何類。只需要為它定制了共同的行為就可以了。在使用委托的時候接口比抽像類更好用。比如在裝飾模式的使用中,可能需要實現(xiàn)一個接口,而其中還要有一個本接口的引用。 如果是抽象類,則不可以實現(xiàn)。
7. 通用框架應該具有靈活性,不應該依懶于任何具體的框架。如果通用框架依懶于某一技術(shù)細節(jié),某一框架,那么它就有一定的局限性。所以通用分頁不應該依懶于ibatis或hibernate 或spring的某一特點。更不應該依懶于sql或oralce某種數(shù)據(jù)庫。



劉錚 2007-09-17 16:41 發(fā)表評論
]]>
java中inputstream的有關(guān)類的設(shè)計模式-the decorator patternhttp://www.aygfsteel.com/liuzheng/articles/144443.html劉錚 劉錚 Wed, 12 Sep 2007 04:02:00 GMThttp://www.aygfsteel.com/liuzheng/articles/144443.htmlhttp://www.aygfsteel.com/liuzheng/comments/144443.htmlhttp://www.aygfsteel.com/liuzheng/articles/144443.html#Feedback0http://www.aygfsteel.com/liuzheng/comments/commentRss/144443.htmlhttp://www.aygfsteel.com/liuzheng/services/trackbacks/144443.htmljava中inputstream的有關(guān)類的設(shè)計模式-the decorator pattern

inputstream中比較重要的decorator----BufferedInputStream
它的構(gòu)造函數(shù)為BufferedInputStream(InputStream in)
BufferedInputStream(InputStream in, int size)


可以裝飾繼承了inputsream類的類

自己完成的新的inputstream
public class LowerCaseInputStream extends FilterInputStream {
public LowerCaseInputStream(InputStream in) {
super(in);
}
public int read() throws IOException {
int c = super.read();
return (c == -1 ? c : Character.toLowerCase((char)c));
}
public int read(byte[] b, int offset, int len) throws IOException {
int result = super.read(b, offset, len);
for (int i = offset; i < offset+result; i++) {
b[i] = (byte)Character.toLowerCase((char)b[i]);
}
return result;
}
}


FiterInputStream 便是一種特殊的類,他滿足裝飾器(decorator)的條件,
1。必須繼承需要decorator的類:InputStream
2。在此類中必須包含需要decorator的類的實例,這樣的話此類就擁有decorator的類的功能還能擴展其他功能。
FiterInputStream 的原代碼

/*
 * @(#)FilterInputStream.java 1.28 03/12/19
 *
 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

package java.io;

/**
 * A <code>FilterInputStream</code> contains
 * some other input stream, which it uses as
 * its  basic source of data, possibly transforming
 * the data along the way or providing  additional
 * functionality. The class <code>FilterInputStream</code>
 * itself simply overrides all  methods of
 * <code>InputStream</code> with versions that
 * pass all requests to the contained  input
 * stream. Subclasses of <code>FilterInputStream</code>
 * may further override some of  these methods
 * and may also provide additional methods
 * and fields.
 *
 * @author  Jonathan Payne
 * @version 1.28, 12/19/03
 * @since   JDK1.0
 */
public
class FilterInputStream extends InputStream {
    /**
     * The input stream to be filtered.
     */
    protected volatile InputStream in;   
/**
     * Creates a <code>FilterInputStream</code>
     * by assigning the  argument <code>in</code>
     * to the field <code>this.in</code> so as
     * to remember it for later use.
     *
     * @param   in   the underlying input stream, or <code>null</code> if
     *          this instance is to be created without an underlying stream.
     */
    protected FilterInputStream(InputStream in) {
 this.in = in;
    }

    /**
     * Reads the next byte of data from this input stream. The value
     * byte is returned as an <code>int</code> in the range
     * <code>0</code> to <code>255</code>. If no byte is available
     * because the end of the stream has been reached, the value
     * <code>-1</code> is returned. This method blocks until input data
     * is available, the end of the stream is detected, or an exception
     * is thrown.
     * <p>
     * This method
     * simply performs <code>in.read()</code> and returns the result.
     *
     * @return     the next byte of data, or <code>-1</code> if the end of the
     *             stream is reached.
     * @exception  IOException  if an I/O error occurs.
     * @see        java.io.FilterInputStream#in
     */
    public int read() throws IOException {
 return in.read();
    }

    /**
     * Reads up to <code>byte.length</code> bytes of data from this
     * input stream into an array of bytes. This method blocks until some
     * input is available.
     * <p>
     * This method simply performs the call
     * <code>read(b, 0, b.length)</code> and returns
     * the  result. It is important that it does
     * <i>not</i> do <code>in.read(b)</code> instead;
     * certain subclasses of  <code>FilterInputStream</code>
     * depend on the implementation strategy actually
     * used.
     *
     * @param      b   the buffer into which the data is read.
     * @return     the total number of bytes read into the buffer, or
     *             <code>-1</code> if there is no more data because the end of
     *             the stream has been reached.
     * @exception  IOException  if an I/O error occurs.
     * @see        java.io.FilterInputStream#read(byte[], int, int)
     */
    public int read(byte b[]) throws IOException {
 return read(b, 0, b.length);
    }

    /**
     * Reads up to <code>len</code> bytes of data from this input stream
     * into an array of bytes. This method blocks until some input is
     * available.
     * <p>
     * This method simply performs <code>in.read(b, off, len)</code>
     * and returns the result.
     *
     * @param      b     the buffer into which the data is read.
     * @param      off   the start offset of the data.
     * @param      len   the maximum number of bytes read.
     * @return     the total number of bytes read into the buffer, or
     *             <code>-1</code> if there is no more data because the end of
     *             the stream has been reached.
     * @exception  IOException  if an I/O error occurs.
     * @see        java.io.FilterInputStream#in
     */
    public int read(byte b[], int off, int len) throws IOException {
 return in.read(b, off, len);
    }

    /**
     * Skips over and discards <code>n</code> bytes of data from the
     * input stream. The <code>skip</code> method may, for a variety of
     * reasons, end up skipping over some smaller number of bytes,
     * possibly <code>0</code>. The actual number of bytes skipped is
     * returned.
     * <p>
     * This method
     * simply performs <code>in.skip(n)</code>.
     *
     * @param      n   the number of bytes to be skipped.
     * @return     the actual number of bytes skipped.
     * @exception  IOException  if an I/O error occurs.
     */
    public long skip(long n) throws IOException {
 return in.skip(n);
    }

    /**
     * Returns the number of bytes that can be read from this input
     * stream without blocking.
     * <p>
     * This method
     * simply performs <code>in.available()</code> and
     * returns the result.
     *
     * @return     the number of bytes that can be read from the input stream
     *             without blocking.
     * @exception  IOException  if an I/O error occurs.
     * @see        java.io.FilterInputStream#in
     */
    public int available() throws IOException {
 return in.available();
    }

    /**
     * Closes this input stream and releases any system resources
     * associated with the stream.
     * This
     * method simply performs <code>in.close()</code>.
     *
     * @exception  IOException  if an I/O error occurs.
     * @see        java.io.FilterInputStream#in
     */
    public void close() throws IOException {
 in.close();
    }

    /**
     * Marks the current position in this input stream. A subsequent
     * call to the <code>reset</code> method repositions this stream at
     * the last marked position so that subsequent reads re-read the same bytes.
     * <p>
     * The <code>readlimit</code> argument tells this input stream to
     * allow that many bytes to be read before the mark position gets
     * invalidated.
     * <p>
     * This method simply performs <code>in.mark(readlimit)</code>.
     *
     * @param   readlimit   the maximum limit of bytes that can be read before
     *                      the mark position becomes invalid.
     * @see     java.io.FilterInputStream#in
     * @see     java.io.FilterInputStream#reset()
     */
    public synchronized void mark(int readlimit) {
 in.mark(readlimit);
    }

    /**
     * Repositions this stream to the position at the time the
     * <code>mark</code> method was last called on this input stream.
     * <p>
     * This method
     * simply performs <code>in.reset()</code>.
     * <p>
     * Stream marks are intended to be used in
     * situations where you need to read ahead a little to see what's in
     * the stream. Often this is most easily done by invoking some
     * general parser. If the stream is of the type handled by the
     * parse, it just chugs along happily. If the stream is not of
     * that type, the parser should toss an exception when it fails.
     * If this happens within readlimit bytes, it allows the outer
     * code to reset the stream and try another parser.
     *
     * @exception  IOException  if the stream has not been marked or if the
     *               mark has been invalidated.
     * @see        java.io.FilterInputStream#in
     * @see        java.io.FilterInputStream#mark(int)
     */
    public synchronized void reset() throws IOException {
 in.reset();
    }

    /**
     * Tests if this input stream supports the <code>mark</code>
     * and <code>reset</code> methods.
     * This method
     * simply performs <code>in.markSupported()</code>.
     *
     * @return  <code>true</code> if this stream type supports the
     *          <code>mark</code> and <code>reset</code> method;
     *          <code>false</code> otherwise.
     * @see     java.io.FilterInputStream#in
     * @see     java.io.InputStream#mark(int)
     * @see     java.io.InputStream#reset()
     */
    public boolean markSupported() {
 return in.markSupported();
    }
}



劉錚 2007-09-12 12:02 發(fā)表評論
]]>
JNDI的簡單概念&簡單示例http://www.aygfsteel.com/liuzheng/articles/143902.html劉錚 劉錚 Mon, 10 Sep 2007 02:43:00 GMThttp://www.aygfsteel.com/liuzheng/articles/143902.htmlhttp://www.aygfsteel.com/liuzheng/comments/143902.htmlhttp://www.aygfsteel.com/liuzheng/articles/143902.html#Feedback0http://www.aygfsteel.com/liuzheng/comments/commentRss/143902.htmlhttp://www.aygfsteel.com/liuzheng/services/trackbacks/143902.html介紹JNDI的簡單概念&簡單示例。

JNDI: The Java Naming and Directory Interface


 什么是JNDI

The Java Naming and Directory Interface是訪問不同名字和目錄服務(wù)的統(tǒng)一API接口。

不同的服務(wù)使用不同的名字格式。

Java程序需要以相同的格式訪問數(shù)據(jù)庫,文件,目錄,對象和網(wǎng)絡(luò)。

JNID有兩部分接口:應用程序接口和提供服務(wù)的接口。在應用程序中使用API來訪問名字或目錄服務(wù),在一個新的服務(wù)中使用SPI來提供服務(wù)。

JNDI結(jié)構(gòu)

名字服務(wù)(Naming Services)

名字服務(wù)提供一種方法,映射標識符到實體或?qū)ο蟆?/p>

你需要知道的幾條基本條款:

綁定:綁定是將一個不可分割的名字("原子"名字)與一個對象聯(lián)系起來。像DNS,我們用名字www.yahoo.com與IP地址216.32.74.53聯(lián)系起來,一個文件對象用文件名afile.txt聯(lián)系起來。

名字空間;名字空間包含一組名字,但名字空間內(nèi)每個名字是唯一的。一個文件目錄就是一個簡單的名字空間,如目錄C:\temp,在這個目錄下,不能有兩個相同名字的文件,但是,不同目錄下的兩個文件可能有相同的名字。

復合名字:復合名字是用名字空間構(gòu)成的唯一名字,有一個或多個"原子"名字構(gòu)成,取決于所在的名字空間。文件路徑就是一個復合名字,比如我們用C:\temp\myfile.txt,我們可以看到,這個名字由根目錄名(C:\),臨時目錄名(temp)和一個文件名(myfile.txt)構(gòu)成,這3個名字復合起來表示一個唯一的名字。

組合名字:組合名字能跨越多個名字空間。一個URL就是一個組合名字,如果你看見http://www.npu.edu/index.htm,你使用http服務(wù)連接到服務(wù)器,然后使用另一個名字空間/index.htm來訪問一個文件。

目錄服務(wù)

目錄服務(wù)提供一組分成等級的目錄對象,具有可搜索的能力。

在目錄服務(wù)中存儲的對象可以是任何能用一組屬性描述的對象,每個對象都可通過一組屬性來描述該對象的能力。例如,一個Person對象可能有height,hair color,age,sex等屬性。目錄服務(wù)還可提供根據(jù)要求來搜索的能力,如我們可以使用Person的age屬性,搜索20-25歲間的Person對象,目錄服務(wù)將返回符合條件的Persion對象。這通常被稱作基于內(nèi)容的搜索。


在客戶端使用JNDI:

u       創(chuàng)建一個java.util.Hashtable或者java.util.Properties的實例。

u       添加變量到Hashtable或Properties對象:

由naming server提供的JNDI class類名。

包含aming server位置的URL。

安全信任書。

u       通過Hashtable或Properites或jndi屬性文件創(chuàng)建一個InitialContext對象。

 

示例:
import java.util.*;
import javax.naming.*;
...
env.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
env.put(Context.PROVIDER_URL,"t3://localhost:7001");
InitialContext ctx = new InitialContext(env);

環(huán)境變量

相應的常量

說明

java.naming.factory.initial

Context.INITIAL_CONTEXT_FACTORY

Context Factory

類名,由服務(wù)提供商給出。

java.naming.provider.url

Context.PROVIDE_URL

初始化地址。

java.naming.security.

principal

Context.SECURITY_PRINCIPAL

服務(wù)使用者信息。

java.naming.security.

credentials

Context.SECURITY_CREDENTIAL

口令。

更多的配置示例:
Hashtable env = new Hashtable();
env.put (Context.INITIAL_CONTEXT_FACTORY,
"weblogic.jndi.WLInitialContextFactory");
env.put(Context.PROVIDER_URL, "t3://localhost:7001");
env.put(Context.SECURITY_PRINCIPAL, "system");
env.put(Context.SECURITY_CREDENTIALS, "password here");
Properties env = new Properties();
env.setProperties ("java.naming.factory.initial",
"weblogic.jndi.WLInitialContextFactory");
env.setProperties("java.naming.provider.url" , "t3://localhost:7001");
env.setProperties("java.naming.security.principal" , "tommy");
env.setProperties("java.naming.security.credentials" ,"password here");
創(chuàng)建InitialContext
Class Name: javax.naming.InitialContext
Interfaces that it implements: javax.naming.Context
Constructors:
    public InitialContext();
    public InitialContext(Hashtable configuration);
    public InitialContext(Properties configuration);

以上所有方法都可能拋出NamingException。

一個Binding示例:
public static InitialContext getInitialContext() throws NamingException {
    Hashtable env = new Hashtable();
    env.put(Context.INITIAL_CONTEXT_FACTORY,
         "weblogic.jndi.WLInitialContextFactory");
    env.put(Context.PROVIDER_URL,"t3://localhost:7001");
    InitialContext context = new InitialContext(env);
    return context;
}
//Obtain the initial context
InitialContext initialContext = getInitialContext();
//Create a Bank object.
Bank myBank = new Bank();
//Bind the object into the JNDI tree.
initialContext.rebind("theBank",myBank);
一個Lookup示例:
public static InitialContext getInitialContext() throws NamingException {
    Hashtable env = new Hashtable();
    env.put(Context.INITIAL_CONTEXT_FACTORY,
         "weblogic.jndi.WLInitialContextFactory");
    env.put(Context.PROVIDER_URL,"t3://localhost:7001");
    InitialContext context = new InitialContext(env);
    return context;
}
//Obtain the initial context
InitialContext initialContext = getInitialContext();
//Lookup an existing Bank object.
Bank myBank = (Bank) initialContext.lookup("theBank");
可能發(fā)生的NamingException
AuthenticationException
CommunicationException
InvalidNameException
NameNotFoundException
NoInitialContextException
枚舉所有名字對象:
NamingEnumeration Declaration:
public interface NamingEnumeration extends Enumeration {
    public boolean hashMore() throws NamingException;
    public Object next() throws NamingException;
    public void close() throws NamingException; //jndi 1.2
}
try {
    ...
    NamingEnumeration enum = ctx.list("");
    while (enum.hasMore()) {
        NameClassPair ncp = (NameClassPair) enum.next();
        System.out.println("JNDI name is:" + ncp.getName());
    }
}
catch (NamingException e) {...}
最后的示例:
import java.util.*;
import javax.naming.*;
import javax.naming.directory.*;
import java.io.*;
public class ListAll {
    public static void main(java.lang.String[] args) {
        Hashtable env = new Hashtable();
        env.put(Context.INITIAL_CONTEXT_FACTORY,
            "weblogic.jndi.WLInitialContextFactory");
        env.put(Context.PROVIDER_URL, "t3://localhost:7001");
        try {
            InitialContext ctx = new InitialContext(env);
            NamingEnumeration enum = ctx.listBindings("");
            while(enum.hasMore()) {
                Binding binding = (Binding) enum.next();
                Object obj = (Object) binding.getObject();
                System.out.println(obj);
            }
        } catch (NamingException e) {
        System.out.println(e);
        }
    } // end main

}



劉錚 2007-09-10 10:43 發(fā)表評論
]]>
JAVA動態(tài)代理學習心得http://www.aygfsteel.com/liuzheng/articles/143197.html劉錚 劉錚 Thu, 06 Sep 2007 08:18:00 GMThttp://www.aygfsteel.com/liuzheng/articles/143197.htmlhttp://www.aygfsteel.com/liuzheng/comments/143197.htmlhttp://www.aygfsteel.com/liuzheng/articles/143197.html#Feedback0http://www.aygfsteel.com/liuzheng/comments/commentRss/143197.htmlhttp://www.aygfsteel.com/liuzheng/services/trackbacks/143197.htmlJAVA動態(tài)代理學習心得

1.       所有的額外新添加的方法要放到InvocationHandler的實現(xiàn)類中

2.       Proxy類都與InvocationHandler相聯(lián)系的,也就是說Proxy類的中的方法調(diào)用都會被重新分配到實例的InvoctionHandler中的invoke方法中,傳遞了reflect中的method

3.       創(chuàng)建Java動態(tài)代理類的步驟:

a)       實現(xiàn)InvocationHandler接口

b)      通過Proxy.newProxyInstance得到一個Proxy類的實例

一般的寫法如下:

public class XXXHandler implements InvocationHandler {

private Object originalObject;

public Object bind(Object obj) {

this.originalObject = obj;

return Proxy.newProxyInstance(

obj.getClass().getClassLoader(),

obj.getClass().getInterfaces(),

this)

}

public Object invoke(Object proxy, Method method, Object[] args)

throws Throwable {

method.invoke(originalObject, args);

}

4.       這樣調(diào)用XXXHandler:代理目標的接口類= XXXHandler的實例.bind(代理目標的實現(xiàn)類)



劉錚 2007-09-06 16:18 發(fā)表評論
]]>
JAVA 學習目標和資料http://www.aygfsteel.com/liuzheng/articles/139100.html劉錚 劉錚 Fri, 24 Aug 2007 06:48:00 GMThttp://www.aygfsteel.com/liuzheng/articles/139100.htmlhttp://www.aygfsteel.com/liuzheng/comments/139100.htmlhttp://www.aygfsteel.com/liuzheng/articles/139100.html#Feedback0http://www.aygfsteel.com/liuzheng/comments/commentRss/139100.htmlhttp://www.aygfsteel.com/liuzheng/services/trackbacks/139100.html本文將告訴你學習Java需要達到的30個目標,希望能夠?qū)δ愕膶W習有所幫助。對比一下自己,你已經(jīng)掌握了這30條中的多少條了呢?

  1.你需要精通面向?qū)ο蠓治雠c設(shè)計(OOA/OOD)、涉及模式(GOF,J2EEDP)以及綜合模式。你應該十分了解UML,尤其是class,object,interaction以及statediagrams。

  2.你需要學習JAVA語言的基礎(chǔ)知識以及它的核心類庫(collections,serialization,streams,networking, multithreading,reflection,event,handling,NIO,localization,以及其他)。

  3.你應該了解JVM,classloaders,classreflect,以及垃圾回收的基本工作機制等。你應該有能力反編譯一個類文件并且明白一些基本的匯編指令。

  4.如果你將要寫客戶端程序,你需要學習WEB的小應用程序(applet),必需掌握GUI設(shè)計的思想和方法,以及桌面程序的SWING,AWT, SWT。你還應該對UI部件的JAVABEAN組件模式有所了解。JAVABEANS也被應用在JSP中以把業(yè)務(wù)邏輯從表現(xiàn)層中分離出來。

  5.你需要學習java數(shù)據(jù)庫技術(shù),如JDBCAPI并且會使用至少一種persistence/ORM構(gòu)架,例如Hibernate,JDO, CocoBase,TopLink,InsideLiberator(國產(chǎn)JDO紅工廠軟件)或者iBatis。
  6.你還應該了解對象關(guān)系的阻抗失配的含義,以及它是如何影響業(yè)務(wù)對象的與關(guān)系型數(shù)據(jù)庫的交互,和它的運行結(jié)果,還需要掌握不同的數(shù)據(jù)庫產(chǎn)品運用,比如:oracle,mysql,mssqlserver。

  7.你需要學習JAVA的沙盒安全模式(classloaders,bytecodeverification,managers,policyandpermissions,
codesigning, digitalsignatures,cryptography,certification,Kerberos,以及其他)還有不同的安全/認證 API,例如JAAS(JavaAuthenticationandAuthorizationService),JCE (JavaCryptographyExtension),JSSE(JavaSecureSocketExtension),以及JGSS (JavaGeneralSecurityService)。

  8.你需要學習Servlets,JSP,以及JSTL(StandardTagLibraries)和可以選擇的第三方TagLibraries。

  9.你需要熟悉主流的網(wǎng)頁框架,例如JSF,Struts,Tapestry,Cocoon,WebWork,以及他們下面的涉及模式,如MVC/MODEL2。

  10.你需要學習如何使用及管理WEB服務(wù)器,例如tomcat,resin,Jrun,并且知道如何在其基礎(chǔ)上擴展和維護WEB程序。

  11.你需要學習分布式對象以及遠程API,例如RMI和RMI/IIOP。

  12.你需要掌握各種流行中間件技術(shù)標準和與java結(jié)合實現(xiàn),比如Tuxedo、CROBA,當然也包括javaEE本身。

  13.你需要學習最少一種的XMLAPI,例如JAXP(JavaAPIforXMLProcessing),JDOM(JavaforXMLDocumentObjectModel),DOM4J,或JAXR(JavaAPIforXMLRegistries)。

  14.你應該學習如何利用JAVAAPI和工具來構(gòu)建WebService。例如JAX-RPC(JavaAPIforXML/RPC),SAAJ (SOAPwithAttachmentsAPIforJava),JAXB(JavaArchitectureforXMLBinding),JAXM(JavaAPIforXMLMessaging), JAXR(JavaAPIforXMLRegistries),或者JWSDP(JavaWebServicesDeveloperPack)。

  15.你需要學習一門輕量級應用程序框架,例如Spring,PicoContainer,Avalon,以及它們的IoC/DI風格(setter,constructor,interfaceinjection)。

  16.你需要熟悉不同的J2EE技術(shù),例如JNDI(JavaNamingandDirectoryInterface),JMS (JavaMessageService),JTA/JTS(JavaTransactionAPI/JavaTransactionService),JMX (JavaManagementeXtensions),以及JavaMail。

  17.你需要學習企業(yè)級JavaBeans(EJB)以及它們的不同組件模式:Stateless/StatefulSessionBeans,EntityBeans(包含Bean- ManagedPersistence[BMP]或者Container-ManagedPersistence[CMP]和它的EJB-QL),或者 Message-DrivenBeans(MDB)。

  18.你需要學習如何管理與配置一個J2EE應用程序服務(wù)器,如WebLogic,JBoss等,并且利用它的附加服務(wù),例如簇類,連接池以及分布式處理支援。你還需要了解如何在它上面封裝和配置應用程序并且能夠監(jiān)控、調(diào)整它的性能。

  19.你需要熟悉面向方面的程序設(shè)計以及面向?qū)傩缘某绦蛟O(shè)計(這兩個都被很容易混淆的縮寫為AOP),以及他們的主流JAVA規(guī)格和執(zhí)行。例如AspectJ和AspectWerkz。

  20.你需要熟悉對不同有用的API和frame work等來為你服務(wù)。例如Log4J(logging/tracing),Quartz (scheduling),JGroups(networkgroupcommunication),JCache(distributedcaching), Lucene(full-textsearch),JakartaCommons等等。

  21.如果你將要對接或者正和舊的系統(tǒng)或者本地平臺,你需要學習JNI (JavaNativeInterface) and JCA (JavaConnectorArchitecture)。

  22.你需要熟悉JINI技術(shù)以及與它相關(guān)的分布式系統(tǒng),比如掌握CROBA。

  23.你需要JavaCommunityProcess(JCP)以及他的不同JavaSpecificationRequests(JSRs),例如Portlets(168),JOLAP(69),DataMiningAPI(73),等等。

  24.你應該熟練掌握一種JAVAIDE例如sunOne,netBeans,IntelliJIDEA或者Eclipse。(有些人更喜歡VI或EMACS來編寫文件。隨便你用什么了:)

  25.JAVA(精確的說是有些配置)是冗長的,它需要很多的人工代碼(例如EJB),所以你需要熟悉代碼生成工具,例如XDoclet。

  26.你需要熟悉一種單元測試體系(JNunit),并且學習不同的生成、部署工具(Ant,Maven)。

  27.你需要熟悉一些在JAVA開發(fā)中經(jīng)常用到的軟件工程過程。例如RUP(RationalUnifiedProcess)andAgilemethodologies。

  28.你需要能夠深入了解加熟練操作和配置不同的操作系統(tǒng),比如GNU/linux,sunsolaris,macOS等,做為跨平臺軟件的開發(fā)者。

  29.你還需要緊跟java發(fā)展的步伐,比如現(xiàn)在可以深入的學習javaME,以及各種java新規(guī)范,技術(shù)的運用,如新起的web富客戶端技術(shù)。

  30.你必需要對opensource有所了解,因為至少java的很多技術(shù)直接是靠開源來驅(qū)動發(fā)展的,如java3D技術(shù)。

posted @ 2007-07-07 15:46 topquan 閱讀(80) | 評論 (0)編輯 收藏

My Favorite Java Site

1.TheServerside.com  依然是地位無可動搖的CCTV1。

2.InfoQ.com Floyd Marinescu 在離開 TSS 后另起爐灶,2006年中最重要推薦。視野不再局限于Java 而是包括Java,.Net, Ruby ,SOA, Agile方法等熱門話題。

3.JDJ的電子雜志 在JDJ首頁的最底處訂閱,文章質(zhì)量不低于5-7的傳統(tǒng)三強。

4.SWik.net  收集了大量OpenSource Project的資源聚合。其中如Spring,Hibernate的更新度非常高,出現(xiàn)什么和Spring有關(guān)的blog,article,project都會馬上被聚合。

5.IBM DeveloperWorks 傳統(tǒng)、穩(wěn)定的Java文章來源地。

6.JavaWorld 傳統(tǒng)、穩(wěn)定的Java文章來源地。

7.OnJava  傳統(tǒng)、穩(wěn)定的Java文章來源地。

8.Artima.com 類似于TSS而略遜,其中Spotlight 文章值得關(guān)注,而Java News是聚合了所有其他Java站點的大聚合。

9.JavaLobby  站內(nèi)的Announcements 是大大小小Java  Project的發(fā)布聲明區(qū),Trips and Tricks 有很多的Tips。

10. No Fluff Just Stuff 的Blogs 聚合 一直缺一個所有優(yōu)秀Java Blogger的rss總聚合,NFJS這里勉強算一個。

11. JBOSS 官方網(wǎng)站 JBOSS被RedHat收購后,在各方面都有所加強,出現(xiàn)了高質(zhì)量的產(chǎn)品



劉錚 2007-08-24 14:48 發(fā)表評論
]]>
主站蜘蛛池模板: 南岸区| 平昌县| 资中县| 历史| 岳池县| 息烽县| 涪陵区| 兰州市| 若尔盖县| 旬阳县| 霍城县| 西乡县| 奎屯市| 即墨市| 抚州市| 司法| 甘德县| 岗巴县| 泉州市| 清流县| 那坡县| 舒城县| 甘德县| 梁山县| 礼泉县| 沽源县| 襄樊市| 锦屏县| 泾川县| 呼伦贝尔市| 友谊县| 鲁山县| 祁阳县| 商南县| 广安市| 江达县| 理塘县| 鲁山县| SHOW| 蓬溪县| 洪江市|