1.如果你在堅持做某件事,其實你很脆弱,你在強迫自己做一件事,因為你心里有一個度,此時這個度大于這件需要堅持的事,如果有某件事物干擾,超越了這個度呢?就出現所謂的堅持不下去了。
2.如果你習慣于做某件事,這時候潛意識里無理由就要做這件事,自動,條件反射,基本上不會不爽,可是,如果有意識覺得某樣東西超越這個習慣,這個習慣就被打破了,所以還是度的問題。
3.如果你已經形成某種信仰,真正的堅信不移,你就可怕了,你的度是無窮大,給定一個任意大的理由,卻總存在一個更大的理由,去執行自己的信仰,毫不動搖。
所以,信仰>習慣>堅持。
……
傳說,看客們有70%會相信以上論調,5%會因此改變自己,只有若干人會建立自己的信仰。
?? A DO:
?? 1.好好工作
?? 2.以結婚為目的找一個女朋友,解決個人問題。
?? 3.多運動,成為一個“肌肉男”。
?? 濤哥:
?? 1.租一個大大的房子,大家來廣州好好落腳。
?? 2.好好掙錢,為成家做準備。
?? 3.還債。
?? 濤嫂:
?? 1.掙錢。
?? 2.掙錢。
?? 3.還是掙錢。
?? 韓老大:
?? 1.吃遍公司附近的餐館。
?? 2.還Banner的¥735.00元。
???3.半年內保持單身。
?? 老毛:
?? 1.找一女朋友解決單身問題,首當其沖。
?? 2.繼續彩票事業,多買多賺,以500W和LAMBORGHINI為目標。
?? 3.任勞任怨,踏實工作。
澳門仔自歸大陸后,身形愈發消瘦,思循古法于入冬時加以補養。【注意身形愈發消瘦不是去了澳門才造成的,沒看到我天天堅持跑步啊,鍛煉結果Keep Fit,知不知啊】小三川之味,已去數次,漸厭之,眾人遂奔大巴適。為犒此仔拔毛之舉,夜敲此篇“老毛”,為RICA人物列傳開刀之作【很榮幸啊,看來錢沒有白花啊,雖然錢也是從萬惡的
Casino
拿來的,但誰知下次會不會再還回去呢】。
??? 吾與此猥物同床異枕二載有余,甚悉之。【這話說的,我是和你對腳,不是同床。反正我是沒有gay傾向,至于你有沒有我就不知啦】老毛悄然行至身后,吾不待轉首即感猥瑣之氣鋪天蓋地,料定必是此物,老毛訝之。【對我如此之關切,更加證明你的取向有問題,以后注意和我保持距離】
??? 此君好戴一寵物圈于項,名曰健身,實未見效,【帶鈦白項圈好處有二:1.防止腰肌勞損,知不知腰對男人的重要性啊。2.美觀,引領時尚之風,君不見劉德華也開始學樣了嘛。】反有阻大腦供養之嫌,何以為證?近日老毛言語迥異于常。濤哥、阿杜皆不堪其擾,存滅其肉體而后快之意。老毛以寡敵眾,慷慨應對,屢除其自生大規模殺傷化學武器保險,置于寢室上風處,隨即頹勢立轉。【我有這么殘忍嘛,要怪就怪安踏不透氣,無心之作。】余竊以為此乃老毛漸歸本性之兆。
??? 老毛長于言辯,眼光敏銳,領風氣之先(數度拉吾下水),思維極為跳躍,擅傷女仔之心(略去數萬言。。。),而討大媽歡心。【反了反了,從來都是我被別人挫傷。】猛男CALL之“猥瑣毛”,頗為傳神。【保留申辯的權利】此仔將混跡于珠海某著名CM公司,余甚憂之。澳門場暗備此仔諸多劣跡,若這廝任職CM毛總,無間道恐將由其主演【雖然我玩了5次,大部分是有掙,誰知別人是不是小餌釣大魚】。。。
PS:覓兔肉于巴適,半餉而不可得,痛憾之~
【感謝韓老大為我研究生三年做了個簡要的總結,雖然大部分不是好話,弄得我都不好到處貼。總是為我整理了下思路,開始寫自序了!】
二十歲之前相信的很多東西,后來一件一件變成不相信。
曾經相信過愛國,后來知道“國”的定義有問題,通常那循循善誘要你愛國的人所定義的“國”,不一定可愛,不一定值得愛,而且更可能值得推翻。
曾經相信過歷史,后來知道,原來歷史的一半是編造。前朝史永遠是后朝人在寫,后朝人永遠在否定前朝,他的后朝又來否定他,但是負負不一定得正,只是累積漸進的扭曲變形移位,使真相永遠掩蓋,無法復原。說“不容青史盡成灰”,表達的正是,不錯,青史往往是要成灰的。指鹿為馬,也往往是可以得逞和勝利的。
曾經相信過文明的力量,后來知道,原來人的愚昧和野蠻不因文明的進展而消失,只是愚昧野蠻有很多不同的面貌:純樸的農民工人、深沉的知識分子、自信的政治領袖、替天行道的王師,都可能有不同形式的巨大愚昧和巨大野蠻,而且野蠻和文明之間,竟然只有極其細微、隨時可以被抹掉的一線之隔。
曾經相信過正義,后來知道,原來同時完全可以存在兩種正義,而且彼此抵觸,冰火不容。選擇其中之一,正義同時就意味著不正義。而且,你絕對看不出,某些人在某一個特定的時機熱烈主張某一個特定的正義,其中隱藏著深不可測的不正義。
曾經相信過理想主義者,后來知道,理想主義者往往經不起權力的測試:一掌有權力,他或者變成當初自己誓死反對的“邪惡”,或者,他在現實的場域里不堪一擊,一下就被弄權者拉下馬來,完全沒有機會去實現他的理想。理想主義者要有品格,才能不被權力腐化;理想主義者要有能力,才能將理想轉化為實踐。可是理想主義者兼具品格及能力者,幾希。
曾經相信過愛情,后來知道,原來愛情必須轉化為親情才可能持久,但是轉化為親情的愛情,猶如化入杯水中的冰塊---它還是冰塊嗎?
曾經相信過海枯石爛作為永恒不滅的表征,后來知道,原來海其實很容易枯,石,原來很容易爛。雨水,很可能不再來,滄海,不會再成桑田。原來,自己腳下所踩的地球,很容易被毀滅。海枯石爛的永恒,原來不存在。
二十歲之前相信的很多東西,有些其實到今天也還相信。
譬如國也許不可愛,但是土地和人可以愛。譬如史也許不能信,但是對于真相的追求可以無止盡。譬如文明也許脆弱不堪,但是除文明外我們其實別無依靠。譬如正義也許極為可疑,但是在乎正義比不在乎要安全。譬如理想主義者也許成就不了大事大業,但是沒有他們社會一定不一樣。譬如愛情總是幻滅的多,但是螢火蟲在夜里發光從來就不是為了保持光。譬如海枯石爛的永恒也許不存在,但是如果一粒沙里有一個無窮的宇宙,一剎那里想必也有一個不變不移的時間。
那么,有沒有什么,是我二十歲前不相信的,現在卻信了呢?
有的,不過都是些最平凡的老生常談。曾經不相信“性格決定命運”,現在相信了。曾經不相信“色即是空”,現在相信了。曾經不相信“船到橋頭自然直”,現在有點信了。曾經不相信無法實證的事情,現在也還沒準備相信,但是,有些無關實證的感覺,我明白了,譬如李叔同圓寂前最后的手書:“君子之交,其淡如水,執象而求,咫尺千里。問余何適,廓爾忘言,華枝春滿,天心月圓。”
相信與不相信之間,彷佛還有令人沉吟的深度。
8.異常,如果對try{}catch(exception o){}的所有catch情況都考慮到了的話,調用者就不需要添加catch或throw exception啦
9.文件流: 分為字節流( 帶Input)和字符流(帶reader)
????????????? 例如FileInputStream??? 例如FileReader
?????????? 字符流不依賴於編碼,全部采用unicode編碼
?????????? 如果需要支持國際化的話就需要采用直接流啦 。
?????????? 示例:? FileInputStream is=new FileInputStream(f);
?????????????????? InputStreamReader r=new InputSteamReader(is,"utf-8");
? 另外可以使用System.getProperty("file.endcoding")來獲得系統的默認編碼
10,數組和矢量Vector比較? 遍歷Vector比較慢,因為Vector是線程安全的,獲取值時采用了同步化,解決方法在遍歷是toArray()
??? 例外ArrayList具有vector的動態增加長度的特點,但ArrayList是非同步的矢量。
11.在循環體內鏈接字符串,使用StringBuffer效率更高;其他情況下使用+。
為什么會業務邏輯層使用if else,其實使用者的目的也是為了重用,但是這是面向過程編程的重用,程序員只看到代碼重用,因為他看到if else幾種情況下大部分代碼都是重復的,只有個別不同,因此使用if else可以避免重復代碼,并且認為這是模板Template模式。
他范的錯誤是:程序員只從代碼運行順序這個方向來看待它的代碼,這種思維類似水管或串行電路,水沿著水管流動(代碼運行次序),當遇到幾個分管(子管),就分到這幾個分管子在流動,這里就相當于碰到代碼的if else處了。
而使用OO,則首先打破這個代碼由上向下順序等同于運行時的先后循序這個規律,代碼結構不由執行循序決定,由什么決定呢?由OO設計;設計模式會取代這些if else,但是最后總是由一個Service等總類按照運行順序組裝這些OO模塊,只有一處,這處可包含事務,一般就是Service,EJB中是Session bean。
一旦需求變化,我們更多的可能是Service中各個OO模塊,甚至是只改動Service中的OO模塊執行順序就能符合需求。
這里我們也看到OO分離的思路,將以前過程語言的一個Main函數徹底分解,將運行順序與代碼其他邏輯分離開來,而不是象面向過程那樣混亂在一起。所以有人感慨,OO也是要順序的,這是肯定的,關鍵是運行順序要單獨分離出來。
是否有if else可以看出你有沒有將運行順序分離到家。
設計模式的切入口
經常有人反映,設計模式是不錯,但是我很難用到,其實如果你使用if else來寫代碼時(除顯示控制以外),就是在寫業務邏輯,只不過使用簡單的判斷語句來作為現實情況的替代者。
還是以大家熟悉的論壇帖子為例子,如ForumMessage是一個模型,但是實際中帖子分兩種性質:主題貼(第一個根貼)和回帖(回以前帖子的帖子),這里有一個樸素的解決方案:
建立一個ForumMessage,然后在ForumMessage加入isTopic這樣判斷語句,注意,你這里一個簡單屬性的判斷引入,可能導致你的程序其他地方到處存在if else 的判斷。
如果我們改用另外一種分析實現思路,以對象化概念看待,實際中有主題貼和回帖,就是兩種對象,但是這兩種對象大部分是一致的,因此,我將ForumMessage設為表達主題貼;然后創建一個繼承ForumMessage的子類ForumMessageReply作為回帖,這樣,我在程序地方,如Service中,我已經確定這個Model是回帖了,我就直接下溯為ForumMessageReply即可,這個有點類似向Collection放入對象和取出時的強制類型轉換。通過這個手段我消滅了以后程序中if else的判斷語句出現可能。
從這里體現了,如果分析方向錯誤,也會導致誤用模式。
討論設計模式舉例,不能沒有業務上下文場景的案例,否則無法決定是否該用模式,下面舉兩個對比的例子:
第一. 這個帖子中舉例的第一個代碼案例是沒有上下文的,文中只說明有一段代碼:
main() {
if(case A){ //do with strategy A }else(case B){ //do with strategy B }else(case C){ //do with strategy C } } | ? |
這段代碼只是純粹的代碼,沒有業務功能,所以,在這種情況下,我們就很難確定使用什么模式,就是一定用策略模式等,也逃不過還是使用if else的命運,設計模式不是魔法,不能將一段毫無意義的代碼變得簡單了,只能將其體現的業務功能更加容易可拓展了。
第二.在這個帖子中,作者舉了一個PacketParser業務案例,這段代碼是體現業務功能的,是一個數據包的分析,作者也比較了各種模式使用的不同,所以我們還是使用動態代理模式或Command模式來消滅那些可能存在的if else
由以上兩個案例表明:業務邏輯是我們使用設計模式的切入點,而在分解業務邏輯時,我們習慣則可能使用if else來實現,當你有這種企圖或者已經實現代碼了,那么就應該考慮是否需要重構Refactoring了。
if else替代者
那么實戰中,哪些設計模式可以替代if else呢?其實GoF設計模式都可以用來替代if else,我們分別描述如下:
? public class Order{ private int status; //說明: //status=1 表示訂貨但為查看 ; //status=2 表示已經查看未處理; //status=3 表示已經處理未付款 //status=4 表示已經付款未發貨 //status=5 表示已經發貨 } |
OO設計的總結
還有一種偽模式,雖然使用了狀態等模式,但是在模式內部實質還是使用if else或switch進行狀態切換或重要條件判斷,那么無疑說明還需要進一步努力。更重要的是,不能以模式自居,而且出書示人。
真正掌握面向對象這些思想是一件困難的事情,目前有各種屬于揪著自己頭發向上拔的解說,都是誤人子弟的,所以我覺得初學者讀Thinking in Java(Java編程思想)是沒有用,它試圖從語言層次來講OO編程思想,非常失敗,作為語言參考書可以,但是作為Java體現的OO思想的學習資料,就錯了。
OO編程思想是一種方法論,方法論如果沒有應用比較,是無法體會這個方法論的特點的,禪是古代一個方法論,悟禪是靠挑水砍柴這些應用才能體會。
那么OO思想靠什么應用能夠體會到了?是GoF設計模式,GoF設計模式是等于軟件人員的挑水砍柴等基本活,所以,如果一個程序員連基本活都不會,他何以自居OO程序員?從事OO專業設計編程這個工作,如果不掌握設計模式基本功,就象一個做和尚的人不愿意挑水砍柴,他何以立足這個行業?早就被師傅趕下山。
最后總結:將if else用在小地方還可以,如簡單的數值判斷;但是如果按照你的傳統習慣思維,在實現業務功能時也使用if else,那么說明你的思維可能需要重塑,你的編程經驗越豐富,傳統過程思維模式就容易根深蒂固,想靠自己改變很困難;建議接受專業頭腦風暴培訓。
用一句話總結:如果你做了不少系統,很久沒有使用if else了,那么說明你可能真正進入OO設計的境地了。(這是本人自己發明的實戰性的衡量考核標準)。
1. 常用快捷鍵
(1)Ctrl+Space
說明:內容助理。提供對方法,變量,參數,javadoc等得提示,應運在多種場合,總之需要提示的時候可先按此快捷鍵。
注:避免輸入法的切換設置與此設置沖突
(2)Ctrl+Shift+Space
說明:變量提示
(3)Ctrl+/
說明:添加/消除//注釋,在eclipse2.0中,消除注釋為Ctrl+\
(4)Ctrl+Shift+/
說明:添加/* */注釋
(5)Ctrl+Shift+\
說明:消除/* */注釋
(6)Ctrl+Shift+F
說明:自動格式化代碼
(7)Ctrl+1
說明:批量修改源代碼中的變量名,此外還可用在catch塊上.
(8)Ctril+F6
說明:界面切換
(9)Ctril+Shift+M
說明:查找所需要得包
(10)Ctril+Shift+O
說明:自動引入所需要得包
(11)Ctrl+Alt+S
說明:源代碼得快捷菜單。其中的Generate getters and setters 和 Surround with try/catch
block比較常用.建議把它們添加為快捷鍵.快捷鍵設置在windows->preferences->Workbench->Keys
2. 快捷鍵列表
編輯
作用域 功能 快捷鍵
全局 查找并替換 Ctrl+F
文本編輯器 查找上一個 Ctrl+Shift+K
文本編輯器 查找下一個 Ctrl+K
全局 撤銷 Ctrl+Z
全局 復制 Ctrl+C
全局 恢復上一個選擇 Alt+Shift+↓
全局 剪切 Ctrl+X
全局 快速修正 Ctrl1+1
全局 內容輔助 Alt+/
全局 全部選中 Ctrl+A
全局 刪除 Delete
全局 上下文信息 Alt+?Alt+Shift+?Ctrl+Shift+Space
Java編輯器 顯示工具提示描述 F2
Java編輯器 選擇封裝元素 Alt+Shift+↑
Java編輯器 選擇上一個元素 Alt+Shift+←
Java編輯器 選擇下一個元素 Alt+Shift+→
文本編輯器 增量查找 Ctrl+J
文本編輯器 增量逆向查找 Ctrl+Shift+J
全局 粘貼 Ctrl+V
全局 重做 Ctrl+Y
查看
作用域 功能 快捷鍵
全局 放大 Ctrl+=
全局 縮小 Ctrl+-
窗口
作用域 功能 快捷鍵
全局 激活編輯器 F12
全局 切換編輯器 Ctrl+Shift+W
全局 上一個編輯器 Ctrl+Shift+F6
全局 上一個視圖 Ctrl+Shift+F7
全局 上一個透視圖 Ctrl+Shift+F8
全局 下一個編輯器 Ctrl+F6
全局 下一個視圖 Ctrl+F7
全局 下一個透視圖 Ctrl+F8
文本編輯器 顯示標尺上下文菜單 Ctrl+W
全局 顯示視圖菜單 Ctrl+F10
全局 顯示系統菜單 Alt+-
導航
作用域 功能 快捷鍵
Java編輯器 打開結構 Ctrl+F3
全局 打開類型 Ctrl+Shift+T
全局 打開類型層次結構 F4
全局 打開聲明 F3
全局 打開外部javadoc Shift+F2
全局 打開資源 Ctrl+Shift+R
全局 后退歷史記錄 Alt+←
全局 前進歷史記錄 Alt+→
全局 上一個 Ctrl+,
全局 下一個 Ctrl+.
Java編輯器 顯示大綱 Ctrl+O
全局 在層次結構中打開類型 Ctrl+Shift+H
全局 轉至匹配的括號 Ctrl+Shift+P
全局 轉至上一個編輯位置 Ctrl+Q
Java編輯器 轉至上一個成員 Ctrl+Shift+↑
Java編輯器 轉至下一個成員 Ctrl+Shift+↓
文本編輯器 轉至行 Ctrl+L
搜索
作用域 功能 快捷鍵
全局 出現在文件中 Ctrl+Shift+U
全局 打開搜索對話框 Ctrl+H
全局 工作區中的聲明 Ctrl+G
全局 工作區中的引用 Ctrl+Shift+G
文本編輯
作用域 功能 快捷鍵
文本編輯器 改寫切換 Insert
文本編輯器 上滾行 Ctrl+↑
文本編輯器 下滾行 Ctrl+↓
文件
作用域 功能 快捷鍵
全局 保存 Ctrl+X Ctrl+S
全局 打印 Ctrl+P
全局 關閉 Ctrl+F4
全局 全部保存 Ctrl+Shift+S
全局 全部關閉 Ctrl+Shift+F4
全局 屬性 Alt+Enter
全局 新建 Ctrl+N
項目
作用域 功能 快捷鍵
全局 全部構建 Ctrl+B
源代碼
作用域 功能 快捷鍵
Java編輯器 格式化 Ctrl+Shift+F
Java編輯器 取消注釋 Ctrl+\
Java編輯器 注釋 Ctrl+/
Java編輯器 添加導入 Ctrl+Shift+M
Java編輯器 組織導入 Ctrl+Shift+O
Java編輯器 使用try/catch塊來包圍 未設置,太常用了,所以在這里列出,建議自己設置。也可以使用Ctrl+1自動修正。
運行
作用域 功能 快捷鍵
全局 單步返回 F7
全局 單步跳過 F6
全局 單步跳入 F5
全局 單步跳入選擇 Ctrl+F5
全局 調試上次啟動 F11
全局 繼續 F8
全局 使用過濾器單步執行 Shift+F5
全局 添加/去除斷點 Ctrl+Shift+B
全局 顯示 Ctrl+D
全局 運行上次啟動 Ctrl+F11
全局 運行至行 Ctrl+R
全局 執行 Ctrl+U
重構
作用域 功能 快捷鍵
全局 撤銷重構 Alt+Shift+Z
全局 抽取方法 Alt+Shift+M
全局 抽取局部變量 Alt+Shift+L
全局 內聯 Alt+Shift+I
全局 移動 Alt+Shift+V
全局 重命名 Alt+Shift+R
全局 重做 Alt+Shift+Y
以上內容為轉載~下面內容為原創!
今天在做客戶端程序的自動更新,簡單描述一下,就是從服務器上將更新包下載下來,然后在本地解壓縮,最后刪掉~功能很簡單~
但是問題出在使用JAVA的ZIP模塊做文件的解壓縮不是想象的那么簡單,資源需要釋放,一個不小心就沒有辦法刪除掉原有ZIP文件了~資源的占用確實是個大問題,但是好在,客戶端程序更新完是要重啟的,一切都煙消云散了~對于刪除不掉ZIP文件的問題,我也流氓一下~用DEL硬刪除~此處一定要注意!
Process process = Runtime.getRuntime().exec("cmd /c del f:\\aaa.doc");
這樣的調用是沒有問題~
Process process = Runtime.getRuntime().exec("del f:\\aaa.doc");
這樣寫是不可能對的~
記錄一下,警告一下后人!
Ref from:http://m.tkk7.com/leeguannan/archive/2007/11/29/164044.html
SetCharacterEncodingFilter:
package com.util.filters;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.UnavailableException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class SetCharacterEncodingFilter
??? implements Filter {
? protected String encoding = null;
? protected FilterConfig filterConfig = null;
? protected boolean ignore = true;
? public void destroy() {
??? this.encoding = null;
??? this.filterConfig = null;
? }
? public void doFilter(ServletRequest request, ServletResponse response,
?????????????????????? FilterChain chain) throws IOException, ServletException {
??? // Conditionally select and set the character encoding to be used
?? request.setCharacterEncoding("GBK");
??? // Pass control on to the next filter
??? chain.doFilter(request, response);
? }
? public void init(FilterConfig filterConfig) throws ServletException {
??? this.filterConfig = filterConfig;
??? this.encoding = filterConfig.getInitParameter("encoding");
??? String value = filterConfig.getInitParameter("ignore");
??? if (value == null) {
????? this.ignore = true;
??? }
??? else if (value.equalsIgnoreCase("true")) {
????? this.ignore = true;
??? }
??? else if (value.equalsIgnoreCase("yes")) {
????? this.ignore = true;
??? }
??? else {
????? this.ignore = false;
??? }
? }
? protected String selectEncoding(ServletRequest request) {
??? return (this.encoding);
? }
}
2.解決GET方式出現亂碼的方案
tomcat的server.xml中
<Connector connectionTimeout="20000" maxSpareThreads="75" maxThreads="150" minSpareThreads="25" port="8080" redirectPort="8443" uRIEncoding="UTF-8" useBodyEncodingForURI="true">
</Connector>
注意其中的useBodyEncodingForURI="true"這句是是解決問題的關鍵,但缺省情況下沒有,自己加進去。
然后再用Filter方案解決 解決GET的問題
3.亂碼字符轉換
byte[] bytes = str.getBytes("ISO8859-1");
??? String dept=new String(bytes);
AJAX
在用XMLHttpRequest發送請求時如用post方式傳送數據,容易出現中文亂碼問題!
在Ajax中,默認的編碼方式是UTF-8,所以在服務器端用request.setCharacterEncoding("UTF-8");(對于java言,其它語言可能類似方法)設置編碼即可解決大部份的編碼問題!
?對于服務器端返回的XML文件在用responseXML讀取時也要注意編碼問題!
以下是正確的處理方法:
response.setCharacterEncoding("UTF-8");-----(1)
PrintWriter out=response.getWriter();------(2)
out.println("返回內容");
如上所示,如果1、2的先后順序發生變化就會產生亂碼!
在jsp向頁面輸出圖片的時候,使用response.getOutputStream()會有這樣的提示:java.lang.IllegalStateException:getOutputStream() has already been called for this response,會拋出Exception
//檢查是否是一個文件上傳請求
boolean isMultipart = FileUpload.isMultipartContent(request);
現在我們就可以準備解析這個請求到一個備選的選項了。解析的結果是一個文件選項的List,每個這樣的選項都實現了FileItem接口,處理這些選項將在下面得到討論。
最簡單的情況
最簡單的使用場景可以參照下面:
在這種情景下處理這樣一個請求并不是很簡單的:
//創建一個新的文件上傳句柄
DiskFileUpload upload = new DiskFileUpload();
//解析請求
List /* FileItem */ items = upload.parseRequest(request);
這就是所有我們需要做的,真的!
解析的結果是一個文件項目的List,每一個都實現了FileItem接口。處理這些項目將在下面討論。
練習更多的控制
如果你的使用情景非常接近最簡單的使用方式,在上文中可以看到,但是你需要更多的控制臨界的大小和臨時文件的駐留地址,你可以使用DiskFileUpload類的方法來自定義這些動作,就像這樣:
//創建一個新的文件上傳句柄
DiskFileUpload upload = new DiskFileUpload();
//設置上傳參數
upload.setSizeThrehold(最大內存大小);
upload.setSizeMax(最大請求大小);
upload.setRepositoryPath(臨時目錄);
//解析請求
List /* FileItem */ items = upload.parseRequest(request);
當然,每個配置方法都是獨立于其它的,但是如果你想一次就配置它們,你可以使用可選的parseRequest()方法,像這樣:
// 建立一個新的文件上傳句柄
DiskFileUpload upload = new DiskFileUpload();
// 解析請求
List /* FileItem */ items = upload.parseRequest(request,
??????? 內存大小, 允許上傳的最大文件, 臨時目錄);
如果你想更多地控制請求的解析,比如把上傳選項存儲到其它地方,例如,存到數據庫中-你可以參照自定義FileUpload。
處理上傳選項
一旦解析過程完畢,你就可以獲得一個文件選項的List,以便進一步處理。在大多數情況下,你將會根據規則的表單域來不同地處理文件的上傳。所以你可能以這樣的方式來處理:
// 處理上傳的選項
Iterator iter = items.iterator();
while (iter.hasNext()) {
??? FileItem item = (FileItem) iter.next();
??? if (item.isFormField()) {
??????? processFormField(item);
??? } else {
??????? processUploadedFile(item);
??? }
}
對于一個規則的表單域來說,你對它感興趣的可能就只有它的名字以及它的字符串值。你也會想到,處理它們是簡單的:
//處理一個規則表單域
if (item.isFormField()) {
??? String name = item.getFieldName();
??? String value = item.getString();
??? ...
}
而對于一個文件的上傳,在你處理它的內容之前,可以有好多令你想知道的不同的東西,這里有一個采用了一些你可能感興趣的方法的例子
// 處理一個文件上傳
if (!item.isFormField()) {
??? String fieldName = item.getFieldName();
??? String fileName = item.getName();
??? String contentType = item.getContentType();
??? boolean isInMemory = item.isInMemory();
??? long sizeInBytes = item.getSize();
??? ...
}
對于這些上傳的文件,你一般不想通過內存來存取它們,除非它們很小,或者你沒有其它好的方法,更進一步,你想將內容當作文件流來處理,或者將整個文件寫到最終的地址。FileUpload提供了簡單的方法來完成這些 操作。
// 處理一個文件上傳的情況
if (writeToFile) {
??? File uploadedFile = new File(...);
??? item.write(uploadedFile);
} else {
??? InputStream uploadedStream = item.getInputStream();
??? ...
??? uploadedStream.close();
}
注意到,在默認的FileUpload的實現中,write()方法將嘗試把文件改名以將它保存到特定的地點,如果數據已經在臨時文件中了,如果重命名失敗,實際的復制文件就完成了(?),在其它原因看來,或者數據已經在內存中了。如果你的確需要在內存中取上傳的數據,你只需簡單的調用get()方法來把它當作一個字符數組來獲得。
// 在內存中處理一個上傳的文件
byte[] data = item.get();
...
和殺毒軟件的相互作用
當web容器在運行時,而殺毒軟件又同時運行在同樣的系統上,這種情況下在應用中使用FileUpload容易導致一些很難預料的事情.這部分將描述一些你可能要遇到的情況,我們會提供一些方法來處理它們。默認的FileUpload實現將會使超過它在內存中大小的上傳的選項寫入到磁盤。而當這樣的文件關閉后,任何系統中的殺毒軟件都會被喚醒,然后去檢查它,然后會潛在地隔離這個文件--就是說,將它移動到一個不產生問題的特定地方。這樣一來,對開發者來說當然是一個意外,因為剛剛上傳的文件將不能被處理了。從另一方面來說,小于設定的內存大小的那些上傳的文件將被保持在內存中,這樣一來,將不會被殺毒軟件所檢測到,這樣就有可能使病毒以某種方式駐留在了系統中了(雖然如果一旦它被寫入到磁盤,殺毒軟件就會定位并檢測到它)。一個通用的解決方法是在系統中專門設置一個目錄來存放這些上傳的文件,然后配置殺毒軟件忽略這個目錄。這樣將確保上傳的文件在系統中不被隔離,但是這樣就把掃描病毒的責任交給了應用程序的開發者了。掃描這些上傳的文件的任務可以在外部的處理中實現。這樣可以將干凈的文件移動到一個“改進”過的地方,或者也可以把殺毒集成到應用中去。至于怎么將外部處理或集成病毒掃描到一個
應用,這個已經超出了本文檔的討論范圍。
下一步是什么
希望這個頁面能提供給你一個好的意見,讓你在你自己的應用中能使用FileUpload。更多關于這里介紹的方法,以及其它可用的方法,你可以參照api文檔。這里介紹的用法已經可以滿足大多數的文件上傳的需要了,當然,如果你還有更多的復雜的需求,使用它的靈活的自定義配置的能力,FileUpload一定可以能夠幫助你。
另一個實例:
commons.fileupload實現文件的上傳,代碼如下:
<%!
?//服務器端保存上傳文件的路徑
??? String saveDirectory = "g:\\upload\\";
??? // 臨時路徑 一旦文件大小超過getSizeThreshold()的值時數據存放在硬盤的目錄
??? String tmpDirectory = "g:\\upload\\tmp\\";
??? // 最多只允許在內存中存儲的數據大小,單位:字節
??? int maxPostSize = 1024 * 1024;
%>
<%
??? // 文件內容?
??? String FileDescription = null;
??? // 文件名(包括路徑)
??? String FileName = null;
??? // 文件大小
??? long FileSize = 0;
??? // 文件類型
??? String ContentType = null;
%>
<%
?? DiskFileUpload fu = new DiskFileUpload();
??? // 設置允許用戶上傳文件大小,單位:字節
?? fu.setSizeMax(200*1024*1024);
??? // 設置最多只允許在內存中存儲的數據,單位:字節
?? fu.setSizeThreshold(maxPostSize);
??? // 設置一旦文件大小超過getSizeThreshold()的值時數據存放在硬盤的目錄
?? fu.setRepositoryPath("g:\\upload\\tmp\\");
??? //開始讀取上傳信息 得到所有文件
?? try{
????? List fileItems = fu.parseRequest(request);
???? }catch(FileUploadException e){
???????? //這里異常產生的原因可能是用戶上傳文件超過限制、不明類型的文件等
???????? //自己處理的代碼
???? }
%>
<%
?? // 依次處理每個上傳的文件
?? Iterator iter = fileItems.iterator();
?? while (iter.hasNext()) {
???? FileItem item = (FileItem) iter.next();
?????? //忽略其他不是文件域的所有表單信息
???? if (!item.isFormField()) {
?????? String name = item.getName();
?????? long size = item.getSize();
?????? String? contentType = item.getContentType();
???? if((name==null||name.equals("")) && size==0)
?????? continue;
%>
<%
?? //保存上傳的文件到指定的目錄
? String[] names=StringUtils.split(name,"\\");? //對原來帶路徑的文件名進行分割
?? name = names[names.length-1];
?? item.write(new File(saveDirectory+ name));
? }
}
%>
?下面是其簡單的使用場景:
?A、上傳項目只要足夠小,就應該保留在內存里。
?B、較大的項目應該被寫在硬盤的臨時文件上。
?C、非常大的上傳請求應該避免。
?D、限制項目在內存中所占的空間,限制最大的上傳請求,并且設定臨時文件的位置。
?
?可以根據具體使用用servlet來重寫,具體參數配置可以統一放置到一配置文件
?
?文件的下載用servlet實現
????? public void doGet(HttpServletRequest request,
?????????????????????? HttpServletResponse response)
???? {
??????? ?String aFilePath = null;??? //要下載的文件路徑
???????? String aFileName = null;??? //要下載的文件名
???????? FileInputStream in = null;? //輸入流
???????? ServletOutputStream out = null;? //輸出流
???????? try
???{
???????? ?
???????????? aFilePath = getFilePath(request);
???????????? aFileName = getFileName(request);
???????????? response.setContentType(getContentType(aFileName) + "; charset=UTF-8");
???????????? response.setHeader("Content-disposition", "attachment; filename=" + aFileName);
???????????? in = new? FileInputStream(aFilePath + aFileName); //讀入文件
??????????? out = response.getOutputStream();
??????????? out.flush();
?????????? ?int aRead = 0;
?????????? while((aRead = in.read()) != -1 & in != null)
?????? ?{
???????????? out.write(aRead);
???????? }
?????????? out.flush();
????? }
?????? catch(Throwable e)
???? {
???? log.error("FileDownload doGet() IO error!",e);
????? }
???????? finally
???????? {
???????????? try
???????????? {
???????????????? in.close();
???????????????? out.close();
???????????? }
???????????? catch(Throwable e)
???????????? {
???????????? ?log.error("FileDownload doGet() IO close error!",e);
???????????? }
???????? }
???? }
<%@ page contentType="image/jpeg" import="java.awt.*,
java.awt.image.*,java.util.*,javax.imageio.*" %>
<%!
Color getRandColor(int fc,int bc){//給定范圍獲得隨機顏色
??????? Random random = new Random();
??????? if(fc>255) fc=255;
??????? if(bc>255) bc=255;
??????? int r=fc+random.nextInt(bc-fc);
??????? int g=fc+random.nextInt(bc-fc);
??????? int b=fc+random.nextInt(bc-fc);
??????? return new Color(r,g,b);
??????? }
%>
<%
//設置頁面不緩存
response.setHeader("Pragma","No-cache");
response.setHeader("Cache-Control","no-cache");
response.setDateHeader("Expires", 0);
// 在內存中創建圖象
int width=60, height=20;
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// 獲取圖形上下文
Graphics g = image.getGraphics();
//生成隨機類
Random random = new Random();
// 設定背景色
g.setColor(getRandColor(200,250));
g.fillRect(0, 0, width, height);
//設定字體
g.setFont(new Font("Times New Roman",Font.PLAIN,18));
//畫邊框
//g.setColor(new Color());
//g.drawRect(0,0,width-1,height-1);
// 隨機產生155條干擾線,使圖象中的認證碼不易被其它程序探測到
g.setColor(getRandColor(160,200));
for (int i=0;i<155;i++)
{
?int x = random.nextInt(width);
?int y = random.nextInt(height);
??????? int xl = random.nextInt(12);
??????? int yl = random.nextInt(12);
?g.drawLine(x,y,x+xl,y+yl);
}
// 取隨機產生的認證碼(4位數字)
String sRand="";
for (int i=0;i<4;i++){
??? String rand=String.valueOf(random.nextInt(10));
??? sRand+=rand;
??? // 將認證碼顯示到圖象中
??? g.setColor(new Color(20+random.nextInt(110),20+random.nextInt(110),20+random.nextInt(110)));
//調用函數出來的顏色相同,可能是因為種子太接近,所以只能直接生成
??? g.drawString(rand,13*i+6,16);
}
// 將認證碼存入SESSION
session.setAttribute("rand",sRand);
// 圖象生效
g.dispose();
// 輸出圖象到頁面
ImageIO.write(image, "JPEG", response.getOutputStream());
%>
使用驗證碼圖片的文件a.jsp
<%@ page contentType="text/html;charset=gb2312" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>認證碼輸入頁面</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Cache-Control" CONTENT="no-cache">
<META HTTP-EQUIV="Expires" CONTENT="0">
</head>
<body>
<form method=post action="check.jsp">
<table>
<tr>
<td align=left>系統產生的認證碼:</td>
<td><img border=0 src="image.jsp"></td>
</tr>
<tr>
<td align=left>輸入上面的認證碼:</td>
<td><input type=text name=rand maxlength=4 value=""></td>
</tr>
<tr>
<td colspan=2 align=center><input type=submit value="提交檢測"></td>
</tr>
</form>
</body>
</html>
驗證的頁面check.jsp
<%@ page contentType="text/html; charset=gb2312" language="java" import="java.sql.*" errorPage="" %>
<html>
<head>
<title>認證碼驗證頁面</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Cache-Control" CONTENT="no-cache">
<META HTTP-EQUIV="Expires" CONTENT="0">
</head>
<body>
<%
?String rand = (String)session.getAttribute("rand");
?String input = request.getParameter("rand");
%>
系統產生的認證碼為: <%= rand %><br>
您輸入的認證碼為: <%= input %><br>
<br>
<%
? if (rand.equals(input)) {
%>
<font color=green>輸入相同,認證成功!</font>
<%
? } else {
%>
<font color=red>輸入不同,認證失敗!</font>
<%
? }
%>
</body>
</html>