
2005年10月25日
帕金森定律
美國著名歷史學家諾斯古德-帕金森通過長期調查研究,寫了一本名叫《帕金森定律》的書,他在書中闡述了機構人員膨脹的原因及后果:一個不稱職的官員,可能有三條出路。第一是申請退職,把位子讓給能干的人;第二是讓一位能干的人來協助自己工作;第三是任用兩個水平比自己更低的人當助手。
這第一條路是萬萬走不得的,因為那樣會喪失許多權力;第二條路也不能走,因為那個能干的人會成為自己的對手;看來只有第三條路最適宜。于是,兩個平庸的助手分擔了他的工作,他自己則高高在上發號施令。兩個助手既無能,也就上行下效,再為自己找兩個無能的助手。如此類推,就形成了一個機構臃腫、人浮于事、相互扯皮、效率低下的領導體系。
苛希納定律
西方管理學中有一條著名的苛希納定律:如果實際管理人員比最佳人數多兩倍,工作時間就要多兩倍,工作成本就要多四倍;如果實際管理人員比最佳人數多三倍,工作時間就要多三倍,工作成本就要多六倍。
苛希納定律告訴我們,在管理上并不是人多力量大,管理人員越多,工作效率未必就會越高。苛希納定律要求我們,要認真研究并找到一個最佳人數,以最大限度地減少工作時間,降低工作成本。
馬蠅效應
林肯少年時和他的兄弟在肯塔基老家的一個農場里犁玉米地,林肯吆馬,他兄弟扶犁,而那匹馬很懶,慢慢騰騰,走走停停。可是有一段時間馬走得飛快。林肯感到奇怪,到了地頭,他發現有一只很大的馬蠅叮在馬身上,他就把馬蠅打落了。看到馬蠅被打落了,他兄弟就抱怨說:“哎呀,你為什么要打掉它,正是那家伙使馬跑起來的嘛!”
沒有馬蠅叮咬,馬慢慢騰騰,走走停停;有馬蠅叮咬,馬不敢怠慢,跑得飛快。這就是馬蠅效應。馬蠅效應給我們的啟示是:一個人只有被叮著咬著,他才不敢松懈,才會努力拼搏,不斷進步。
“南風”法則
“南風”法則也稱“溫暖”法則,源于法國作家拉封丹寫過的一則寓言:北風和南風比威力,看誰能把行人身上的大衣脫掉。北風首先來一個冷風凜冽寒冷刺骨,結果行人為了抵御北風的侵襲,便把大衣裹得緊緊的。南風則徐徐吹動,頓時風和日麗,行人因為覺得春暖上身,始而解開紐扣,繼而脫掉大衣,南風獲得了勝利。
這則寓言形象地說明了一個道理:溫暖勝于嚴寒。領導者在管理中運用“南風”法則,就是要尊重和關心下屬,以下屬為本,多點“人情味”,盡力解決下屬日常生活中的實際困難,使下屬真正感受到領導者給予的溫暖,從而激發出工作的積極性。
酒與污水定律
酒與污水定律是指,如果把一匙酒倒進一桶污水中,你得到的是一桶污水;如果把一匙污水倒進一桶酒中,你得到的還是一桶污水。
在任何組織里,都存在幾個難弄的人物,他們存在的目的似乎就是為了把事情搞糟。最糟糕的是,他們像果箱里的爛蘋果一樣,如果你不及時處理,它會迅速傳染,把果箱里其他的蘋果也弄爛。“爛蘋果”的可怕之處在于它那驚人的破壞力。一個正直能干的人進入一個混亂的部門可能被吞沒,而一個無德無才者能很快將一個高效的部門變成一盤散沙。一個能工巧匠花費時日精心制作的陶瓷品,一頭驢子一秒鐘就能將它毀壞掉。
posted @
2007-11-27 14:18 surffish 閱讀(381) |
評論 (0) |
編輯 收藏
1、WINKEY+D:這是高手最常用的第一快捷組合鍵(木頭按:也是我最喜歡用的哦,好像有點自詡為高手)。這個快捷鍵組合可以將桌面上的所有窗口瞬間最小化,無論是聊天的窗口還是游戲的窗口……只要再次按下這個組合鍵,剛才的所有窗口都回來了,而且激活的也正是你最小化之前在使用的窗口!
2、WINKEY + F:不用再去移動鼠標點“開始→搜索→文件和文件夾”了,在任何狀態下,只要一按WINKEY+F就會彈出搜索窗口。
3、WINKEY + R:在我們的文章中,你經常會看到這樣的操作提示:“點擊‘開始→運行’,打開‘運行’對話框……”。其實,還有一個更簡單的辦法,就是按WINKEY + R!
4、ALT + TAB :如果打開的窗口太多,這個組合鍵就非常有用了,它可以在一個窗口中顯示當前打開的所有窗口的名稱和圖標,選中自己希望要打開的窗口,松開這個組合鍵就可以了。而ALT+TAB+SHIFT鍵則可以反向顯示當前打開的窗口。
5、WINKEY + E:當你需要打開資源管理器找文件的時候,這個快捷鍵會讓你感覺非常“爽”!再也不用騰出一只手去摸鼠標了!
?????????6、WINKEY+L,鎖定計算機
小提示:
WINKEY指的是鍵盤上刻有Windows徽標的鍵。WINKEY主要出現在104鍵和107鍵的鍵盤中。104鍵盤又稱Win95鍵盤,這種鍵盤在原來101鍵盤的左右兩邊、Ctrl和Alt鍵之間增加了兩個Windwos鍵和一個屬性關聯鍵。107鍵盤又稱為Win98鍵盤,比104鍵多了睡眠、喚醒、開機等電源管理鍵,這3個鍵大部分位于鍵盤的右上方。
posted @
2007-02-15 15:30 surffish 閱讀(168) |
評論 (0) |
編輯 收藏
不論你是單一團隊的領導者還是多個團隊的管理人,團隊管理工作都是你職權范圍內一個重要的組成部分。在今日,集多重技術于一身的工作方法已逐漸取代階層式的、缺乏彈性的傳統工作體制,團隊合作因而很快就成為了一種很受歡迎的工作方式。對于每一位參與團隊管理工作的人而言,《團隊管理》是一本不可或缺的重要讀物。它向你提供了達成計劃所需的技巧、建立團隊成員間的信任、激發團隊最大的潛能等方面的知識,為你能專業化地管理好你的團隊創造了有利條件。另外,全書還散布了101條簡明提示,為你提供重要而實用的訊息。后半部分有個自我評估練習,使你能正確地評估自己的領導能力,并針對自己的不足加以改進。
了解團隊運作
團隊合作是所有成功管理的根基。無論你是新手還是資深管理人,對你而言,管理好團隊都是重要且具激勵性的挑戰。
1.切記:每位成員都能為團隊作出一些貢獻。
2.謹慎地設定團隊目標,且認真嚴肅地對待它們。
3.切記成員間要彼此扶持。
4.將長程目標打散成許多短程計劃。
5.為每個計劃設定明確的期限。
6.盡早決定何種形態的團隊適合你的目標。
7.努力與其它團隊的成員建立強有力的緊密關系。
8.找一位可提升團隊工作士氣的重量級人物。
9.時時提醒團隊成員:他們都是團隊的一份子。
10.將團隊的注意力集中在固定可衡量的目標上。
11.利用友誼的強大力量強化團隊。
12.選擇領導者時要把握用人唯才原則。
13.領導者需具備強烈的團隊使命感。
14.獎賞優異的表現,但絕不姑息錯誤。
15.記住每位團隊成員看事情的角度都不一樣。
16.征召團隊成員時,應注重他們的成長潛能。
17.密切注意團隊成員缺少的相關經驗。
18.應使不適任的成員退出團隊。
19.找到能將人際關系處理得很好的人,并培養他們。
設立一支團隊
成立一支團隊是領導者的主要工作。確保你的團隊有清楚明確的目的和足夠達成目標的資源。要以開放和公正無私的態度對待團隊成員。
20.設定具挑戰性的目標須根據限期來考量是否合理。
21.設定目標時,考量個別成員的工作目標。
22.計劃的失敗危及整體計劃的成功。
23.堅持得到信息技術支持,它能為你提供確實需要的東西。
24.對待團隊外的顧問要如同對待團隊成員一般。
25.讓團隊的贊助者隨時知道工作進展情形。
26.除非你確定沒有人能夠勝任,否則應避免“事必躬親”。
27.不要委托不必要的工作,最好將其去除掉。
28.賦予團隊自己作決策的權力。
29.鼓勵團隊成員正面積極的貢獻。
30.肯定、宣揚和慶祝團隊每次的成功。
31.找到易于讓成員及團隊了解每日工作進度的展現方式。
32.鼓勵成員之間建立工作上的伙伴關系。
33.鼓勵天生具有領導才能的人,并引導和培養他們的領導技巧。
34.絕對不能沒有解釋就駁回團隊的意見,與此相反,解釋要坦白,理由要充分。
35.確定團隊和客戶經常保持聯系。
36.以自信肯定的態度讓團隊知道誰當家,但要預防予人來勢洶洶的感覺。
37.想辦法給新團隊留下一個實時的好印象,但切忌操之過急。
38.倘若你要求別人的建議,抱持的心態不能只是歡迎就行了,也要依循建議有所行動。
提升團隊效率
團隊要達到應有的效率,唯一的條件是每個成員都要學會集中力量。你必須了解團隊的能力,以確保團隊的成功。
39.協助團隊找出方法以改變有礙任務推展的團體行為。
40.找出可建設性地利用沖突的方法。
41.記住要在工作中穿插安排娛樂調劑身心──這是每個人應得的福利。
42.若有計劃出錯,一定要作全面性、公開化的分析。
43.如果你希望團隊成員有問題時能毫不猶疑地找你談,就要實施“開門政策”。
44.要求提出問題的人解決問題。
45.安排正式的和非正式的會面,討論團隊的工作進展。
46.使用不帶感情只問事實的態度,是化解紛爭的最好方法。
47.保持團隊成員間的熟稔,以易于溝通。
48.設立交誼場所,讓團隊成員可作非正式的碰面交談。
49.鼓勵同事間自由的溝通活動。
50.建立最適合的通訊科技系統,并經常更新。
51.實施會議主席輪流制,讓每個人都有機會主持會議。
52.盡可能多地授權給團隊成員。
53.事先于會前發出議程,預留時間給與會者準備。
54.培養所有對團隊有益的關系。
55.努力保持團隊內外關系的均衡與平穩。
56.確定所有相關人士都能聽到、了解好消息。
57.倘有麻煩在團隊關系中發酵蘊釀,要盡快處理。
58.安排團隊與機構的其它部門作社交聯誼。
59.找出你與“大佬”保持聯系的最佳通訊科技。
60.要對你在團隊或辦公室外接觸過的重要人士作聯系記錄。
61.謹慎分派角色以避免任務重復。
62.找尋建議中的精華,且絕不在公開場合批評任何建議。
63.一定要找有經驗的人解決問題。
64.分析團隊成員每個人所扮演的角色。
65.腦力激發出的意見,就算不采用,亦不得輕視。否則,會打擊人的積極性,創意的流動也會因此停止。
66.公平對待每個成員才能避免怨恨。
67.確定團隊成員真正有錯之前,都須視他們沒有錯。
68.告訴同事他們做得很好,這有助于激勵團隊士氣。
69.尊重每一位成員,包括那些給你制造麻煩的人。
70.避免和團隊成員有直接的沖突。
71.記住采用對事不對人的處事態度。
72.確定整個團隊都能夠從解決問題中學習經驗。
73.先選擇完成一些規模大的、可快速達成及有成就感的任務,以激勵成員再接再勵。
74.確信團隊成員皆了解團隊中的其它角色。
75.計算品質的成本之前,先計算失敗的成本。
76.針對每筆預算及每項團隊行動計劃,設定重大的改進目標。
為未來努力
為團隊設定新的、更高的挑戰目標是團隊工作中最令人興奮的事情之一。可運用一些適當的技巧,推動團隊向更大、更好的目標前進。
77.告知團隊每位成員,在設定的標準中有哪些評量的項目。
78.確定所有改善措施及新訂目標都持續進行著。
79.召開檢討會議前傳閱所有相關資料及資料。
80.開檢討會時一定要避諱人身攻擊。
81.記住關系會隨時間改變。
82.避開低估或忽視壞消息的陷井。
83.每天結束時自問團隊今天是否又向前跨出了一步。
84.傾聽受訓者關于訓練課程的回饋意見。
85.找到有最好設備的最佳訓練場所。
86.聘請顧問設立公司內部的訓練課程。
87.利用移地訓練時的用餐時間作非正式的計劃。
88.每位團隊成員都必須參與設定目標的工作,以促進團隊合作及達成共識。
89.允許團隊自行決定達成目標的方法,可激勵團隊努力工作。
90.確定目標能激發團隊的斗志,如果不行,請改變目標。
91.一支沒有“嚴峻”目標的團隊,工作表現將不如接受過此類考驗的團隊。
92.設定獎勵標準時,允許團隊成員有發言權。
93.避免使用名次表,因為落后的團隊成員將會感到自尊心受創。
94.指定某人監視市場上每一個相關變化。
95.隨時準備作改變,甚至計劃的根本要素亦包含在改變的范圍內。
96.記住有某些人很害怕變革。
97.尋找能推動改革的團隊成員。
98.每隔一段時間作一次生涯發展的評量。
99.記住:鼓勵團隊成員即是在幫助團隊。
100.與團隊同事就生涯規劃達成一致意見,并給他們提供必要的協助。
101.團隊解散后仍舊要與團隊成員保持聯系,因為你可能還會與他們再次合作
posted @
2006-09-21 08:05 surffish 閱讀(213) |
評論 (0) |
編輯 收藏
LEFT JOIN 和 RIGHT JOIN 運算
用于 FROM 子句時,把源表記錄組合起來。
語法
FROM表1 [ LEFT | RIGHT ] JOIN表2
????ON 表1.字段1compopr 表2. 字段2
LEFT JOIN 及 RIGHT JOIN 運算可分為以下幾個部分:
部分 |
說明 |
table1, table2 |
記錄被組合的表的名稱。 |
field1, field2 |
被聯接的字段的名稱。且這些字段必須有相同的數據類型及包含相同類型的數據,但它們不需要有相同的名稱。 |
compopr
|
任何的關系比較運算子:"=," "<," ">," "<=," ">=," 或 "<>." |
說明
用 LEFT JOIN 運算 創建左邊外部聯接.左邊外部聯接將包含了從第一個(左邊)開始的兩個表中的全部記錄,即使在第二個(右邊)表中并沒有相符值的記錄。
用RIGHT JOIN 運算 創建 右邊外部聯接.右邊外部聯接將包含了從第二個(右邊)開始的兩個表中的全部記錄,即使在第一個(左邊)表中并沒有匹配值的記錄。
例如,可以使用 LEFT JOIN 與部門(左邊)及員工(右邊)表來選擇所有的部門,包含了沒有分配到員工的部門。可以使用 RIGHT JOIN 選擇所有的員工,包含了沒有分配到部門的員工。
下列示例顯示如何在類標識符字段中聯接類表及產品表。查詢將會列出所有種類的列表,包含那些沒有產品在其中的種類:
SELECT CategoryName,
ProductName
FROM Categories LEFT JOIN Products
ON Categories.CategoryID = Products.CategoryID;
在本例中,CategoryID 是聯接的字段,但由于它不包含在 SELECT 語句中,因此,也不包含在查詢結果中。要包含聯接的字段,請在 SELECT 語句中輸入字段名 — 在這個示例中為 Categories.CategoryID。
注意
欲創建只包含聯接字段中數據相同的記錄的查詢,請用 INNER JOIN 運算。
- 在 INNER JOIN 之中可以寫一個嵌套的 LEFT JOIN 或一個 RIGHT JOIN,但是在一個 LEFT JOIN 或一個 RIGHT JOIN 之中不能寫嵌套的 INNER JOIN。請參閱 INNER JOIN 主題中有關使用嵌套的討論,從其中可獲知如何在其它聯接中編寫嵌套聯接的信息。
- 可以鏈接多個 ON 子句。若需更多信息,請參閱在 INNER JOIN 主題中的子句鏈接的討論。
若試圖聯接包含 Memo或 OLE Object數據的字段,會導致錯誤。
請參閱
示例
LEFT JOIN 和 RIGHT JOIN 運算示例
posted @
2006-09-03 11:52 surffish 閱讀(248) |
評論 (0) |
編輯 收藏
關閉msn,在開始->運行中分別輸入
regsvr32 softpub.dll
regsvr32 mssip32.dll
regsvr32 intipki.dll
regsvr32 MSXML3.dll
11221399B
再重新啟動msn即可
posted @
2006-08-21 08:03 surffish 閱讀(225) |
評論 (0) |
編輯 收藏
1. 在業務層使用JDBC直接操作數據庫-最簡單,最直接的操作
1)數據庫url,username,password寫死在代碼中
Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
String url="jdbc:oracle:thin:@localhost:1521:orcl";
String user="scott";
String password="tiger";
Connection conn= DriverManager.getConnection(url,user,password);
Statement stmt=conn.createStatement(
ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
String sql="select * from test";
ResultSet rs=stmt.executeQuery(sql);
2)采用Facade和Command模式,使用DBUtil類封裝JDBC操作;
數據庫url,username,password可以放在配置文件中(如xml,properties,ini等)。
這種方法在小程序中應用較多。
2.DAO(Data Accessor Object)模式-松耦合的開始
DAO = data + accessor + domain object
例如User類-domain object (javabean)
UserDAO類-accessor ,提供的方法getUser(int id),save(User user)內包含了JDBC操作
在業務邏輯中使用這兩個類來完成數據操作。
使用Factory模式可以方便不同數據庫連接之間的移植。
3.數據庫資源管理模式
3.1 數據庫連接池技術
資源重用,避免頻繁創建,釋放連接引起大大量性能開銷;
更快的系統響應速度;
通過實現JDBC的部分資源對象接口( Connection, Statement, ResultSet ),可以使用Decorator設計模式分別產生三種邏輯資源對象: PooledConnection, PooledStatement和 PooledResultSet。
一個最簡單地數據庫連接池實現:
public class ConnectionPool {
private static Vector pools;
private final int POOL_MAXSIZE = 25;
/**
* 獲取數據庫連接
* 如果當前池中有可用連接,則將池中最后一個返回;若沒有,則創建一個新的返回
*/
public synchronized Connection getConnection() {
Connection conn = null;
if (pools == null) {
pools = new Vector();
}
if (pools.isEmpty()) {
conn = createConnection();
} else {
int last_idx = pools.size() - 1;
conn = (Connection) pools.get(last_idx);
pools.remove(last_idx);
}
return conn;
}
/**
* 將使用完畢的數據庫連接放回池中
* 若池中連接已經超過閾值,則關閉該連接;否則放回池中下次再使用
*/
public synchronized void releaseConnection(Connection conn) {
if (pools.size() >= POOL_MAXSIZE)
try {
conn.close();
} catch (SQLException e) {
// TODO自動生成 catch 塊
e.printStackTrace();
} else
pools.add(conn);
}
public static Connection createConnection() {
Connection conn = null;
try {
Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
String url = "jdbc:oracle:thin:@localhost:1521:orcl";
String user = "scott";
String password = "tiger";
conn = DriverManager.getConnection(url, user, password);
} catch (InstantiationException e) {
// TODO自動生成 catch 塊
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO自動生成 catch 塊
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO自動生成 catch 塊
e.printStackTrace();
} catch (SQLException e) {
// TODO自動生成 catch 塊
e.printStackTrace();
}
return conn;
}
}
注意:利用getConnection()方法得到的Connection,程序員很習慣地調用conn.close()方法關閉了數據庫連接,那么上述的數據庫連接機制便形同虛設。在調用conn.close()方法方法時如何調用releaseConnection()方法?這是關鍵。這里,我們使用Proxy模式和java反射機制。
public synchronized Connection getConnection() {
Connection conn = null;
if (pools == null) {
pools = new Vector();
}
if (pools.isEmpty()) {
conn = createConnection();
} else {
int last_idx = pools.size() - 1;
conn = (Connection) pools.get(last_idx);
pools.remove(last_idx);
}
ConnectionHandler handler=new ConnectionHandler(this);
return handler.bind(con);
}
public class ConnectionHandler implements InvocationHandler {
private Connection conn;
private ConnectionPool pool;
public ConnectionHandler(ConnectionPool pool){
this.pool=pool;
}
/**
* 將動態代理綁定到指定Connection
* @param conn
* @return
*/
public Connection bind(Connection conn){
this.conn=conn;
Connection proxyConn=(Connection)Proxy.newProxyInstance(
conn.getClass().getClassLoader(), conn.getClass().getInterfaces(),this);
return proxyConn;
}
/* (非 Javadoc)
* @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO自動生成方法存根
Object obj=null;
if("close".equals(method.getName())){
this.pool.releaseConnection(this.conn);
}
else{
obj=method.invoke(this.conn, args);
}
return obj;
}
}
在實際項目中,并不需要你來從頭開始來設計數據庫連接池機制,現在成熟的開源項目,如C3P0,dbcp,Proxool等提供了良好的實現。一般推薦使用Apache dbcp,基本使用實例:
DataSource ds = null;
try{
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
ds = (DataSource)envCtx.lookup("jdbc/myoracle");
if(ds!=null){
out.println("Connection is OK!");
Connection cn=ds.getConnection();
if(cn!=null){
out.println("cn is Ok!");
Statement stmt = cn.createStatement();
ResultSet rst = stmt.executeQuery("select * from BOOK");
out.println("
rst is Ok!" + rst.next());
while(rst.next()){
out.println("
BOOK_CODE:" + rst.getString(1));
}
cn.close();
}else{
out.println("rst Fail!");
}
}
else
out.println("Fail!");
}catch(Exception ne){ out.println(ne);
}
3.2 Statement Pool
普通預編譯代碼:
String strSQL=”select name from items where id=?”;
PreparedStatement ps=conn.prepareStatement(strSQL);
ps.setString(1, “2”);
ResultSet rs=ps.executeQuery();
但是PreparedStatement 是與特定的Connection關聯的,一旦Connection關閉,則相關的PreparedStatement 也會關閉。
為了創建PreparedStatement 緩沖池,可以在invoke方法中通過sql語句判斷池中還有沒有可用實例。
4. 持久層設計與O/R mapping 技術
1) Hernate:適合對新產品的開發,進行封閉化的設計
Hibernate 2003年被Jboss接管,通過把java pojo對象映射到數據庫的table中,采用了xml/javareflection技術等。3.0提供了對存儲過程和手寫sql的支持,本身提供了hql語言。
開發所需要的文件:
hibernate配置文件: hibernate.cfg.xml 或 hibernate.properties
hibernate 映射文件: a.hbm.xml
pojo類源文件: a.java
導出表與表之間的關系:
a. 從java對象到hbm文件:xdoclet
b. 從hbm文件到java對象:hibernate extension
c. 從數據庫到hbm文件:middlegen
d. 從hbm文件到數據庫:SchemaExport
2)Iatis :適合對遺留系統的改造和對既有數據庫的復用,有很強的靈活性 3) Apache OJB:優勢在于對標準的全面支持 4)EJB:適合集群服務器,其性能也不象某些人所詬病的那么差勁 5) JDO (java data object)
設置一個Properties對象,從而獲取一個JDO的PersistenceManagerFactory(相當于JDBC連接池中的DataSource),進而獲得一個PersistenceManager對象(相當于JDBC中的Connection對象),之后,你可以用這個PersistenceManager對象來增加、更新、刪除、查詢對象。
JDOQL是JDO的查詢語言;它有點象SQL,但卻是依照Java的語法的。
5. 基于開源框架的Struts+Spring+Hibernate實現方案
示例:這是一個3層架構的web 程序,通過一個Action 來調用業務代理,再通過它來回調 DAO類。下面的流程圖表示了MyUsers是如何工作的。數字表明了流程的先后順序,從web層(UserAction)到中間層(UserManager),再到數據層(UserDAO),然后返回。
Spring是AOP, UserManager和UserDAO都是接口.
1) web層(UserAction) :調用中間層的接口方法,將UserManager作為屬性注入。
采用流行的Struts框架,雖然有很多人不屑一顧,但是這項技術在業界用的比較普遍,能滿足基本的功能,可以減少培訓學習成本。
2) 中間層(UserManager):將UserDAO作為屬性注入,其實現主要是調用數據層接口的一些方法;它處于事務控制中。
采用Spring框架實現,IOC與AOP是它的代名詞,功能齊全,非常棒的一個架構。
3) 數據層(UserDAO):實現類繼承HibernateDaoSupport類,在該類中可以調用getHibernateTemplate()的一些方法執行具體的數據操作。
采用Hibernate做O/R mapping,從種種跡象可以看出,Hibernate就是EJB3.0的beta版。 (轉載文章請保留出處:Java家(www.javajia.com))
posted @
2006-04-18 11:05 surffish 閱讀(269) |
評論 (0) |
編輯 收藏
【品名】民間俗稱老婆,正式場合可稱妻子或夫人;古稱內人,現亦可叫愛人。
【成分】水、血液和脂肪類碳水化合物。
【性狀】本品為細長條塊狀糖衣片,表面涂層一般為粉底、口紅等化妝物,除去後呈淺黃色,外觀與除去前略有差異;本品隨時間推移,形狀會有所改變,出現發胖、起皺等現象,但不影響繼續使用。
【功能主治】主治單身恐懼癥及傳宗接代等頑疾,對失戀和相思病也有明顯效果。
【用法用量】口服兼外用,一次限一片。對無效者,可暫時停用并向婚姻專家咨詢,或間隔一段時間後重復使用。
【注意事項】本品僅適用于單身之成年男性。服用時 小心謹慎,細心觀察有無不良反應,如有必須馬上停止服用,沒有則可繼續使用。若忌煙酒等不良習慣,會使療效更佳。
【規格】通常為45千克至55千克,特殊情況下亦有例外。
【貯藏】常溫下妥善保存,室內陰涼處最佳;如在室外,則 避免強烈陽光直射。 貯藏期間,尤忌隨意棄置一旁不管
posted @
2006-03-23 12:00 surffish 閱讀(272) |
評論 (0) |
編輯 收藏
用java寫服務端代碼
import java.io.*;
import java.net.*;
public class test {
public test() {
}
public static final int PORT = 8080;
public static final String ip = "10.194.111.222";
public static void main(String[] args) throws IOException {
ServerSocket s = new ServerSocket(51,2,InetAddress.getByName(ip));
System.out.println("Started: " + s);
try {
// Blocks until a connection occurs:
Socket socket = s.accept();
try {
System.out.println(
"Connection accepted: "+ socket);
BufferedReader in =
new BufferedReader(
new InputStreamReader(
socket.getInputStream()));
// Output is automatically flushed
// by PrintWriter:
PrintWriter out =
new PrintWriter(
new BufferedWriter(
new OutputStreamWriter(
socket.getOutputStream())),true);
while (true) {
String str = in.readLine();
if (str.equals("END")) break;
System.out.println("Echoing: " + str);
out.println(str);
}
// Always close the two sockets...
} finally {
System.out.println("closing...");
socket.close();
}
} finally {
s.close();
}
}
}
.net寫客戶端代碼
private void button2_Click(object sender, System.EventArgs e)
{
try
{
stSend = new Socket ( AddressFamily.InterNetwork ,
SocketType.Stream , ProtocolType.Tcp ) ;
//初始化一個Socket實例
IPEndPoint tempRemoteIP = new IPEndPoint(IPAddress.Parse("10.194.111.222"),51);
//根據IP地址和端口號創建遠程終結點
EndPoint epTemp = ( EndPoint ) tempRemoteIP;
stSend.Connect ( epTemp ) ;
}
catch ( Exception err)
{
string s = err.ToString();
}
}
posted @
2005-12-09 16:36 surffish 閱讀(1189) |
評論 (0) |
編輯 收藏
1.工作區: (顯隱)
項目面板:ctrl + Alt + p (Project)
設計面板: ctrl + Alt + c (content)
結構面板: ctrl + Alt + s (Structure)
信息面板: ctrl + Alt + M (Message)
狀態面板: ctrl + Alt + Z
2.主面板:(代碼面板和設計面板)
激活代碼模塊: ctrl + J (@1)
參數提示信息的激活: ctrl + shift + H
打開查詢、替換窗口: ctrl + F
類的查詢: ctrl + -
3.F 鍵的用法
F1: 幫助快捷
F4: 運行多行
F5: 加入斷點
F7: 當遇到方法時會運行方法內的代碼
F8: 逐步運行代碼
F12: 代碼面板和設計面板切換
4. Shift 鍵的用法
添加多個相同組件: 按shift鍵在選項上選取組件,把組件添加到窗口即可
調整組件間間隔和對齊: 假設有組件JPanel 1/2/3;(要達到3個組件寬度相同,組件間隔相等,并且都是依據JPanel1左對齊),按shift鍵,用鼠標選中需要調整的組件,(第一個選中的組件是其他的基準)然后右鍵。
5: codeInsight 和 Codetemplates
MemberInsight -- 根據當前的代碼提示可用的類成員或方法(說明)
ParameterInsight -- 提示當前的方法需要使用的參數
SymbolInsigh -- 查看當前的變量、方法或者類的愿代碼。
MemberInsight: ctrl + space 或 ctrl + H
ParameterInsight: ctrl + shift + space 或 ctrl + shift + H
SymbolInsight: ctrl + Enter 或 Alt + shift + H
ClassInsight : ctrl + alt + space 或 ctrl + alt + H
注: (@1):使用代碼功能:(ctrl + J)
1、 在想要輸入代碼的位置輸入代碼摸板名,然后按 ctrl + J(開發人員可以用主菜單上的Tools/Editor/Templates命令來查看代碼摸板的名字)
2、把光標定位于想要輸入代碼的位置,然后按ctrl + J
posted @
2005-12-09 11:40 surffish 閱讀(301) |
評論 (0) |
編輯 收藏
http://blog.csdn.net/javamxj/archive/2004/10/11/131935.aspx
我是一名java的愛好者,理所當然裝了不少java方面的軟件,大部分是開放源碼的,而且多數是綠色軟件,只要解壓,設置一下環境變量即可使用。
由于軟件本身升級比較頻繁,經常需要重新設置使用的環境變量,而且我常常同時安裝同一軟件的不同版本(甚至是相同版本)。如eclipse我就分別在F,G,H三個盤上裝了不同的版本,一個是中文版,一個是英文的Latest Release,一個是Stream Stable,反正是綠色安裝,也不會發生沖突,這樣通過對比便于了解和測試最新版本的先進之處。
但是假如把JDK版本從1.3升級到1.4,即JDK目錄名可能要從“j2sdk1.3”改為“j2sdk1.4”,如果是這樣的話,那么eclipse可能會無法再啟動了(它要從環境變量中尋找JAVA_HOME變量,而JAVA_HOME變量值已經從“j2sdk1.3”改為“j2sdk1.4”了)。
在談談jakarta-tomcat,這個軟件升級比較頻繁,如果你是結合eclipse來使用Tomcat的,那么每次Tomcat升級,可能都要在eclipse中重新設置一下Tomcat的安裝目錄,是不是有些麻煩?
對于此類問題,解決的方法很簡單,只要把默認的軟件安裝目錄名去掉版本號即可(如果擔心忘記版本號,只要在目錄中添加一個readme文件加以說明即可)。
如上圖,我的j2sdk,ant,jakata-tomcat等都沒有版本號。
同樣,在環境變量設置中也沒有出現版本號。
這樣,如果再需要升級軟件時,僅僅把新版軟件安裝在舊版軟件目錄即可。其它一般都不需要再改動了。
另外,在環境變量設置中,可以用%變量%代替變量值,如Path變量值可以這樣設置: %JAVA_HOME%\bin;%JBOSS_HOME%\bin;%ANT_HOME%\bin;
posted @
2005-12-07 16:31 surffish 閱讀(482) |
評論 (0) |
編輯 收藏
我們要開發一個java類:其內容只有一句,輸出"hello ant"字符串。并使用ant完成編譯和運行工作,這個例子只是為了跑通ant,不附加多余的東西。
下圖為文件組織,請建立相應的目錄,并編寫HelloAnt.java

按照人家老外的文件組織規則咱也照搬。
在項目根目錄(hello-ant\)寫1個文件:ant執行配置文件build.xml
ok,一切大功告成,哦,不,還沒有運行它。
dos下進入hello-ant的目錄,即build.xml所在的目錄,我們要用ant工具執行它 ,
執行: %ant_home%/bin/ant -file build.xml 用ant工具執行當前目錄下的配置文件build.xml
或 :ant -file build.xml 你如果設置%ant_home%/bin到path中
這次ok了,這是答案:
命令提示符窗口 |
D:\temp\hello-ant>ant -file build.xml Buildfile: build.xml
main: [javac] Compiling 1 source file to D:\temp\hello-ant\build\classes [java] hello ant,ant 的第一次接觸,好棒!
BUILD SUCCESSFUL Total time: 2 seconds D:\temp\hello-ant> |
檢查一下build/classes目錄,哦,看到編譯過的文件就在這里:
build/classes/hello/ant/HelloAnt.class.
hello ant 進級
(此段比較廢話,可以略過)
你也許會說:這末簡單的工作寫個批處理不就得了,又xml又ant的,把我的時間都浪費完了,我用jbuild或
webShpere不就得了,怎末說你才明白呢?反正網上開源項目大多數都用ant,你總不能給人家個*.jpx吧,
而且這樣的工具太貴,受不了(當然用D的兄弟不怕^_^ ),而且ant可以讓你明確的管理和自動化所有的東西:
編譯-實施-測試...,哎,稍微麻煩一點點,但節約你以前花在零碎的copy,paste上的時間.而且我發現管理
代碼的質量有所提高.
我們要改進build.xml,讓它做更多的事情:
- 定義全局變量
- 初始化,主要是建立目錄
- 編譯 (已有)
- 打包為jar
- 建立API documentation
- 生成distribution產品
凡事都講究平衡,你要ant給你做更多事,當然要累一點點,不過只用累一次,以后的代碼修改后的構建都是"一鍵式"完成,我們制作一個hello的簡單例子,你可以自己做j2ee的練習。
我們要擴充目錄結構,使它更像回事:
ant處理編譯之前的目錄:

ant處理之后的目錄:

圖中:\src,\docs,\lib是自己組織的文件結構,\build,\dist是ant動態生成的成品。
\src 源文件:java源,script源,jsp源,xml配置.....
\src\main java源
\src\script window,unix,liunx的執行script,我們的簡單只有一個:
run.bat: java hello.ant.HelloAnt
\docs 手寫說明文檔
\lib 程序所需類庫的jar,比如j2ee.jar,mail,jar...
\build 用ant動態生成的構建目錄
\build\classes 編譯的類文件
\build\docs copy "\docs"的手寫說明文檔,和ant生成的api文檔
\build\lib 放置我們自己的HelloAnt.class打包成品hello-ant.jar
\dist\bin copy "\src\script" 得執行文件
\dist\docs copy "\build\docs" 的文檔
\dist\lib 除了copy "\build\lib"下的hello-ant.jar外,
還應copy "\lib"的程序所需jar,這里我們沒有。
以上是我學老外的文件組織,大家可以按照自己的愛好組織
我們編寫必要的文件:
hello.ant. HelloAnt.java |
已有 |
\docs\index.html 隨便寫一個手寫的文檔 |
hello ant 軟件項目手冊docs
訪問api文檔 |
build.xml多了些,但其實很簡單:(注釋比較詳細可以參照,這里再簡單說一下)
一個build.xml包含一個工程的自動化處理的完整xml說明,并且基本由3種東東組成:
<project >
1.全局變量的定義
<property/>
2.任務組
<target>
3.許多單項任務... 像copy,delete,javac,jar...
<task1/>
<task2/>
<task3/>
</target>
</project>
參考及下載:
本文程序:第1個hello-ant
本文程序:第2個進階的hello-ant
ant最新下載:
http://jakarta.apache.org/ant/index.html
ant具體的編寫方法參考ant手冊以下2部分就形,
http://jakarta.apache.org/ant/manual/using 使用說明
http://jakarta.apache.org/ant/manual/coretasklist.html 核心tasks
其他一大堆東西你要看也行。不過我覺得比較浪費時間。
http://jakarta.apache.org/ant/manual/index.html 手冊index
huihoo.com翻譯改編的ant/manual/using
http://www.huihoo.com/java/ant.html
用ANT構造Application作者:余斌斌
http://developer.ccidnet.com/pub/disp/Article?columnID=295&articleID=27619&pageNO=1
ibm 利用 Ant 和 JUnit 進行增量開發——使用單元測試來逐步改進代碼
http://www-900.ibm.com/developerWorks/cn/java/j-ant/index.shtml
posted @
2005-12-07 14:33 surffish 閱讀(580) |
評論 (1) |
編輯 收藏
本文以最新發布的Ant 1.5.1為例,介紹這款優秀的Build工具的安裝配置、基本應用和一些高級話題。最新的Ant下載地址是
http://jakarta.apache.org/ant/ 。
Ant是一種基于Java的Build工具。理論上來說,它有些類似于C中的make,但比make優越。現在存在的大多數Build工具,如make、gnumake、nmake、jam等都存在這樣或那樣的不足,比如依賴于特定的平臺、配置文件過于復雜或者對格式無法檢查而容易出錯等。與這些工具相比較,Ant的兩個特性決定了它是一款優秀的Build工具:
1. 基于Java的實現。具有良好的跨平臺性,同時可以通過增加新的Java類來擴展Ant的功能,而無需去了解不同平臺上不同的腳本語言。
2.基于XML的配置文件。Ant以XML樹來描述Target/Task的關系,文件結構清晰、易讀易寫,并且利用XML對格式的控制來避免由于配置文件的錯誤造成的Build操作失敗。
安裝與配置
Ant的安裝非常簡單,把從網上下載的jakarta-ant-1.5.1-bin.zip解開到一個目錄下即可(以下假定安裝在目錄D:\jakarta-ant-1.5.1)。接下來需要進行環境變量配置:
SET ANT_HOME=D:\jakarta-ant-1.5.1 //注意是Ant的安裝目錄,不是bin子目錄 SET PATH=%PATH%;%ANT_HOME%\bin; |
在配置環境變量之前,請確認已經正確設置了JAVA_HOME系統變量。輸入ant命令,看到如下輸出說明已成功安裝了Ant工具:
Buildfile: build.xml does not exist! Build failed |
提示信息表明在當前目錄不存在build.xml配置文件,但這本身已經說明Ant成功運行了。
快速入門
下面用一個最簡單也是最經典的例子-HelloWorld來感受一下Ant吧。
//HelloWorld.java package com.sharetop.antdemo; public class HelloWorld { public static void main( String args[] ) { System.out.println("Hello world. "); } } |
要讓Ant編譯這個文件,首先需要編寫一個Build配置文件。在一般情況下,這個文件被命名為build.xml。
<?xml version="1.0" encoding="UTF-8" ?> <project name="HelloWorld" default="run" basedir="." > <property name="src" value="src"/> <property name="dest" value="classes"/> <property name="hello_jar" value="hello.jar" /> <target name="init"> <mkdir dir="${dest}"/> </target> <target name="compile" depends="init"> <javac srcdir="${src}" destdir="${dest}"/> </target> <target name="build" depends="compile"> <jar jarfile="${hello_jar}" basedir="${dest}"/> </target> <target name="run" depends="build"> <java classname="com.sharetop.antdemo.HelloWorld" classpath="${hello_jar}"/> </target> </project> |
來看一下這個文件的內容,它描述了以下信息:工程的名字為HelloWorld,工程有四個target,分別是init、compil、build和run,缺省是run。compile只有一個任務javac,源文件位于src目錄下,輸出的類文件要放在classes目錄下。build的任務是jar,生成的jar文件為hello.jar,它打包時以classes為根目錄。而run則是執行這個HelloWorld類,用hello.jar作為classpath。這四個target之間有一個依賴關系,這種關系用depends來指定。即如果Target A依賴于Target B,那么在執行Target A之前會首先執行Target B。所以從下面運行缺省Target(run)的輸出看,這四個Target的執行順序是:init→compile→build→run。文件目錄結構如圖1所示。HelloWorld.java文件在src\com\sharetop\antdemo子目錄下。
圖1 ant_demo應用的目錄結構
在命令行輸入命令:ant,然后運行,可以看到如下輸出:
如果配置文件名不是build.xml,比如是build_front.xml,那么,可以使用-buildfile命令參數指定:
G:\myDoc\ant_demo>ant -buildfile build_front.xml |
也可以單獨執行指定的某個target,比如,只編譯不打包執行,可以使用下面輸入命令即可:
G:\myDoc\ant_demo>ant compile |
在相應的目錄下會找到編譯出的HelloWorld.class文件。
再看看上面的build.xml配置文件,文件開頭定義了3個屬性,分別指定了源文件輸出路徑、類文件輸出路徑和生成的Jar文件名,后面對這些路徑的引用都通過一個${property name}來引用。所以,要注意這樣一個原則“目錄的定義與目錄的引用應該分開”。
基本應用
建立工程的目錄 一般要根據工程的實際情況來建立工程的目錄結構。但是,有一些比較通用的組織形式可供參考,比如所有的jakarta項目都使用類似的目錄結構。下面讓我們來看一下這種目錄結構的特點。
表1
目錄 |
文件 |
bin |
公共的二進制文件,以及運行腳本 |
build |
臨時創建的文件,如類文件等 |
dist |
目標輸出文件,如生成Jar文件等。 |
doc/javadocs |
文檔。 |
lib |
需要導出的Java包 |
src |
源文件 |
對于一個簡單的工程,一般包括表1的幾個目錄。其中bin、lib、doc和src目錄需要在CVS的控制之下。當然在這樣的目錄結構上,也可以做一些調整,例如,可以建立一個extra目錄來放置需要發布的Jar文件、Inf文件及圖像文件等。同樣,如果開發Web應用可以建立一個Web目錄放置JSP、HTML等文件。
如果我們開發的是一個比較復雜的項目,包括多個子項目,并且各個子項目是由不同的開發人員來完成的,那么要如何來設計它的目錄結構?首先有一點是需要確定的,不同的子項目應該擁有不同的Build文件,并且整個項目也應該有一個總的Build文件。可以通過Ant任務或是AntCall任務調用子項目的Build文件,如下例:
<target name="core" depends="init"> <ant dir="components" target="core"/> <ant dir="waf/src" target="core"/> <ant dir="apps" target="core"/> </target> |
在各個子項目的耦合不是非常緊密的情況下,各個子項目應該有各自獨立的目錄結構,也就是說它們可以有自己的src、doc、build、dist等目錄及自己的build.xml文件,但是可以共享lib和bin目錄。而對于那些耦合緊密的子項目,則推薦使用同一個src目錄,但是不同的子項目有不同的子目錄,各個子項目的build.xml文件可以放在根目錄下,也可以移到各個子項目的目錄下。
編寫Build文件 要用好Ant工具,關鍵是要編寫一個build.xml文件。要編寫出一個結構良好、靈活可擴展的Build文件,有兩個問題要考慮,一是了解Build文件的基本結構,二是了解Ant定義的大量任務。
Ant的Build文件是一個標準的XML文件,它包含一個根節點Project,每個Project定義了至少一個或多個Target,每個Target又是一系列Task的集合。它們之間的關系如圖2所示。

圖2 build.xml文件的結構
每個Task是一段可被執行的代碼,比如,前例中的javac、jar就是兩個最常用的Task。Ant定義了大量的核心Task,我們要考慮的第二個問題正是如何去掌握這大量的Task。其實唯一的方法就是邊學習邊實踐,這方面最好的參考就是官方的Ant使用手冊。
外部文件的使用 使用外部的Property文件可以保存一些預設置的公共屬性變量。這些屬性可以在多個不同的Build文件中使用。
可以將一個外部的XML文件導入Build文件中,這樣多個項目的開發者可以通過引用來共享一些代碼,同樣,這也有助于Build文件的重用,示例代碼如下所示:
<!DOCTYPE project [ <!ENTITY share-variable SYSTEM "file:../share-variable.xml"> <!ENTITY build-share SYSTEM "file:../build-share.xml"> ]> <project name="main" default="complie" basedir="."> &share-variable; &build-share; ... ... |
在J2EE項目中的應用
只要掌握了Ant的使用方法,在J2EE項目中的應用與在其它項目中的應用并沒有太大的不同,但是仍有幾點是需要注意的。
一是要清楚War和Jar文件的目錄結構,主要是War的配置文件web.xml文件的位置和EJB的配置文件(ejb-jar.xml和weblogic-ejb-jar.xml等)的位置,在調用Jar任務打包文件時一定要記得把它們也包含進來。一般在編譯之前就要注意把這些需打包的文件拷入相應目錄下。二是在J2EE項目中可能會涉及到一些特殊的任務,比如在Weblogic中會調用ejbc預編譯EJB的代碼存根,或者需要在Ant中同時發布Jar到相應的服務器中等。可以用兩種途徑實現這些任務,一是擴展Ant任務實現這些任務,二是直接用Java任務來執行這些命令。下面是打包、發布一個EJB的build.xml配置文件片斷,代碼如下:
<target name="deploy_HelloEJB" depends="compile"> <delete dir="${temp}/ejb_make"/> <!-- 首先刪除臨時目錄 --> <delete file="${temp}/helloEJB.jar"/> <!-- 刪除WebLogic域中老版本的EJB --> <delete file="${weblogic.deploy.dest}/helloEJB.jar"/> <!-- 創建META-INF目錄,放置ejb-jar.xml和weblogic-ejb-jar.xml --> <mkdir dir="${temp}/ejb_make/META-INF"/> <!-- 拷貝ejb-jar.xml和weblogic-ejb-jar.xml 到臨時目錄--> <copy todir="${temp}/ejb_make/META-INF"> <fileset dir="etc/baseinfo"> <include name="*.xml"/> </fileset> </copy> <!-- 拷貝所有的helloEJB類到臨時目錄 --> <copy todir="${temp}/ejb_make/"> <fileset dir="${dest.classes}/"> <!-- dest.classes是輸出的類文件目錄 --> <include name="${dest.classes}/helloEJB/**"/> </fileset> </copy> <!-- 將所有這些文件打包成helloEJB.jar --> <jar jarfile="${temp}/helloEJB.jar" basedir="${temp}/ejb_make"/> <!-- 進行weblogic.ejbc編譯 --> <java classpath="${wl_cp}" classname="weblogic.ejbc" fork="yes" > <classpath> <fileset dir="lib"> <include name="*.jar" /> </fileset> </classpath> <arg value="${temp}/helloEJB.jar" /> <arg value="${temp}/helloEJB_deploy.jar" /> </java> <!-- 拷貝/發布到WebLogic的{DOMAIN}\applications目錄 --> <copy file="${temp}/helloEJB_deploy.jar" todir="${weblogic.deploy.dest}"/> </target> |
用Ant配合JUnit實現單元測試
Ant 提供了JUnit任務,可以執行單元測試代碼。如何使用JUnit,以及如何編寫測試用例(TestCase),感興趣的讀者可以參閱JUnit的相關文檔。在Ant中使用JUnit的方法非常簡單,首先需要把junit.jar拷入ANT_HOME\lib下,確認在這個目錄下有optional.jar,因為JUnit是Ant的擴展任務,需要引用這個擴展包。然后就是在Build文件中加入JUnit的任務,代碼如下:
<target name="run" depends="client"> <junit printsummary="yes" fork="yes" haltonfailure="yes"> <classpath> <pathelement location="client.jar" /> </classpath> <formatter type="plain" /> <test name="com.sharetop.antdemo.HelloWorldTest" /> </junit> </target> |
高級話題
為Ant開發擴展任務 為Ant實現擴展任務其實是非常容易的,只需按照以下幾個步驟即可:
1. 創建一個Java類繼承org.apache.tools.ant.Task類;
2. 對每個屬性實現set方法。Ant會根據需要自動完成類型轉換;
3. 如果擴展的任務需要嵌套其它的Task,那么這個Java類必需實現接口org.apache.tools.ant.TaskContainer;
4. 如果擴展的任務要支持Text,需要增加一個方法void addText(String);
5. 對每個嵌套的元素,實現create、add 或 addConfigured 方法;
6. 實現public void execute方法;
7. 在build.xml文件中使用 <taskdef> 來引用自定義的Task。
下面以一個簡單的例子來說明如何為Ant增加一個hello任務,它可以連續打印多條信息,打印的次數由屬性count指定,而打印的內容則由它內嵌的一個helloinfo任務的message屬性指定,看上去這非常類似JSP中自定義標簽的一些概念,實現代碼如下:
//HelloInfoTask.java package com.sharetop.antdemo; import org.apache.tools.ant.*; public class HelloInfoTask { private String msg; public void execute() throws BuildException { System.out.println(msg); } public void setMessage(String msg) { this.msg = msg; } } |
下面是外部Task類的代碼:
//HelloTask.java package com.sharetop.antdemo; import org.apache.tools.ant.*; public class HelloTask extends Task implements org.apache.tools.ant.TaskContainer { private Task info; private int count; public void execute() throws BuildException { for(int i=0;i<count;i++) info.execute(); } public void setCount(int c){ this.count=c; } public void addTask(Task t){ this.info=t; } } |
實現了這兩個Task,在build.xml文件中定義它的task name,就可以在Target中執行它了。如果你不想使用 <taskdef> 標簽來定義Task,也可以通過修改default.properties文件來實現引入新Task,這個文件位于org.apache.tools.ant.taskdefs 包里。下例是一個使用 標簽來引入新Task的Build文件部分:
<target name="hello" depends="client"> <taskdef name="hello" classname="com.sharetop.antdemo.HelloTask" classpath="client.jar"/> <taskdef name="helloinfo" classname="com.sharetop.antdemo.HelloInfoTask" classpath="client.jar"/> <hello count="3" > <helloinfo message="hello world" /> </hello> </target> |
在自己的程序中調用Ant
Ant的任務其實就是一段功能代碼。Ant內置的大量任務對于我們開發Java應用具有非常大的意義,為什么我們不能直接使用呢?
因為盡管在程序中調用Ant的任務并不復雜,而且我們知道Ant的任務其實都是一些Java類,調用的方法無非就是執行這些類而已,不過在執行之前需要對它做一些初始化的工作,所以我們需要引用一個Task類的子類來實現這個功能,比如如下代碼:
package com.sharetop.antdemo; import org.apache.tools.ant.*; import org.apache.tools.ant.taskdefs.*; import java.io.File; public class RunAntTask { public RunAntTask() { } public static void main(String args[]){ AntJAR j = new AntJAR(); j.setBasedir(new File("./classes")); j.setJarfile(new File("aaa.jar")); j.execute(); } } final class AntJAR extends Jar { public AntJAR() { project = new Project(); project.init(); taskType = "jar"; taskName = "jar"; } } |
注意AntJAR類的構造方法,先創建了Project并初始化它,這是直接調用Task的必需條件。
如果要在自己的程序中執行Ant,需要了解的是Ant定義的幾個BuildEvent,它包括:
◆ Build started
◆ Build finished
◆ Target started
◆ Target finished
◆ Task started
◆ Task finished
◆ Message logged
我們需要做的是實現BuildListener接口來處理各種事件,而執行Ant的方法與上面給的例子非常類似,以實際開發的AntBuilder軟件的部分代碼為例:
public void buildTarget(String targetName,String buildFileName) { try { Project p = new Project(); p.init(); File f = new File(buildFileName); p.setUserProperty("ant.file",f.getAbsolutePath()); ProjectHelper.configureProject(p,f); p.addBuildListener(this); if( targetName==null ) p.executeTarget(p.getDefaultTarget()); else p.executeTarget(targetName); } catch (Exception ex) { jTextArea1.append(ex.getMessage()); } } |
創建Project并初始化,設置它的配置文件(build.xml),執行它缺省的或指定的Target,然后在實現了BuildListenser接口的監聽器類中對你感興趣的事件作處理,代碼如下:
public void buildStarted(BuildEvent event){ /* nothing*/ } public void buildFinished(BuildEvent event) { /* nothing*/ } public void targetStarted(BuildEvent event) { this.jTextArea1.append(event.getTarget().getName()+": \n\r"); } public void targetFinished(BuildEvent event) {/* nothing*/ } public void taskStarted(BuildEvent event) {/* nothing*/ } public void taskFinished(BuildEvent event) { /* nothing*/ } public void messageLogged(BuildEvent event) { int prior = event.getPriority(); switch(prior){ case Project.MSG_ERR : this.jTextArea1.append("["+event.getTask().getTaskName()+"]Err:" +event.getMessage()); break; case Project.MSG_INFO: this.jTextArea1.append("["+event.getTask().getTaskName()+"]"+event.getMessage ()); break; case Project.MSG_WARN: this.jTextArea1.append("["+event.getTask().getTaskName()+"]" +event.getMessage()); break; case Project.MSG_VERBOSE: this.jTextArea1.append(event.getMessage()); break; } } |
Build.xml文件的寫法每個公司都有不同,這里沒有太大的參考價值,所以略去。(全文完)
posted @
2005-12-07 14:29 surffish 閱讀(1658) |
評論 (0) |
編輯 收藏
//服務器代碼
/********************************Main******************************/
import java.io.*;
import java.net.*;
import java.util.*;
public class ServerMain{
public static Vector socketVector=new Vector();
public static void main(String[] args) throws IOException{
System.out.println("服務器啟動........");
ServerSocket s = new ServerSocket(5000);
while(true){
Socket soc = s.accept();
SocketThread st=new SocketThread(soc);
socketVector.addElement(st);
st.start();
}
}
public static void sendEveryone(String msg){
Object object=null;
int len=socketVector.size();
for(int i=0;i<len;i++){
try {
object=socketVector.elementAt(i);
SocketThread st = (SocketThread)object;
st.sender.send(msg);
}
catch (Exception ex) {
socketVector.removeElement(object);
}
}
}
public static void removeObject(Object object){
socketVector.removeElement(object);
}
public static void removeObject(Sender sender) throws Exception{
int len=socketVector.size();
for(int i=0;i<len;i++){
Object object=socketVector.elementAt(i);
SocketThread st = (SocketThread)object;
if(st.sender==sender)
socketVector.removeElement(object);
}
}
}
/*********************************SocketThread **********************/
import java.io.*;
import java.net.*;
import java.util.*;
public class SocketThread implements Runnable{
public Socket socke;
public DataInputStream dis;
public DataOutputStream dos;
public Sender sender;
private boolean stop;
Calendar date;// = Calendar.getInstance(TimeZone.getTimeZone("Asia/ShangHai"));
public SocketThread(Socket sok){
socke=sok;
}
public void start(){
Thread t=new Thread(this);
t.start();
}
public void run() {
try {
socke.setKeepAlive(true);
dis = new DataInputStream(socke.getInputStream());
dos = new DataOutputStream(socke.getOutputStream());
sender = new Sender(dos);
while (true) {
StringBuffer sb = new StringBuffer();
char c;
while (((c = dis.readChar()) != '\n') && (c != -1)) {
sb.append(c);
}
if (c == -1) {
break;
}
date = Calendar.getInstance(TimeZone.getTimeZone("Asia/ShangHai"));
String ljnTime="("+date.get(date.YEAR)+"/"+(date.get(date.MONTH)+1)+"/"+date.get(date.DATE)+" "+date.get(date.HOUR_OF_DAY)+":"+date.get(date.MINUTE)+":"+date.get(date.SECOND)+")";
String acceptMsg=sb.toString();
System.out.println(ljnTime+acceptMsg);
ServerMain.sendEveryone(acceptMsg);
}
stop();
ServerMain.removeObject(this);
} catch (IOException ioe) {
} catch (Exception e) {
e.printStackTrace();
}
}
public void stop() {
try {
stop = true;
if(sender!=null){
sender.stop1();
}
if (dis != null) {
dis.close();
}
if (dos != null) {
dos.close();
}
if (socke != null) {
socke.close();
}
} catch (IOException ioe) {
}
}
}
/*********************************************Sender**************************/
import java.io.*;
public class Sender extends Thread {
private DataOutputStream dos;
private String message;
public Sender(DataOutputStream os) {
this.dos = os;
start();
}
public synchronized void send(String msg) {
message = msg;
notify();
}
public synchronized void run() {
while (true) {
if (message == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
if (message == null) {
break;
}
try {
dos.writeChars(message);
dos.writeChars("\r\n");
} catch (IOException ioe) {
try {
ServerMain.removeObject(this);
}
catch (Exception ex) {
}
}
message = null;
}
}
public synchronized void stop1() {
message = null;
notify();
}
}
//下面為手機客戶端代碼
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class ChatClientMIDlet extends MIDlet {
private static ChatClientMIDlet instance;
public static ChatForm displayable = new ChatForm();
/** Constructor */
public ChatClientMIDlet() {
instance = this;
}
/** Main method */
public void startApp() {
Display.getDisplay(this).setCurrent(displayable);
}
/** Handle pausing the MIDlet */
public void pauseApp() {
}
/** Handle destroying the MIDlet */
public void destroyApp(boolean unconditional) {
}
public static void setCurrent(Displayable s){
Display.getDisplay(instance).setCurrent(s);
}
/** Quit the MIDlet */
public static void quitApp() {
instance.destroyApp(true);
instance.notifyDestroyed();
instance = null;
}
}
/********************************************************ChatForm ************************/
import com.nec.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.io.*;
import java.io.*;
public class ChatForm extends Form implements CommandListener,Runnable {
public Form mainForm=new Form("聊天室");
public Command enter=new Command("進入",Command.OK,0);
public Command send=new Command("發送",Command.OK,1);
public Command exit=new Command("退出",Command.EXIT,0);
public DataInputStream dis;
public DataOutputStream dos;
public SocketConnection sc;
public Sender sender;
public boolean stop;
public TextField textField=new TextField("請輸入昵稱:", null, 10, TextField.ANY);
public TextField info=new TextField("請輸入消息:", null,255, TextField.ANY);
public ChoiceGroup choiceGroup=new ChoiceGroup(null,ChoiceGroup.EXCLUSIVE);
public String MyName="游客";
public boolean isCurrent=false;;
public ChatForm() {
super("我的聊天室");
append(textField);
addCommand(enter);
mainForm.append(info);
mainForm.append(choiceGroup);
choiceGroup.append(");
setCommandListener(this);
mainForm.addCommand(send);
mainForm.addCommand(exit);
mainForm.setCommandListener(this);
}
public void commandAction(Command c, Displayable dis) {
if(c==enter){
if(textField.getString().length()==0){
Alert alert=new Alert("警告","昵稱不能為空!", null, AlertType.WARNING) ;
alert.setTimeout(3000);
ChatClientMIDlet.setCurrent(alert);
return;
}else
{
MyName = textField.getString();
append("正在進入......");
}
Thread t=new Thread(this);
t.start();
}else if(c==send){
if(info.getString().length()==0){
Alert alert=new Alert("警告","消息內容不能為空!", null, AlertType.WARNING) ;
alert.setTimeout(3000);
ChatClientMIDlet.setCurrent(alert);
return;
}
sender.send(MyName+"說:"+info.getString());
info.setString("");
}
else{
stop();
ChatClientMIDlet.quitApp();
}
}
public void run() {
try {
sc = (SocketConnection) Connector.open("socket://127.0.0.1:5000");
sc.setSocketOption(SocketConnection.LINGER, 5);
dis = new DataInputStream(sc.openInputStream());
dos = new DataOutputStream(sc.openOutputStream());
sender = new Sender(dos);
sender.send("歡迎"+MyName+"進入房間");
while (true) {
if(stop) break;
StringBuffer sb = new StringBuffer();
char c;
while (((c = dis.readChar()) != '\n') && (c != -1)) {
sb.append(c);
}
if (c == -1) break;
if(!isCurrent){
ChatClientMIDlet.setCurrent(mainForm);
isCurrent=true;
}
String msg=sb.toString();
msg=msg.substring(0,msg.length()-2);
choiceGroup.insert(0,msg,null);
choiceGroup.setSelectedIndex(0,true);
}
stop();
} catch (ConnectionNotFoundException cnfe) {
} catch (IOException ioe) {
if (!stop) {
ioe.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void stop() {
try {
stop = true;
if (sender != null) {
sender.stop1();
}
if (dis != null) {
dis.close();
}
if (dos != null) {
dos.close();
}
if (sc != null) {
sc.close();
}
} catch (IOException ioe) {
}
}
}
/**************************Sender*********************************/
同上
posted @
2005-11-22 12:54 surffish 閱讀(1080) |
評論 (2) |
編輯 收藏
//怎樣獲取一個文件夾下中的所有文件File dir = new File("fileDirectory");
String[] filel= dir.list();
//oracle啟動方法
--啟動數據庫
su - oracle
sqlplus /nolog
connect /as sysdba
startup
exit
--監聽
lsnrctl
start
posted @
2005-11-21 09:57 surffish 閱讀(229) |
評論 (0) |
編輯 收藏
telnet 10.194.132.1
ftp 192.168.10.1
ls
vi
i
esc
:wq
ctrl + c
cp
posted @
2005-11-10 15:23 surffish 閱讀(288) |
評論 (0) |
編輯 收藏
在Weblogic 8.1 sp1 上調試《精通EJB 2》源代碼
----連接池及數據源ejbPool的配置.
作者: naxin9999@163.com
--------------------------------------------------------------------------------
一. 首先在mysql數據庫中新建一個me2庫,再建一個sa用戶(密碼:222222).授予權限.再提交源代碼中的EJB.sql文件 ( 在EJB.sql文件頭加上use me2; )。
具體如下:
d:\mysql –u root –p
mysql> create database me2;
mysql> GRANT ALL PRIVILEGES ON me2.* TO sa@'localhost' IDENTIFIED BY '222222' WITH GRANT OPTION;
mysql> quit
d:\ mysql –u sa –p < EJB.sql
password: (輸入222222)
完成.
二. 下面開始創建DS:
a. 把mysql的驅動程序mm.mysql-2.0.14-bin.jar復制到 D:\bea\weblogic81\server\lib 目錄下.
b. 修改D:\bea\user_projects\domains\mydomain 目錄下的startweblogic.cmd文件中的 CLASSPATH設置,加上%WL_HOME%\server\lib\mm.mysql-2.0.14-bin.jar;
c. 起動weblogic,登陸 http://localhost:7001/console
--------------------------------------------------------------------------------
1.先建個pool (下圖)

--------------------------------------------------------------------------------
2. (下圖)

--------------------------------------------------------------------------------
3. (下圖)

--------------------------------------------------------------------------------
4. (下圖)

--------------------------------------------------------------------------------
5. (下圖)

--------------------------------------------------------------------------------
6. (下圖)
--------------------------------------------------------------------------------
7. 再建JDBC DS (下圖)

--------------------------------------------------------------------------------
8. (下圖)

--------------------------------------------------------------------------------
9. (下圖)

--------------------------------------------------------------------------------
10(下圖)

--------------------------------------------------------------------------------
11. (下圖)

--------------------------------------------------------------------------------
12. 部署你的EJB,可以進行測試了(下圖)

--------------------------------------------------------------------------------
13. 運行cmp 2.0的例子. Client輸出:

14. Console 上輸出

1. 在http://localhost:7001/console 找到 Configure a new JMS Topic..

2.如下圖輸入:

3.Create成功后.

4.部署你的消息驅動Bean

5.運行客戶端,run_client.bat

6.weblogic控制臺上的輸出.

posted @
2005-10-31 15:35 surffish 閱讀(274) |
評論 (0) |
編輯 收藏
/*$T BYBARP~1.H GC 1.137 09/13/05 08:37:52 */
#ifndef ByBarPrinterH
#define ByBarPrinterH
#include "vcl.h"
#define BPLA_OK 1000 //一切正常
///
#define BPLA_COMERROR 1001 //通訊錯或者未聯接打印機
#define BPLA_PARAERROR 1002 //參數錯誤
#define BPLA_FILEOPENERROR 1003 //文件打開錯誤
#define BPLA_FILEREADERROR 1004 //文件讀錯誤
#define BPLA_FILEWRITEERROR 1005 //文件寫錯誤
#define BPLA_FILEERROR 1006 //文件不合要求
#define BPLA_NUMBEROVER 1007 //指定的接收信息數量過大
#define BPLA_IMAGETYPEERROR 1008 //圖象文件格式不正確
#define BPLA_PAPERSHORT 1009 //缺紙
#define BPLA_RIBBIONSHORT 1010 //缺色帶
#define BPLA_BUSY 1011 //解釋器忙
#define BPLA_PAUSE 1012 //暫停
///中
#define BPLA_HEADHEAT 1013 //打印頭過熱
#define BPLA_HEADOVER 1014 //打印頭抬起
#define BPLA_CUT 1015 //切刀錯
#define BPLA_READERROR 1016 //read error
//打開端口
typedef int (__stdcall *mBY_Open_Port) (int devtype, int porttype, char *opencode, int codelength, int baudrate);
//打印
typedef int (__stdcall *mBY_Print_Label)
(
int LabelType,
const char *JiDaJu,
const char *FenFaJu,
const char *TiaoMaXinXi,
const char *HaoMa,
const char *JianShu,
const char *ZhongLiang,
const char *ZhuanKouJuDaiHao,
const char *XingHao,
const char *BeiZhu,
const char *BiaoPaiBianHao,
const char *ZhongLeiJianCheng,
const char *BenZhuan,
int Pieces
);
//查詢狀態
typedef int (__stdcall *mBY_Query_Status) ();
//關閉端口
typedef int (__stdcall *mBY_Close_Port) (char *closecode, long codelength);
class PACKAGE CByBarPrinter
{
public:
long OpenPort(long nPcIndex, long nPortIndex, long baudrate);
void ClosePort(void);
long PrintLabel
(
long LabelType,
String JiDaJu,
String FenFaJu,
String TiaoMaXinXi,
String HaoMa,
String JianShu,
String ZhongLiang,
String ZhuanKouJuDaiHao,
String XingHao,
String BeiZhu,
String BiaoPaiBianHao,
String ZhongLeiJianCheng,
String BenZhuan,
long Pieces
);
CByBarPrinter(void);
long GetStatus(void);
private:
HINSTANCE m_hDll;
bool LoadLib(void);
};
#endif
/*$T BYBARP~1.CPP GC 1.137 09/13/05 08:37:52 */
#pragma hdrstop
#include "ByBarPrinter.h"
/* ---------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------- */
CByBarPrinter::CByBarPrinter(void)
{
m_hDll = NULL;
}
/* ---------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------- */
bool CByBarPrinter::LoadLib(void)
{
if(m_hDll == NULL) m_hDll = ::LoadLibrary("byprndll.dll");
if(m_hDll == NULL)
return false;
else
return true;
}
/* ---------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------- */
long CByBarPrinter::OpenPort(long nPcIndex, long nPortIndex, long baudrate)
{
long retCode;
if(!LoadLib())
{
retCode = -2;
return retCode;
}
mBY_Open_Port BY_Open_Port;
BY_Open_Port = (mBY_Open_Port) GetProcAddress(m_hDll, "BY_Open_Port");
if(BY_Open_Port == NULL)
{
retCode = -1;
}
else
{
String szCom;
szCom = "COM";
szCom += IntToStr(nPortIndex);
int nLen = szCom.Length();
retCode = BY_Open_Port(nPcIndex, nPortIndex, szCom.c_str(), nLen, 19200);
}
return retCode;
}
/* ---------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------- */
void CByBarPrinter::ClosePort(void)
{
if(!LoadLib()) return;
mBY_Close_Port BY_Close_Port;
BY_Close_Port = (mBY_Close_Port) GetProcAddress(m_hDll, "BY_Close_Port");
char CloseCode[50];
int CodeLength = 0;
memset(CloseCode, 0, 50);
BY_Close_Port(CloseCode, CodeLength);
//FreeLibrary(m_hDll);
delete[] CloseCode;
return;
}
/* ---------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------- */
long CByBarPrinter::PrintLabel
(
long LabelType,
String JiDaJu,
String FenFaJu,
String TiaoMaXinXi,
String HaoMa,
String JianShu,
String ZhongLiang,
String ZhuanKouJuDaiHao,
String XingHao,
String BeiZhu,
String BiaoPaiBianHao,
String ZhongLeiJianCheng,
String BenZhuan,
long Pieces
)
{
long retCode;
if(!LoadLib())
{
retCode = -2;
return retCode;
}
//USES_CONVERSION;
mBY_Print_Label BY_Print_Label;
BY_Print_Label = (mBY_Print_Label) GetProcAddress(m_hDll, "BY_Print_Label");
if(BY_Print_Label == NULL)
{
retCode = -1;
return S_OK;
}
retCode = BY_Print_Label
(
LabelType,
JiDaJu.c_str(),
FenFaJu.c_str(),
TiaoMaXinXi.c_str(),
HaoMa.c_str(),
JianShu.c_str(),
ZhongLiang.c_str(),
ZhuanKouJuDaiHao.c_str(),
XingHao.c_str(),
BeiZhu.c_str(),
BiaoPaiBianHao.c_str(),
ZhongLeiJianCheng.c_str(),
BenZhuan.c_str(),
Pieces
);
return retCode;
}
/* ---------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------- */
long CByBarPrinter::GetStatus(void)
{
long state;
if(!LoadLib())
{
state = -1;
return state;
}
mBY_Query_Status BY_Query_Status;
BY_Query_Status = (mBY_Query_Status) GetProcAddress(m_hDll, "BY_Query_Status");
if(BY_Query_Status == NULL)
state = -1;
else
state = BY_Query_Status();
return state;
}
#pragma package(smart_init)
posted @
2005-10-31 13:54 surffish 閱讀(248) |
評論 (0) |
編輯 收藏
substr(string,1,8)
1.
//將一個表中符合條件的記錄批量更新到另外一張表。(假設表名為:toffice,tofficetemp)
??????update toffice a
??????set a.office_code = (select b.office_code from tofficetemp b where a.jgdm = b.jgdm)
??????where a.jgdm in (select jgdm from tofficetemp)
??????update tofficenexas set isuse = '0' where rowid in?
??????(select rowid from tofficenexas a where?
??????rowid !=(select max(rowid) from tofficenexas b where a.office_id = b.office_id and
??????a.father_office_id = b.father_office_id and a.big_kind_id =b.big_kind_id))
2
//查詢某個時間段的值
select * from tdespatch t
where t.out_time between to_date('2005-10-18 15:47:42','yyyy-mm-dd hh24:mi:ss')
?and to_date('2005-10-20 10:47:42','yyyy-mm-dd hh24:mi:ss')
3。
//復制表(只復制結構,源表名:a?新表名:b)
SQL:?select?*?into?b?from?a?where?1<>1
4。
//拷貝表(拷貝數據,源表名:a?目標表名:b)
SQL:?insert?into?b(a,?b,?c)?select?d,e,f?from?b;
5。
說明:顯示文章、提交人和最后回復時間
SQL:?select?a.title,a.username,b.adddate?from?table?a,(select?max(adddate)?adddate?from?table?where?table.title=a.title)?b
說明:外連接查詢(表名1:a?表名2:b)
SQL:?select?a.a,?a.b,?a.c,?b.c,?b.d,?b.f?from?a?LEFT?OUT?JOIN?b?ON?a.a?=?b.c
說明:日程安排提前五分鐘提醒
SQL:??select?*?from?日程安排?where?datediff('minute',f開始時間,getdate())>5
說明:兩張關聯表,刪除主表中已經在副表中沒有的信息
SQL:??
delete?from?info?where?not?exists?(?select?*?from?infobz?where?info.infid=infobz.infid?)?
說明:--
SQL:??
SELECT?A.NUM,?A.NAME,?B.UPD_DATE,?B.PREV_UPD_DATE
??FROM?TABLE1,?
????(SELECT?X.NUM,?X.UPD_DATE,?Y.UPD_DATE?PREV_UPD_DATE
????????FROM?(SELECT?NUM,?UPD_DATE,?INBOUND_QTY,?STOCK_ONHAND
????????????????FROM?TABLE2
??????????????WHERE?TO_CHAR(UPD_DATE,'YYYY/MM')?=?TO_CHAR(SYSDATE,?'YYYY/MM'))?X,?
????????????(SELECT?NUM,?UPD_DATE,?STOCK_ONHAND
????????????????FROM?TABLE2
??????????????WHERE?TO_CHAR(UPD_DATE,'YYYY/MM')?=?
????????????????????TO_CHAR(TO_DATE(TO_CHAR(SYSDATE,?'YYYY/MM')?¦¦?'/01','YYYY/MM/DD')?-?1,?'YYYY/MM')?)?Y,?
????????WHERE?X.NUM?=?Y.NUM?(+)
??????????AND?X.INBOUND_QTY?+?NVL(Y.STOCK_ONHAND,0)?<>?X.STOCK_ONHAND?)?B
WHERE?A.NUM?=?B.NUM
說明:--
SQL:??
select?*?from?studentinfo?where?not?exists(select?*?from?student?where?studentinfo.id=student.id)?and?系名稱='"&strdepartmentname&"'?and?專業名稱='"&strprofessionname&"'?order?by?性別,生源地,高考總成績
說明:
從數據庫中去一年的各單位電話費統計(電話費定額賀電化肥清單兩個表來源)
SQL:?
SELECT?a.userper,?a.tel,?a.standfee,?TO_CHAR(a.telfeedate,?'yyyy')?AS?telyear,
??????SUM(decode(TO_CHAR(a.telfeedate,?'mm'),?'01',?a.factration))?AS?JAN,
??????SUM(decode(TO_CHAR(a.telfeedate,?'mm'),?'02',?a.factration))?AS?FRI,
??????SUM(decode(TO_CHAR(a.telfeedate,?'mm'),?'03',?a.factration))?AS?MAR,
??????SUM(decode(TO_CHAR(a.telfeedate,?'mm'),?'04',?a.factration))?AS?APR,
??????SUM(decode(TO_CHAR(a.telfeedate,?'mm'),?'05',?a.factration))?AS?MAY,
??????SUM(decode(TO_CHAR(a.telfeedate,?'mm'),?'06',?a.factration))?AS?JUE,
??????SUM(decode(TO_CHAR(a.telfeedate,?'mm'),?'07',?a.factration))?AS?JUL,
??????SUM(decode(TO_CHAR(a.telfeedate,?'mm'),?'08',?a.factration))?AS?AGU,
??????SUM(decode(TO_CHAR(a.telfeedate,?'mm'),?'09',?a.factration))?AS?SEP,
??????SUM(decode(TO_CHAR(a.telfeedate,?'mm'),?'10',?a.factration))?AS?OCT,
??????SUM(decode(TO_CHAR(a.telfeedate,?'mm'),?'11',?a.factration))?AS?NOV,
??????SUM(decode(TO_CHAR(a.telfeedate,?'mm'),?'12',?a.factration))?AS?DEC
FROM?(SELECT?a.userper,?a.tel,?a.standfee,?b.telfeedate,?b.factration
????????FROM?TELFEESTAND?a,?TELFEE?b
????????WHERE?a.tel?=?b.telfax)?a
GROUP?BY?a.userper,?a.tel,?a.standfee,?TO_CHAR(a.telfeedate,?'yyyy')
說明:四表聯查問題:
SQL:?select?*?from?a?left?inner?join?b?on?a.a=b.b?right?inner?join?c?on?a.a=c.c??inner?join?d?on?a.a=d.d?where?.....
說明:得到表中最小的未使用的ID號
SQL:
SELECT?(CASE?WHEN?EXISTS(SELECT?*?FROM?Handle?b?WHERE?b.HandleID?=?1)?THEN?MIN(HandleID)?+?1?ELSE?1?END)?as?HandleID
?FROM??Handle
?WHERE?NOT?HandleID?IN?(SELECT?a.HandleID?-?1?FROM?Handle?a)
6?? 根據父表 只取子表最新的一條記錄{
SQL> select * from testa ;
?
??????? F1
----------
???????? 1
???????? 2
???????? 3
SQL> select * from testb ;
??????? F1 F2
---------- -------------------
???????? 1 2006-04-10 14:56:41
???????? 1 2006-04-10 14:56:53
???????? 1 2006-04-10 14:57:00
???????? 2 2006-04-10 14:57:08
???????? 3 2006-04-10 14:57:19
???????? 3 2006-04-10 14:57:25?
6 rows selected.
SQL> select testa.f1,v1.f1,v1.f2 from testa ,(select f1,f2,row_number() over (partition by f1 order
by f2 desc) rn from testb) v1 where testa.f1 = v1.f1 and v1.rn = 1 ;
??????? F1???????? F1 F2
---------- ---------- -------------------
???????? 1??????? ??1 2006-04-10 14:57:00
???????? 2????????? 2 2006-04-10 14:57:08
???????? 3????????? 3 2006-04-10 14:57:25
------------------------------------------
7 查詢語句的優化
select t.* from acc$ t
where
not exists (在此不使用not in 是為了性能上的考慮)
(select 'a' from crm$ a
where
a.客戶名=t.用戶名稱
--a.客戶號=t.用戶編號
)
posted @
2005-10-30 09:42 surffish 閱讀(284) |
評論 (0) |
編輯 收藏
作者:[本站編輯] 來源:[CSDN] 瀏覽:[
] |
|
Java Servlet作為首選的服務器端數據處理技術,正在迅速取代CGI腳本。Servlet超越CGI的優勢之一在于,不僅多個請求可以共享公用資源,而且還可以在不同用戶請求之間保留持續數據。本文介紹一種充分發揮該特色的實用技術,即數據庫連接池。
一、實現連接池的意義
動態Web站點往往用數據庫存儲的信息生成Web頁面,每一個頁面請求導致一次數據庫訪問。連接數據庫不僅要開銷一定的通訊和內存資源,還必須完成用戶驗證、安全上下文配置這類任務,因而往往成為最為耗時的操作。當然,實際的連接時間開銷千變萬化,但1到2秒延遲并非不常見。如果某個基于數據庫的Web應用只需建立一次初始連 接,不同頁面請求能夠共享同一連接,就能獲得顯著的性能改善。 Servlet是一個Java類。Servlet引擎(它可能是Web服務軟件的一部分,也可能是一個獨立的附加模塊)在系統啟動或Servlet第一次被請求時將該類裝入Java虛擬機并創建它的一個實例。不同用戶請求由同一Servlet實例的多個獨立線程處理。那些要 求在不同請求之間持續有效的數據既可以用Servlet的實例變量來保存,也可以保存在獨立的輔助對象中。 用JDBC訪問數據庫首先要創建與數據庫之間的連接,獲得一個連接對象(Connection),由連接對象提供執行SQL語句的方法。 本文介紹的數據庫連接池包括一個管理類DBConnectionManager,負責提供與多個連接池對象(DBConnectionPool類)之間的接口。每一個連接池對象管理一組JDBC連接對象,每一個連接對象可以被任意數量的Servlet共享。 類DBConnectionPool提供以下功能:
1) 從連接池獲取(或創建)可用連接。 2) 把連接返回給連接池。 3) 在系統關閉時釋放所有資源,關閉所有連接。
此外, DBConnectionPool類還能夠處理無效連接(原來登記為可用的連接,由于某種原因不再可用,如超時,通訊問題) ,并能夠限制連接池中的連接總數不超過某個預定值。 管理類DBConnectionManager用于管理多個連接池對象,它提供以下功能:
1) 裝載和注冊JDBC驅動程序。 2) 根據在屬性文件中定義的屬性創建連接池對象。 3) 實現連接池名字與其實例之間的映射。 4) 跟蹤客戶程序對連接池的引用,保證在最后一個客戶程序結束時安全地關閉所有連接池。
本文余下部分將詳細說明這兩個類,最后給出一個示例演示Servlet使用連接池的一般過程。
二、具體實現
DBConnectionManager.java程序清單如下:
001 import java.io.*; 002 import java.sql.*; 003 import java.util.*; 004 import java.util.Date; 005 006 /** 007 * 管理類DBConnectionManager支持對一個或多個由屬性文件定義的數據庫連接 008 * 池的訪問.客戶程序可以調用getInstance()方法訪問本類的唯一實例. 009 */ 010 public class DBConnectionManager { 011 static private DBConnectionManager instance; // 唯一實例 012 static private int clients; 013 014 private Vector drivers = new Vector(); 015 private PrintWriter log; 016 private Hashtable pools = new Hashtable(); 017 018 /** 019 * 返回唯一實例.如果是第一次調用此方法,則創建實例 020 * 021 * @return DBConnectionManager 唯一實例 022 */ 023 static synchronized public DBConnectionManager getInstance() { 024 if (instance == null) { 025 instance = new DBConnectionManager(); 026 } 027 clients++; 028 return instance; 029 } 030 031 /** 032 * 建構函數私有以防止其它對象創建本類實例 033 */ 034 private DBConnectionManager() { 035 init(); 036 } 037 038 /** 039 * 將連接對象返回給由名字指定的連接池 040 * 041 * @param name 在屬性文件中定義的連接池名字 042 * @param con 連接對象 043 */ 044 public void freeConnection(String name, Connection con) { 045 DBConnectionPool pool = (DBConnectionPool) pools.get(name); 046 if (pool != null) { 047 pool.freeConnection(con); 048 } 049 } 050 051 /** 052 * 獲得一個可用的(空閑的)連接.如果沒有可用連接,且已有連接數小于最大連接數 053 * 限制,則創建并返回新連接 054 * 055 * @param name 在屬性文件中定義的連接池名字 056 * @return Connection 可用連接或null 057 */ 058 public Connection getConnection(String name) { 059 DBConnectionPool pool = (DBConnectionPool) pools.get(name); 060 if (pool != null) { 061 return pool.getConnection(); 062 } 063 return null; 064 } 065 066 /** 067 * 獲得一個可用連接.若沒有可用連接,且已有連接數小于最大連接數限制, 068 * 則創建并返回新連接.否則,在指定的時間內等待其它線程釋放連接. 069 * 070 * @param name 連接池名字 071 * @param time 以毫秒計的等待時間 072 * @return Connection 可用連接或null 073 */ 074 public Connection getConnection(String name, long time) { 075 DBConnectionPool pool = (DBConnectionPool) pools.get(name); 076 if (pool != null) { 077 return pool.getConnection(time); 078 } 079 return null; 080 } 081 082 /** 083 * 關閉所有連接,撤銷驅動程序的注冊 084 */ 085 public synchronized void release() { 086 // 等待直到最后一個客戶程序調用 087 if (--clients != 0) { 088 return; 089 } 090 091 Enumeration allPools = pools.elements(); 092 while (allPools.hasMoreElements()) { 093 DBConnectionPool pool = (DBConnectionPool) allPools.nextElement(); 094 pool.release(); 095 } 096 Enumeration allDrivers = drivers.elements(); 097 while (allDrivers.hasMoreElements()) { 098 Driver driver = (Driver) allDrivers.nextElement(); 099 try { 100 DriverManager.deregisterDriver(driver); 101 log("撤銷JDBC驅動程序 " + driver.getClass().getName()+"的注冊"); 102 } 103 catch (SQLException e) { 104 log(e, "無法撤銷下列JDBC驅動程序的注冊: " + driver.getClass().getName()); 105 } 106 } 107 } 108 109 /** 110 * 根據指定屬性創建連接池實例. 111 * 112 * @param props 連接池屬性 113 */ 114 private void createPools(Properties props) { 115 Enumeration propNames = props.propertyNames(); 116 while (propNames.hasMoreElements()) { 117 String name = (String) propNames.nextElement(); 118 if (name.endsWith(".url")) { 119 String poolName = name.substring(0, name.lastIndexOf(".")); 120 String url = props.getProperty(poolName + ".url"); 121 if (url == null) { 122 log("沒有為連接池" + poolName + "指定URL"); 123 continue; 124 } 125 String user = props.getProperty(poolName + ".user"); 126 String password = props.getProperty(poolName + ".password"); 127 String maxconn = props.getProperty(poolName + ".maxconn", "0"); 128 int max; 129 try { 130 max = Integer.valueOf(maxconn).intValue(); 131 } 132 catch (NumberFormatException e) { 133 log("錯誤的最大連接數限制: " + maxconn + " .連接池: " + poolName); 134 max = 0; 135 } 136 DBConnectionPool pool = 137 new DBConnectionPool(poolName, url, user, password, max); 138 pools.put(poolName, pool); 139 log("成功創建連接池" + poolName); 140 } 141 } 142 } 143 144 /** 145 * 讀取屬性完成初始化 146 */ 147 private void init() { 148 InputStream is = getClass().getResourceAsStream("/db.properties"); 149 Properties dbProps = new Properties(); 150 try { 151 dbProps.load(is); 152 } 153 catch (Exception e) { 154 System.err.println("不能讀取屬性文件. " + 155 "請確保db.properties在CLASSPATH指定的路徑中"); 156 return; 157 } 158 String logFile = dbProps.getProperty("logfile", "DBConnectionManager.log"); 159 try { 160 log = new PrintWriter(new FileWriter(logFile, true), true); 161 } 162 catch (IOException e) { 163 System.err.println("無法打開日志文件: " + logFile); 164 log = new PrintWriter(System.err); 165 } 166 loadDrivers(dbProps); 167 createPools(dbProps); 168 } 169 170 /** 171 * 裝載和注冊所有JDBC驅動程序 172 * 173 * @param props 屬性 174 */ 175 private void loadDrivers(Properties props) { 176 String driverClasses = props.getProperty("drivers"); 177 StringTokenizer st = new StringTokenizer(driverClasses); 178 while (st.hasMoreElements()) { 179 String driverClassName = st.nextToken().trim(); 180 try { 181 Driver driver = (Driver) 182 Class.forName(driverClassName).newInstance(); 183 DriverManager.registerDriver(driver); 184 drivers.addElement(driver); 185 log("成功注冊JDBC驅動程序" + driverClassName); 186 } 187 catch (Exception e) { 188 log("無法注冊JDBC驅動程序: " + 189 driverClassName + ", 錯誤: " + e); 190 } 191 } 192 } 193 194 /** 195 * 將文本信息寫入日志文件 196 */ 197 private void log(String msg) { 198 log.println(new Date() + ": " + msg); 199 } 200 201 /** 202 * 將文本信息與異常寫入日志文件 203 */ 204 private void log(Throwable e, String msg) { 205 log.println(new Date() + ": " + msg); 206 e.printStackTrace(log); 207 } 208 209 /** 210 * 此內部類定義了一個連接池.它能夠根據要求創建新連接,直到預定的最 211 * 大連接數為止.在返回連接給客戶程序之前,它能夠驗證連接的有效性. 212 */ 213 class DBConnectionPool { 214 private int checkedOut; 215 private Vector freeConnections = new Vector(); 216 private int maxConn; 217 private String name; 218 private String password; 219 private String URL; 220 private String user; 221 222 /** 223 * 創建新的連接池 224 * 225 * @param name 連接池名字 226 * @param URL 數據庫的JDBC URL 227 * @param user 數據庫帳號,或 null 228 * @param password 密碼,或 null 229 * @param maxConn 此連接池允許建立的最大連接數 230 */ 231 public DBConnectionPool(String name, String URL, String user, String password, 232 int maxConn) { 233 this.name = name; 234 this.URL = URL; 235 this.user = user; 236 this.password = password; 237 this.maxConn = maxConn; 238 } 239 240 /** 241 * 將不再使用的連接返回給連接池 242 * 243 * @param con 客戶程序釋放的連接 244 */ 245 public synchronized void freeConnection(Connection con) { 246 // 將指定連接加入到向量末尾 247 freeConnections.addElement(con); 248 checkedOut--; 249 notifyAll(); 250 } 251 252 /** 253 * 從連接池獲得一個可用連接.如沒有空閑的連接且當前連接數小于最大連接 254 * 數限制,則創建新連接.如原來登記為可用的連接不再有效,則從向量刪除之, 255 * 然后遞歸調用自己以嘗試新的可用連接. 256 */ 257 public synchronized Connection getConnection() { 258 Connection con = null; 259 if (freeConnections.size() > 0) { 260 // 獲取向量中第一個可用連接 261 con = (Connection) freeConnections.firstElement(); 262 freeConnections.removeElementAt(0); 263 try { 264 if (con.isClosed()) { 265 log("從連接池" + name+"刪除一個無效連接"); 266 // 遞歸調用自己,嘗試再次獲取可用連接 267 con = getConnection(); 268 } 269 } 270 catch (SQLException e) { 271 log("從連接池" + name+"刪除一個無效連接"); 272 // 遞歸調用自己,嘗試再次獲取可用連接 273 con = getConnection(); 274 } 275 } 276 else if (maxConn == 0 || checkedOut < maxConn) { 277 con = newConnection(); 278 } 279 if (con != null) { 280 checkedOut++; 281 } 282 return con; 283 } 284 285 /** 286 * 從連接池獲取可用連接.可以指定客戶程序能夠等待的最長時間 287 * 參見前一個getConnection()方法. 288 * 289 * @param timeout 以毫秒計的等待時間限制 290 */ 291 public synchronized Connection getConnection(long timeout) { 292 long startTime = new Date().getTime(); 293 Connection con; 294 while ((con = getConnection()) == null) { 295 try { 296 wait(timeout); 297 } 298 catch (InterruptedException e) {} 299 if ((new Date().getTime() - startTime) >= timeout) { 300 // wait()返回的原因是超時 301 return null; 302 } 303 } 304 return con; 305 } 306 307 /** 308 * 關閉所有連接 309 */ 310 public synchronized void release() { 311 Enumeration allConnections = freeConnections.elements(); 312 while (allConnections.hasMoreElements()) { 313 Connection con = (Connection) allConnections.nextElement(); 314 try { 315 con.close(); 316 log("關閉連接池" + name+"中的一個連接"); 317 } 318 catch (SQLException e) { 319 log(e, "無法關閉連接池" + name+"中的連接"); 320 } 321 } 322 freeConnections.removeAllElements(); 323 } 324 325 /** 326 * 創建新的連接 327 */ 328 private Connection newConnection() { 329 Connection con = null; 330 try { 331 if (user == null) { 332 con = DriverManager.getConnection(URL); 333 } 334 else { 335 con = DriverManager.getConnection(URL, user, password); 336 } 337 log("連接池" + name+"創建一個新的連接"); 338 } 339 catch (SQLException e) { 340 log(e, "無法創建下列URL的連接: " + URL); 341 return null; 342 } 343 return con; 344 } 345 } 346 } 三、類DBConnectionPool說明
該類在209至345行實現,它表示指向某個數據庫的連接池。數據庫由JDBC URL標識。一個JDBC URL由三部分組成:協議標識(總是jdbc),驅動程序標識(如 odbc、idb、oracle等),數據庫標識(其格式依賴于驅動程序)。例如,jdbc:odbc:de mo,即是一個指向demo數據庫的JDBC URL,而且訪問該數據庫要使用JDBC-ODBC驅動程序。每個連接池都有一個供客戶程序使用的名字以及可選的用戶帳號、密碼、最大連接數限制。如果Web應用程序所支持的某些數據庫操作可以被所有用戶執行,而其它一些操作應由特別許可的用戶執行,則可以為兩類操作分別定義連接池,兩個連接池使用相同的JDBC URL,但使用不同的帳號和密碼。 類DBConnectionPool的建構函數需要上述所有數據作為其參數。如222至238行所示,這些數據被保存為它的實例變量: 如252至283行、285至305行所示, 客戶程序可以使用DBConnectionPool類提供的兩個方法獲取可用連接。兩者的共同之處在于:如連接池中存在可用連接,則直接返回,否則創建新的連接并返回。如果沒有可用連接且已有連接總數等于最大限制 數,第一個方法將直接返回null,而第二個方法將等待直到有可用連接為止。 所有的可用連接對象均登記在名為freeConnections的向量(Vector)中。如果向量中有多于一個的連接,getConnection()總是選取第一個。同時,由于新的可用連接總是從尾部加入向量,從而使得數據庫連接由于長時間閑置而被關閉的風險減低到最小程度。 第一個getConnection()在返回可用連接給客戶程序之前,調用了isClosed()方法驗證連接仍舊有效。如果該連接被關閉或觸發異常,getConnection()遞歸地調用自己以嘗試獲取另外的可用連接。如果在向量freeConnections中不存在任何可用連 接,getConnection()方法檢查是否已經指定最大連接數限制。如已經指定,則檢查當前連接數是否已經到達極限。此處maxConn為0表示沒有限制。如果沒有指定最大連接數限制或當前連接數小于該值,該方法嘗試創建新的連接。如創建成功,則增加已使用連接的計數并返回,否則返回空值。 如325至345行所示,創建新連接由newConnection()方法實現。創建過程與是否已經指定數據庫帳號、密碼有關。 JDBC的DriverManager類提供多個getConnection()方法,這些方法要用到JDBC URL與其它一些參數,如用戶帳號和密碼等。 DriverManager將使用指定的JDBC URL確定適合于目標數據庫的驅動程序及建立連接。 在285至305行實現的第二個getConnection()方法需要一個以毫秒為單位的時間參數,該參數表示客戶程序能夠等待的最長時間。建立連接的具體操作仍舊由第一個getConnection()方法實現。 該方法執行時先將startTime初始化為當前時間。在while循環中嘗試獲得一個連接。如果失敗,則以給定的時間值為參數調用wait()。wait()的返回可能是由于其它線程調用notify()或notifyAll(),也可能是由于預定時間已到。為找出wait()返回的真正原因,程序用當前時間減開始時間(startTime),如差值大于預定時間則返回空值,否則再次調用getConnection()。 把空閑的連接登記到連接池由240至250行的freeConnection()方法實現,它的參數為返回給連接池的連接對象。該對象被加入到freeConnections向量的末尾,然后減少已使用連接計數。調用notifyAll()是為了通知其它正在等待可用連接的線程。 許多Servlet引擎為實現安全關閉提供多種方法。數據庫連接池需要知道該事件以保證所有連接能夠正常關閉。DBConnectionManager類負協調整個關閉過程,但關閉連接池中所有連接的任務則由DBConnectionPool類負責。在307至323行實現的release()方法供DBConnectionManager調用。該方法遍歷freeConnections向量并關閉所有連接,然后從向量中刪除這些連接。
四、類DBConnectionManager 說明
該類只能創建一個實例,其它對象能夠調用其靜態方法(也稱為類方法)獲得該唯一實例的引用。如031至036行所示,DBConnectionManager類的建構函數是私有的,這是為了避免其它對象創建該類的實例。 DBConnectionManager類的客戶程序可以調用getInstance()方法獲得對該類唯一實例的引用。如018至029行所示,類的唯一實例在getInstance()方法第一次被調用期間創建,此后其引用就一直保存在靜態變量instance中。每次調用getInstance() 都增加一個DBConnectionManager的客戶程序計數。即,該計數代表引用DBConnectionManager唯一實例的客戶程序總數,它將被用于控制連接池的關閉操作。 該類實例的初始化工作由146至168行之間的私有方法init()完成。其中 getResourceAsStream()方法用于定位并打開外部文件。外部文件的定位方法依賴于類裝載器的實現。標準的本地類裝載器查找操作總是開始于類文件所在路徑,也能夠搜索CLASSPATH中聲明的路徑。db.properties是一個屬性文件,它包含定義連接池的鍵-值對。可供定義的公用屬性如下:
drivers 以空格分隔的JDBC驅動程序類列表 logfile 日志文件的絕對路徑
其它的屬性和特定連接池相關,其屬性名字前應加上連接池名字:
<poolname>.url 數據庫的 JDBC URL <poolname>.maxconn 允許建立的最大連接數,0表示沒有限制 <poolname>.user 用于該連接池的數據庫帳號 <poolname>.password 相應的密碼
其中url屬性是必需的,而其它屬性則是可選的。數據庫帳號和密碼必須合法。用于Windows平臺的db.properties文件示例 如下:
drivers=sun.jdbc.odbc.JdbcOdbcDriver jdbc.idbDriver logfile=D:\\user\\src\\java\\DBConnectionManager\\log.txt
idb.url=jdbc:idb:c:\\local\\javawebserver1.1\\db\\db.prp idb.maxconn=2
access.url=jdbc:odbc:demo access.user=demo access.password=demopw
注意在Windows路徑中的反斜杠必須輸入2個,這是由于屬性文件中的反斜杠同時也是一個轉義字符。 init()方法在創建屬性對象并讀取db.properties文件之后,就開始檢查logfile屬性。如果屬性文件中沒有指定日志文件,則默認為當前目錄下的DBConnectionManager.log文件。如日志文件無法使用,則向System.err輸出日志記錄。 裝載和注冊所有在drivers屬性中指定的JDBC驅動程序由170至192行之間的loadDrivers()方法實現。該方法先用StringTokenizer將drivers屬性值分割為對應于驅動程序名稱的字符串,然后依次裝載這些類并創建其實例,最后在 DriverManager中注冊 該實例并把它加入到一個私有的向量drivers。向量drivers將用于關閉服務時從DriverManager取消所有JDBC 驅動程序的注冊。 init()方法的最后一個任務是調用私有方法createPools()創建連接池對象。如109至142行所示,createPools()方法先創建所有屬性名字的枚舉對象(即Enumeration對象,該對象可以想象為一個元素系列,逐次調用其nextElement()方法將順序返 回各元素),然后在其中搜索名字以“.url”結尾的屬性。對于每一個符合條件的屬性,先提取其連接池名字部分,進而讀取所有屬于該連接池的屬性,最后創建連接池對象并把它保存在實例變量pools中。散列表(Hashtable類 )pools實現連接 池名字到連接池對象之間的映射,此處以連接池名字為鍵,連接池對象為值。 為便于客戶程序從指定連接池獲得可用連接或將連接返回給連接池,類DBConnectionManager提供了方法getConnection()和freeConnection()。所有這些方法都要求在參數中指定連接池名字,具體的連接獲取或返回操作則調用對應的連接池對象完成。它們的實現分別在051至064行、066至080行、038至049行。 如082至107行所示,為實現連接池的安全關閉,DBConnectionManager提供了方法release()。在上面我們已經提到,所有DBConnectionManager的客戶程序都應該調用靜態方法getInstance()以獲得該管理器的引用,此調用將增加客戶程序計數。 客戶程序在關閉時調用release()可以遞減該計數。當最后一個客戶程序調用release(),遞減后的引用計數為0,就可以調用各個連接池的release()方法關閉所有連接了。管理類release()方法最后的任務是撤銷所有JDBC驅動程序的注冊。
五、Servlet使用連接池示例
Servlet API所定義的Servlet生命周期類如:
1) 創建并初始化Servlet(init()方法)。 2) 響應客戶程序的服務請求(service()方法)。 3) Servlet終止運行,釋放所有資源(destroy()方法)。
本例演示連接池應用,上述關鍵步驟中的相關操作為:
1) 在init(),用實例變量connMgr 保存調用DBConnectionManager.getInstance()所返回的引用。 2) 在service(),調用getConnection(),執行數據庫操作,用freeConnection()將連接返回給連接池。 3) 在destroy(),調用release()關閉所有連接,釋放所有資源。
示例程序清單如下:
import java.io.*; import java.sql.*; import javax.servlet.*; import javax.servlet.http.*; public class TestServlet extends HttpServlet { private DBConnectionManager connMgr;
public void init(ServletConfig conf) throws ServletException { super.init(conf); connMgr = DBConnectionManager.getInstance(); }
public void service(HttpServletRequest req, HttpServletResponse res) throws IOException {
res.setContentType("text/html"); PrintWriter out = res.getWriter(); Connection con = connMgr.getConnection("idb"); if (con == null) { out.println("不能獲取數據庫連接."); return; } ResultSet rs = null; ResultSetMetaData md = null; Statement stmt = null; try { stmt = con.createStatement(); rs = stmt.executeQuery("SELECT * FROM EMPLOYEE"); md = rs.getMetaData(); out.println("<H1>職工數據</H1>"); while (rs.next()) { out.println("<BR>"); for (int i = 1; i < md.getColumnCount(); i++) { out.print(rs.getString(i) + ", "); } } stmt.close(); rs.close(); } catch (SQLException e) { e.printStackTrace(out); } connMgr.freeConnection("idb", con); }
public void destroy() { connMgr.release(); super.destroy(); } } |
posted @
2005-10-28 09:50 surffish 閱讀(304) |
評論 (0) |
編輯 收藏
exp airport/airport@ems file=airport2.dmp owner=airport log=exp2.log
posted @
2005-10-26 09:56 surffish 閱讀(1192) |
評論 (0) |
編輯 收藏
Java打印程序設計
文楓 深圳全通數碼技術總監
1 前言
在我們的實際工作中,經常需要實現打印功能。但由于歷史原因,Java提供的打印功能一直都比較弱。實際上最初的jdk根本不支持打印,直到jdk1.1才引入了很輕量的打印支持。所以,在以前用Java/Applet/JSP/Servlet設計的程序中,較復雜的打印都是通過調用ActiveX/OCX控件或者VB/VC程序來實現的,非常麻煩。實際上,SUN公司也一直致力于Java打印功能的完善,而Java2平臺則終于有了一個健壯的打印模式的開端,該打印模式與Java2D圖形包充分結合成一體。更令人鼓舞的是,新發布的jdk1.4則提供了一套完整的"Java 打印服務 API" (Java Print Service API),它對已有的打印功能是積極的補充。利用它,我們可以實現大部分實際應用需求,包括打印文字、圖形、文件及打印預覽等等。本文將通過一個具體的程序實例來說明如何設計Java打印程序以實現這些功能,并對不同版本的實現方法進行分析比較。希望大家能從中獲取一些有益的提示。
2 Java中的打印
2.1 Java的打印API
Java的打印API主要存在于java.awt.print包中。而jdk1.4新增的類則主要存在于javax.print包及其相應的子包javax.print.event和javax.print.attribute中。其中javax.print包中主要包含打印服務的相關類,而javax.print.event則包含打印事件的相關定義,javax.print.attribute則包括打印服務的可用屬性列表等。
2.2 如何實現打印
要產生一個打印,至少需要考慮兩條:
- 需要一個打印服務對象。這可通過三種方式實現:在jdk1.4之前的版本,必須要實現java.awt.print.Printable接口或通過Toolkit.getDefaultToolkit().getPrintJob來獲取打印服務對象;在jdk1.4中則還可以通過javax.print.PrintSerivceLookup來查找定位一個打印服務對象。
- 需要開始一個打印工作。這也有幾種實現方法:在jdk1.4之前可以通過java.awt.print.PrintJob(jdk1.1提供的,現在已經很少用了)調用print或printAll方法開始打印工作;也可以通過java.awt.print.PrinterJob的printDialog顯示打印對話框,然后通過print方法開始打印;在jdk1.4中則可以通過javax.print.ServiceUI的printDialog顯示打印對話框,然后調用print方法開始一個打印工作。
2.3 打印機對話框
2.3.1 Printable的打印對話框
開始打印工作之前,可以通過PrinterJob.printDialog來顯示一個打印對話框。它給用戶一個機會以選擇應該打印的頁碼范圍,并可供用戶改變打印設置。它是一個本地對話框。

事實上,當從一個Printable對象進行一個打印工作時,打印對象并不知道需要打印多少頁。它只是不停地調用print方法。只要print方法返回Printable.PAGE_EXISTS值,打印工作就不停地產生打印頁,直到print方法返回Printable.NO_SUCH_PAGE時,打印工作才停止。
由于打印工作只有在打印完成后才進行準確的頁數計算,所以在對話框上的頁碼范圍是尚未初始化的[1,9999]。我們可以通過構建一個java.awt.print.Book對象傳遞給打印對象;也可以通過指定的格式計算需要打印的頁數并傳遞給打印對象,使其準確地知道要打印多少頁。
2.3.2 ServiceUI的打印對話框
與Printable的對話框不同的是,在jdk1.4提供ServiceUI的打印機對話框的缺省行為已經用新的 API 更改了:缺省情況下對話框不顯示。我們必須使用ServiceUI類調用printDialog方法創建如下所示的打印對話框。
3 Java打印程序設計實例
3.1 打印文本
3.1.1 應用場景
假設我們需要打印一個窗體的某個文本編輯域(可能只有幾行,也可能包含多頁)的內容,并且每頁最多打印54行,如何實現呢?
3.1.2 解決方法
基本思路如下:首先我們需要實現Printable接口,然后按照每頁最多54行的格式計算共需要打印多少頁,當打印文本的按鈕被點擊時,執行相應的打印動作。打印文本的具體操作可通過Graphics2D的drawString方法來實現。
1、實現Printable接口
/*Graphic指明打印的圖形環境;PageFormat指明打印頁格式(頁面大小以點為計量單位,
1點為1英才的1/72,1英寸為25.4毫米。A4紙大致為595×842點);page指明頁號*/
public int print(Graphics g, PageFormat pf, int page) throws PrinterException
{
Graphics2D g2 = (Graphics2D)g;
g2.setPaint(Color.black); //設置打印顏色為黑色
if (page >= PAGES) //當打印頁號大于需要打印的總頁數時,打印工作結束
return Printable.NO_SUCH_PAGE;
g2.translate(pf.getImageableX(), pf.getImageableY());//轉換坐標,確定打印邊界
drawCurrentPageText(g2, pf, page); //打印當前頁文本
return Printable.PAGE_EXISTS; //存在打印頁時,繼續打印工作
}
/*打印指定頁號的具體文本內容*/
private void drawCurrentPageText(Graphics2D g2, PageFormat pf, int page)
{
String s = getDrawText(printStr)[page];//獲取當前頁的待打印文本內容
//獲取默認字體及相應的尺寸
FontRenderContext context = g2.getFontRenderContext();
Font f = area.getFont();
String drawText;
float ascent = 16; //給定字符點陣
int k, i = f.getSize(), lines = 0;
while(s.length() > 0 && lines < 54) //每頁限定在54行以內
{
k = s.indexOf('\n'); //獲取每一個回車符的位置
if (k != -1) //存在回車符
{
lines += 1; //計算行數
drawText = s.substring(0, k); //獲取每一行文本
g2.drawString(drawText, 0, ascent); //具體打印每一行文本,同時走紙移位
if (s.substring(k + 1).length() > 0)
{
s = s.substring(k + 1); //截取尚未打印的文本
ascent += i;
}
}
else //不存在回車符
{
lines += 1; //計算行數
drawText = s; //獲取每一行文本
g2.drawString(drawText, 0, ascent); //具體打印每一行文本,同時走紙移位
s = ""; //文本已結束
}
}
}
/*將打印目標文本按頁存放為字符串數組*/
public String[] getDrawText(String s)
{
String[] drawText = new String[PAGES];//根據頁數初始化數組
for (int i = 0; i < PAGES; i++)
drawText[i] = ""; //數組元素初始化為空字符串
int k, suffix = 0, lines = 0;
while(s.length() > 0)
{
if(lines < 54) //不夠一頁時
{
k = s.indexOf('\n');
if (k != -1) //存在回車符
{
lines += 1; //行數累加
//計算該頁的具體文本內容,存放到相應下標的數組元素
drawText[suffix] = drawText[suffix] + s.substring(0, k + 1);
if (s.substring(k + 1).length() > 0)
s = s.substring(k + 1);
}
else
{
lines += 1; //行數累加
//將文本內容存放到相應的數組元素
drawText[suffix] = drawText[suffix] + s;
s = "";
}
}
else //已滿一頁時
{
lines = 0; //行數統計清零
suffix++; //數組下標加1
}
}
return drawText;
}
2、計算需要打印的總頁數
public int getPagesCount(String curStr)
{
int page = 0;
int position, count = 0;
String str = curStr;
while(str.length() > 0) //文本尚未計算完畢
{
position = str.indexOf('\n'); //計算回車符的位置
count += 1; //統計行數
if (position != -1)
str = str.substring(position + 1); //截取尚未計算的文本
else
str = ""; //文本已計算完畢
}
if (count > 0)
page = count / 54 + 1; //以總行數除以54獲取總頁數
return page; //返回需打印的總頁數
}
3.1、以jdk1.4以前的版本實現打印動作按鈕監聽,并完成具體的打印操作
private void printTextAction()
{
printStr = area.getText().trim(); //獲取需要打印的目標文本
if (printStr != null && printStr.length() > 0) //當打印內容不為空時
{
PAGES = getPagesCount(printStr); //獲取打印總頁數
PrinterJob myPrtJob = PrinterJob.getPrinterJob(); //獲取默認打印作業
PageFormat pageFormat = myPrtJob.defaultPage(); //獲取默認打印頁面格式
myPrtJob.setPrintable(this, pageFormat); //設置打印工作
if (myPrtJob.printDialog()) //顯示打印對話框
{
try
{
myPrtJob.print(); //進行每一頁的具體打印操作
}
catch(PrinterException pe)
{
pe.printStackTrace();
}
}
}
else
{
//如果打印內容為空時,提示用戶打印將取消
JOptionPane.showConfirmDialog
(null, "Sorry, Printer Job is Empty, Print Cancelled!", "Empty",
JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE);
}
}
3.2、以jdk1.4新版本提供的API實現打印動作按鈕監聽,并完成具體的打印操作
private void printText2Action()
{
printFlag = 0; //打印標志清零
printStr = area.getText().trim();//獲取需要打印的目標文本
if (printStr != null && printStr.length() > 0) //當打印內容不為空時
{
PAGES = getPagesCount(printStr); //獲取打印總頁數
//指定打印輸出格式
DocFlavor flavor = DocFlavor.SERVICE_FORMATTED.PRINTABLE;
//定位默認的打印服務
PrintService printService = PrintServiceLookup.lookupDefaultPrintService();
//創建打印作業
DocPrintJob job = printService.createPrintJob();
//設置打印屬性
PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();
DocAttributeSet das = new HashDocAttributeSet();
//指定打印內容
Doc doc = new SimpleDoc(this, flavor, das);
//不顯示打印對話框,直接進行打印工作
try
{
job.print(doc, pras); //進行每一頁的具體打印操作
}
catch(PrintException pe)
{
pe.printStackTrace();
}
}
else
{
//如果打印內容為空時,提示用戶打印將取消
JOptionPane.showConfirmDialog(null, "Sorry, Printer Job is Empty, Print Cancelled!", "Empty", JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE);
}
}
3.2 打印預覽
3.2.1應用場景
大多少商業應用都需要提供打印預覽機制,它可以讓我們在屏幕上看到頁面,這樣就不會因為不喜歡的打印結果而浪費紙張。假設我們在打印上一節所說的文本之前,需要先進行打印預覽。那么該怎么實現呢?
界面實現圖示如下:(Next預覽下一頁,Preview預覽前一頁,Close則關閉預覽)
3.2.2解決方法
基本思路:雖然Java2平臺的打印API并不提供標準的打印預覽對話框,但是自己來進行設計也并不復雜。正常情況下,print方法將頁面環境繪制到一個打印機圖形環境上,從而實現打印。而事實上,print方法并不能真正產生打印頁面,它只是將待打印內容繪制到圖形環境上。所以,我們可以忽略掉屏幕圖形環境,經過適當的縮放比例,使整個打印頁容納在一個屏幕矩形里,從而實現精確的打印預覽。
在打印預覽的設計實現中,主要需要解決兩個問題。第一,如何將打印內容按合適的比例繪制到屏幕;第二,如何實現前后翻頁。下面我給出這兩個問題的具體實現方法,完整的實現請參看附件中的PrintPreviewDialog.java文件。
/*將待打印內容按比例繪制到屏幕*/
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
PageFormat pf = PrinterJob.getPrinterJob().defaultPage(); //獲取頁面格式
double xoff; //在屏幕上頁面初始位置的水平偏移
double yoff; //在屏幕上頁面初始位置的垂直偏移
double scale; //在屏幕上適合頁面的比例
double px = pf.getWidth(); //頁面寬度
double py = pf.getHeight(); //頁面高度
double sx = getWidth() - 1;
double sy = getHeight() - 1;
if (px / py < sx / sy)
{
scale = sy / py; //計算比例
xoff = 0.5 * (sx - scale * px); //水平偏移量
yoff = 0;
}
else
{
scale = sx / px; //計算比例
xoff = 0;
yoff = 0.5 * (sy - scale * py); //垂直偏移量
}
g2.translate((float)xoff, (float)yoff); //轉換坐標
g2.scale((float)scale, (float)scale);
Rectangle2D page = new Rectangle2D.Double(0, 0, px, py); //繪制頁面矩形
g2.setPaint(Color.white); //設置頁面背景為白色
g2.fill(page);
g2.setPaint(Color.black);//設置頁面文字為黑色
g2.draw(page);
try
{
preview.print(g2, pf, currentPage); //顯示指定的預覽頁面
}
catch(PrinterException pe)
{
g2.draw(new Line2D.Double(0, 0, px, py));
g2.draw(new Line2D.Double(0, px, 0, py));
}
}
/*預覽指定的頁面*/
public void viewPage(int pos)
{
int newPage = currentPage + pos;
//指定頁面在實際的范圍內
if (0 <= newPage && newPage < preview.getPagesCount(printStr))
{
currentPage = newPage; //將指定頁面賦值為當前頁
repaint();
}
}
這樣,在按下"Next"按鈕時,只需要調用canvas.viewPage(1);而在按下"Preview"按鈕時,只需要調用canvas.viewPage(-1)即可實現預覽的前后翻頁。
3.3 打印圖形
3.3.1應用場景
在實際應用中,我們還需要打印圖形。譬如,我們有時需要將一個Java Applet的完整界面或一個應用程序窗體及其所包含的全部組件都打印出來,又應該如何實現呢?
3.3.2解決方法
基本思路如下:在Java的Component類及其派生類中都提供了print和printAll方法,只要設置好屬性就可以直接調用這兩個方法,從而實現對組件及圖形的打印。
/*打印指定的窗體及其包含的組件*/
private void printFrameAction()
{
Toolkit kit = Toolkit.getDefaultToolkit(); //獲取工具箱
Properties props = new Properties();
props.put("awt.print.printer", "durango");//設置打印屬性
props.put("awt.print.numCopies", "2");
if(kit != null)
{
//獲取工具箱自帶的打印對象
PrintJob printJob = kit.getPrintJob(this, "Print Frame", props);
if(printJob != null)
{
Graphics pg = printJob.getGraphics();//獲取打印對象的圖形環境
if(pg != null)
{
try
{
this.printAll(pg);//打印該窗體及其所有的組件
}
finally
{
pg.dispose();//注銷圖形環境
}
}
printJob.end();//結束打印作業
}
}
}
3.4 打印文件
3.4.1應用場景
在很多實際應用情況下,我們可能都需要打印用戶指定的某一個文件。該文件可能是圖形文件,如GIF、JPEG等等;也可能是文本文件,如TXT、Java文件等等;還可能是復雜的PDF、DOC文件等等。那么對于這樣的打印需求,我們又應該如何實現呢?
3.4.2解決方法
基本思路:在jdk1.4以前的版本,要實現這樣的打印功能將非常麻煩和復雜,甚至是難以想象的。但幸運的是,jdk1.4的打印服務API提供了一整套的打印文件流的類和方法。利用它們,我們可以非常方便快捷地實現各式各樣不同類型文件的打印功能。下面給出一個通用的處理方法。
/*打印指定的文件*/
private void printFileAction()
{
//構造一個文件選擇器,默認為當前目錄
JFileChooser fileChooser = new JFileChooser(SystemProperties.USER_DIR);
int state = fileChooser.showOpenDialog(this);//彈出文件選擇對話框
if (state == fileChooser.APPROVE_OPTION)//如果用戶選定了文件
{
File file = fileChooser.getSelectedFile();//獲取選擇的文件
//構建打印請求屬性集
PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();
//設置打印格式,因為未確定文件類型,這里選擇AUTOSENSE
DocFlavor flavor = DocFlavor.INPUT_STREAM.AUTOSENSE;
//查找所有的可用打印服務
PrintService printService[] = PrintServiceLookup.lookupPrintServices(flavor, pras);
//定位默認的打印服務
PrintService defaultService = PrintServiceLookup.lookupDefaultPrintService();
//顯示打印對話框
PrintService service = ServiceUI.printDialog(null, 200, 200, printService
, defaultService, flavor, pras);
if (service != null)
{
try
{
DocPrintJob job = service.createPrintJob();//創建打印作業
FileInputStream fis = new FileInputStream(file);//構造待打印的文件流
DocAttributeSet das = new HashDocAttributeSet();
Doc doc = new SimpleDoc(fis, flavor, das);//建立打印文件格式
job.print(doc, pras);//進行文件的打印
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
}
在上面的示例中,因尚未確定文件的類型,所以將指定文件的打印格式定義為DocFlavor.INPUT_STREAM.AUTOSENSE。事實上,如果在進行打印之前,就已確定地知道文件的格式,如為GIF,就應定義為DocFlavor.INPUT_STREAM.GIF ;如為PDF,就應該定義為DocFlavor.INPUT_STREAM.PDF;如為純ASCII文件,就可以定義為 DocFlavor.INPUT_STREAM.TEXT_HTML_US_ASCII。等等。jdk1.4的javax.print.DocFlavor提供了極為豐富的文件流類型,你可以根據具體的應用需求進行合適的選擇。具體的API參考文檔可見本文的參考資料3。
4 結束語
以上是本人在兩年多J2EE應用開發中,總結的關于用Java進行打印程序設計的一些經驗,希望能給大家一些啟示和裨益。盡管目前用Java來實現打印功能與用Microsoft的MFC API相比確實有更多的麻煩。但jdk1.4的推出,對Java以前較弱的打印功能是一個極好的補充。相信大家如果能夠很好地理解前文所述的打印程序設計實例,并加以應用和拓展,應該可以解決目前大部分應用的實際編程問題。而隨著Java的進一步發展和完善,必將更好地充實其基礎類庫及打印API,相信用Java實現高級打印功能也將越來越不成為我們這些Java癡迷者頭痛的問題。
5 參考資料
《Java2核心技術 卷Ⅱ:高級特性》 機械工業出版社
Java打印服務參考文檔:http://java.sun.com/j2se/1.4/docs/guide/jps/
jdk1.4 API參考文檔:http://java.sun.com/j2se/1.4/docs/api/
6 例程源碼
PrintSrc.zip包含下列java源代碼和Class代碼:
PrintTest.java包含了本文所描述的所有打印功能的實現源代碼。相應的打印文本功能通過Print Text和PrintText2(jdk1.4實現)按鈕調用;打印文件通過Print File按鈕調用;打印圖形通過Print Frame按鈕調用;而Print Preview則進行打印預覽。
PrintPreviewDialog.java包含打印預覽源代碼,你可以通過PrintTest窗體中的Print Preview按鈕來調用。
關于作者
文楓,深圳全通數碼技術總監。目前專注于J2EE應用與開發。休閑時間喜歡旅游、踢球。你可以通過 wenfb@sina.com 與我聯系
posted @
2005-10-25 14:18 surffish 閱讀(448) |
評論 (0) |
編輯 收藏
幾個刪除重復記錄的SQL語句 |
在大的數據庫應用中,經常因為各種原因遇到重復的記錄,造成數據的冗余和維護上的不便。
1.用rowid方法
2.用group by方法
3.用distinct方法
1。用rowid方法
據據oracle帶的rowid屬性,進行判斷,是否存在重復,語句如下: 查數據: select * from table1 a where rowid !=(select max(rowid) from table1 b where a.name1=b.name1 and a.name2=b.name2......) 刪數據: delete from table1 a where rowid !=(select max(rowid) from table1 b where a.name1=b.name1 and a.name2=b.name2......)
2.group by方法
查數據: select count(num), max(name) from student --列出重復的記錄數,并列出他的name屬性 group by num having count(num) >1 --按num分組后找出表中num列重復,即出現次數大于一次 刪數據: delete from student group by num having count(num) >1 這樣的話就把所有重復的都刪除了。
3.用distinct方法 -對于小的表比較有用
create table table_new as select distinct * from table1 minux truncate table table1; insert into table1 select * from table_new;
|
select sum(bag_weight),sum(bag_total) from tdespatch
posted @
2005-10-25 13:58 surffish 閱讀(716) |
評論 (0) |
編輯 收藏