一.徹底明白操作系統環境變量
設置環境變量有兩種方式:第一種是在命令提示符運行窗口中設置;第二種是通過單擊“我的電腦→屬性→高級”標簽的“環境變量”按鈕設置。需要注意的是,第一種設置環境變量的方式只對當前運行窗口有效,關閉運行窗口后,設置就不起作用了,而第二種設置環境變量的方式則是永久有效。
2.如何在命令提示符窗口中設置環境變量?
在“開始→運行”框中輸入“cmd”后按“確定”按鈕,出現命令運行窗口。在命令提示符下輸入“set”即可查看環境變量設置。要查看具體某個環境變量的設置,比如要查看path環境變量的設置,可以輸入“set path”。要創建一個環境變量,比如要創建一個名為aa的,值為“c:”的環境變量,可以輸入“set aa=c:”命令。而要刪除一個環境變量,比如要刪除aa環境變量,則可輸入“set aa=”命令(注意=后面不能有空格)。如何更改一個環境變量的設置呢?更改環境變量有兩種情況:一是追加方式,即在不改變環境變量現有設置的情況下,增加變量的值,比如要給環境變量aa增加一個值為“D:”的設置,可以輸入“set aa=%path%;D:”。另一種是完全修改方式,對于這種方式,我們可以采用直接創建一個環境變量的方法來實現。
3.用戶變量和系統變量的關系是什么?
點擊“我的電腦→屬性→高級”標簽的“環境變量”按鈕,出現“環境變量”對話框,如果當前是以Administrator登錄系統的用戶,對話框的上面為Administrator的用戶變量,對話框的下面為系統變量(即相當于系統中所有用戶的用戶變量)。有的時候我們會看到在用戶變量和系統變量中都存在某一個環境變量,比如path,那么path的值到底是用戶變量中的值還是系統變量中的值,或者兩者都不是呢?答案是兩者都不是。path變量的值是用戶變量中的值與系統變量中的值的疊加。
4.改變環境變量和環境變量中的值應該注意什么?
環境變量和環境變量的值不要含有空格,也不要用中文,切記!
二.Windows系統環境變量
在Dos輸入:SET 而不加參數,可以顯示Windows當前的環境變量。
Windows 系統環境變量列表:
%ALLUSERSPROFILE% : 列出所有用戶Profile文件位置。
%APPDATA% :??? 列出應用程序數據的默認存放位置。
%CD% :??? 列出當前目錄。
%CLIENTNAME% :??? 列出聯接到終端服務會話時客戶端的NETBIOS名。
%CMDCMDLINE% :??? 列出啟動當前cmd.exe所使用的命令行。
%CMDEXTVERSION% :??? 命令出當前命令處理程序擴展版本號。
%CommonProgramFiles% :??? 列出了常用文件的文件夾路徑。
%COMPUTERNAME% :??? 列出了計算機名。
%COMSPEC% :??? 列出了可執行命令外殼(命令處理程序)的路徑。
%DATE% :??? 列出當前日期。
%ERRORLEVEL% :??? 列出了最近使用的命令的錯誤代碼。
%HOMEDRIVE% :??? 列出與用戶主目錄所在的驅動器盤符。
%HOMEPATH% :??? 列出用戶主目錄的完整路徑。
%HOMESHARE% :??? 列出用戶共享主目錄的網絡路徑。
%LOGONSEVER% :??? 列出有效的當前登錄會話的域名控制器名。
%NUMBER_OF_PROCESSORS% :??? 列出了計算機安裝的處理器數。
%OS% :??? 列出操作系統的名字。(Windows XP 和 Windows 2000 列為 Windows_NT.)
%Path% :??? 列出了可執行文件的搜索路徑。
%PATHEXT% :??? 列出操作系統認為可被執行的文件擴展名。
%PROCESSOR_ARCHITECTURE% :??? 列出了處理器的芯片架構。
%PROCESSOR_IDENTFIER% :??? 列出了處理器的描述。
%PROCESSOR_LEVEL% :??? 列出了計算機的處理器的型號。
%PROCESSOR_REVISION% :??? 列出了處理器的修訂號。
%ProgramFiles% :??? 列出了Program Files文件夾的路徑。
%PROMPT% :??? 列出了當前命令解釋器的命令提示設置。
%RANDOM% :??? 列出界于0 和 32767之間的隨機十進制數。
%SESSIONNAME% :??? 列出連接到終端服務會話時的連接和會話名。
%SYSTEMDRIVE% :??? 列出了Windows啟動目錄所在驅動器。
%SYSTEMROOT% :??? 列出了Windows啟動目錄的位置。
%TEMP% and %TMP% :??? 列出了當前登錄的用戶可用應用程序的默認臨時目錄。
%TIME% :??? 列出當前時間。
%USERDOMAIN% :??? 列出了包含用戶帳號的域的名字。
%USERNAME% :??? 列出當前登錄的用戶的名字。
%USERPROFILE% :??? 列出當前用戶Profile文件位置。
%WINDIR% :??? 列出操作系統目錄的位置
三.明明白白XP系統環境變量
近日,筆者一個朋友的計算機出現了一個奇怪現象:在Windows XP系統的命令行模式中運行所有命令都提示該命令不是內部或外部命令,也不能運行可執行文件和或批處理文件。
解決篇:
筆者認為是執行這些命令的可執行文件被誤刪造成的,進入系統安裝目錄的system32目錄中發現ipconfig等可執行文件仍然存在,并沒有被刪除或改動的跡象。
第一步:在目錄中直接運行這些可執行文件發現可以調出一個命令執行窗口,不過一閃即逝。由此可斷定這些可執行文件沒有問題,是完好無損的。
第一步:輸入“CMD”命令進入命令行模式,然后進入“c:\windows\system32”目錄運行ipconfig命令,發現一切正常,IP地址及DNS等信息全部顯示出來了。
第四步:筆者通過“我的電腦→屬性→高級”標簽的“環境變量”按鈕查看相關信息。發現“系統變量”中的Path項值為空,這應該是問題的關鍵,由于默認Path為空,所以在任意路徑下運行諸如ipconfig的命令系統將無法找到該程序。雙擊path參數為其設置變量值“c:\windows\system32”。
第六步:確定后再在命令行模式中輸入“ipconfig”就能顯示出正確的信息了。
小提示:如果你希望設置多個默認路徑可以采用諸如c:\windows\system32;c:\windows的形式,即中間用“;”隔開。
思考篇:
分析本地故障原因就是因為環境變量中的默認路徑被刪除的結果,默認路徑一經設置,當前系統如有程序運行時需要某些DLL或EXE文件,以及Active控件時就會到所有默認路徑中去查找,如果在這些目錄中查找到相應的程序則自動加載,查找不到則報告缺少某某文件的錯誤信息。
小知識:什么是環境變量?環境變量一般是指在操作系統中用來指定操作系統運行環境的一些參數,比如臨時文件夾位置和系統文件夾位置等。這點有點類似于DOS時期的默認路徑,當你運行某些程時序除了在當前文件夾中尋找外,還會到設置的默認路徑中去查找。簡單地說這里的“Path”就是一個變量,里面存儲了一些常用命令所存放的目錄路徑。
很多朋友會在自己的計算機上安裝雙系統,例如C盤安裝Windows 98,D盤安裝Windows XP。可是某些軟件往往只在Windows 98系統中安裝,Windows XP系統中是無法正常使用的,比較麻煩卻有效的方法是再安裝一遍。當我們了解了環境變量中的用途后就可以很好解決雙系統的軟件共用問題。
小提示:為什么在Windows 98中安裝了的軟件在Windows XP下無法運行呢(綠色軟件除外)?原因是安裝軟件時往往須要向系統目錄中復制某些文件,而使用另外一個系統時會由于缺少這些文件而無法運行。因此,我們可以通過設置環境變量的方法來解決這個問題。
實例:通過設置默認路徑解決雙系統共用應用軟件的問題
任務描述:
安裝了雙系統的本地計算機,C盤為Windows 98系統,安裝了COOL 3D,D盤為Windows XP系統。希望在不重新安裝軟件的前提下可以在D盤系統中正常運行COOL 3D程序。
在Windows XP中直接找到COOL 3D的安裝目錄并運行其執行文件,會彈出報錯對話框。
實現方法:
第一步:在Windows XP系統中的“我的電腦”上點鼠標右鍵選擇“屬性”。在系統屬性窗口選擇“高級”標簽并按“環境變量”按鈕。
第二步:將環境變量設置窗口中的系統變量里的Path值中添加如下目錄:“c:\windows\system32;c:\windows\system;c:\windows”(不含引號)。
第三步:設置完畢后就可以順利運行COOL 3D了,如果需要系統文件會自動到上面提到的C盤Windows 98相應目錄去查找。
總結:
有些軟件不用通過在環境變量中修改默認路徑的方法就可以在D盤系統中正常啟動,例如超級解霸等軟件,因為它們并沒有往系統目錄中復制任何文件。另外修改默認路徑法也并不是對所有軟件有效,對于一些啟動需要加載注冊表中鍵值才能使用的軟件,可能會出現提示要求輸入注冊碼的窗口,輸入正確數值后仍即可正常使用。如果通過修改默認路徑法仍然無法啟動軟件的話,很有可能是因為Windows 98與Windows XP系統的某些DLL文件有區別而無法通用,這種情況只能在Windows XP系統中重新安裝該軟件。
四.我使用的系統為Windows XP,我想把系統臨時文件(Temp文件)存放區由C盤移到其他分區(如D盤),請問該如何操作?
在“我的電腦”上點鼠標右鍵,選擇“屬性”,然后進入高級選項,點“環境變量”,在“系統變量”下拉菜單中找到“TEMP”、“TMP”這兩項,分別編輯,將變量值設為你需要改變的路徑(例如D:\temp),注意兩項改為相同路徑,然后在D盤上建立一個temp目錄,最后重啟計算機即可。
posted @
2007-07-23 04:24 jadmin 閱讀(99) |
評論 (0) |
編輯 收藏
1 最基本的亂碼問題。
這個亂碼問題是最簡單的亂碼問題。一般新會出現。就是頁面編碼不一致導致的亂碼。
<%@ page language="java" pageEncoding="UTF-8"%>
<%@ page contentType="text/html;charset=iso8859-1"%>
<html>
<head>
<title>中文問題</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
</head>
<body>
??? 我是個好人
</body>
</html>
三個地方的編碼。
第一個地方的編碼格式為jsp文件的存儲格式。Eclipse會根據這個編碼格式保存文件。并編譯jsp文件
,包括里面的漢字。
第二處編碼為解碼格式。因為存為UTF-8的文件被解碼為iso8859-1,這樣 如有中文肯定出亂碼。也就
是必須一致。而第二處所在的這一行,可以沒有。缺省也是使用iso8859-1的編碼格式。所以如果沒有
這一行的話,“我是個好人”也會出現亂碼。必須一致才可以。
??? 第三處編碼為控制瀏覽器的解碼方式。如果前面的解碼都一致并且無誤的話,這個編碼格式沒有關系
。有的網頁出現亂碼,就是因為瀏覽器不能確定使用哪種編碼格式。因為頁面有時候會嵌入頁面,導致
瀏覽器混淆了編碼格式。出現了亂碼。
2 表單使用Post方式提交后接收到的亂碼問題
這個問題也是一個常見的問題。這個亂碼也是tomcat的內部編碼格式iso8859-1在搗亂,也就是說post
提交時,如果沒有設置提交的編碼格式,則會以iso8859-1方式進行提交,接受的jsp卻以utf-8的方式
接受。導致亂碼。既然這樣的原因,下面有幾種解決方式,并比較。
A 接受參數時進行編碼轉換
String str = new String(request.getParameter("something").getBytes("ISO-8859-1"),"utf-8")
; 這樣的話,每一個參數都必須這樣進行轉碼。很麻煩。但確實可以拿到漢字。
B 在請求頁面上開始處,執行請求的編碼代碼, request.setCharacterEncoding("UTF-8"),把提交內
容的字符集設為UTF-8。這樣的話,接受此參數的頁面就不必在轉碼了。直接使用
String str = request.getParameter("something");即可得到漢字參數。但每頁都需要執行這句話。
這個方法也就對post提交的有效果,對于get提交和上傳文件時的enctype="multipart/form-data"是無
效的。稍后下面單獨對這個兩個的亂碼情況再進行說明。
C 為了避免每頁都要寫request.setCharacterEncoding("UTF-8"),建議使用過濾器對所有jsp
??? 進行編碼處理。這個網上有很多例子。請大家自己查閱。
3 表單get提交方式的亂碼處理方式。
如果使用get方式提交中文,接受參數的頁面也會出現亂碼,這個亂碼的原因也是tomcat的內部編碼格
式iso8859-1導致。Tomcat會以get的缺省編碼方式iso8859-1對漢字進行編碼,編碼后追加到url,導致
接受頁面得到的參數為亂碼/、。
解決辦法:
A 使用上例中的第一種方式,對接受到的字符進行解碼,再轉碼。
B Get走的是url提交,而在進入url之前已經進行了iso8859-1的編碼處理。要想影響這個編碼則需要在
server.xml的Connector節點增加useBodyEncodingForURI="true"
屬性配置,即可控制tomcat對get方式的漢字編碼方式,上面這個屬性控制get提交也是用
request.setCharacterEncoding("UTF-8")所設置的編碼格式進行編碼。所以自動編碼為utf-8,接受頁
面正常接受就可以了。但我認為真正的編碼過程是,tomcat又要根據
<Connector port="8080"
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" redirectPort="8443" acceptCount="100"
debug="0" connectionTimeout="20000" useBodyEncodingForURI="true"
disableUploadTimeout="true" URIEncoding=”UTF-8”/>
里面所設置的URIEncoding=”UTF-8”再進行一次編碼,但是由于已經編碼為utf-8,再編碼也不會有變
化了。如果是從url獲取編碼,接受頁面則是根據URIEncoding=”UTF-8”來進行解碼的。
4 上傳文件時的亂碼解決
??? 上傳文件時,form表單設置的都是enctype="multipart/form-data"。這種方式以流方式提交文件。
如果使用apach的上傳組件,會發現有很多亂碼想象。這是因為apach的先期commons-fileupload.jar有
bug,取出漢字后進行解碼,因為這種方式提交,編碼又自動使用的是tomcat缺省編碼格式iso-8859-1
。但出現的亂碼問題是: 句號,逗號,等特殊符號變成了亂碼,漢字如果數量為奇數,則會出現亂碼
,偶數則解析正常。
????? 解決方式: 下載commons-fileupload-1.1.1.jar 這個版本的jar已經解決了這些bug。
但是取出內容時仍然需要對取出的字符進行從iso8859-1到utf-8轉碼。已經能得到正常所有漢字以及字
符。
5 Java代碼關于url請求,接受參數的亂碼
url的編碼格式,取決于上面所說的URIEncoding=”UTF-8”。 如果設定了這個編碼格式,則意味著所
有到url的漢字參數,都必須進行編碼才可以。否則得到的漢字參數值都是亂碼,例如
一個鏈接 Response.sendDerect(“/a.jsp?name=張大維”);而在a.jsp里面直接使用
String name");得到的就是亂碼。因為規定了必須是utf-8才可以,所以,這個轉向應該這樣寫:
????? Response.sendDerect(“/a.jsp?name=URLEncode.encode(“張大維”,”utf-8”);才可以。
如果不設置這個參數URIEncoding=”UTF-8”, 會怎么樣呢? 不設置則就使用了缺省的編碼格式
iso8859-1。問題又出來了,第一就是參數值的個數如果是奇數個數,則就可以正常解析,如果使偶數
個數,得到最后字符就是亂碼。還有就是如果最后一個字符如果是英文,則就能正常解析,但中文的標
點符號仍出現亂碼。權宜之計,如果您的參數中沒有中文標點符號,則可以在參數值最后加一個英文符
號來解決亂碼問題,得到參數后再去掉這個最后面的符號。也可以湊或使用。
6 腳本代碼關于url請求,接受到的參數亂碼
腳本中也會進行頁面轉向的控制,也會涉及到附帶參數,并在接受頁面解析這個參數的情況。如果這個
漢字參數不進行URIEncoding=”UTF-8”所指定的編碼處理,則接受頁面接受到的漢字也是亂碼。腳本
處理編碼比較麻煩,必須有相應的編碼腳本對應文件,然后調用腳本中的方法對漢字進行編碼即可。
7 關于jsp在MyEclipse中打開的亂碼問題
對于一個已經存在的項目,Jsp文件的存儲格式可能是utf-8。如果新安裝的eclipse,則缺省打開使用
的編碼格式都是iso8859-1。所以導致jsp里面的漢字出現亂碼。這個亂碼比較容易解決,直接到
eclipse3.1的偏好設置里面找到general-〉edidor,設置為您的文件打開編碼為utf-8即可。Eclipse會
自動重新以新的編碼格式打開。漢字即可正常顯示。
8 關于html頁面在eclipse中打開出現亂碼情況
由于大部分頁面都是由dreamweaver制作,其存儲格式跟eclipse的識別有差別導致。
一般這種情況,在eclipse中新建一個jsp,直接從dreamweaver復制頁面內容粘貼到jsp即可。
//////////////////////////////////////////////////////////////////////////////////////////
jsp中文亂碼問題的解決辦法 jsp中java中文編碼問題的個人經驗|終于看到一個完全解決的方案
四月 5th, 2006
====================http://www.glgg.net/blog===================
開發java應用出現亂碼是很常見的,畢竟現在unicode的使用還不是很廣泛,在使用gb2312(包含了gbk
簡體,big5繁體)的系統中要正確實現
中文的display和數據庫的存儲是最基本的要求。
========================http://www.glgg.net/blog===============
1,首先developer要明確自己為什么會遇到亂碼,遇到什么樣的亂碼(無意義的符號還是一串問號或者
其它什么東西)。
新手遇到一堆很亂的字符時通常不知所措,最直接的反映就是打開google搜索”java中文”(這個字符
串在搜索引擎上的查詢頻率非常高),
然后一個一個的去看別人的解決方法。這樣做沒有錯,但是很難達到目的,原因下面會提到。
總之,出現亂碼的原因是非常多的,解決的方法也完全不一樣,要解決問題必須先分析自己的”上下文
環境”。
========================http://www.glgg.net/blog===============
2,具體說來,需要哪些信息才能確定項目中的亂碼的根源。
a,開發者所用的操作系統
b,j2ee容器的名稱,版本
c,數據庫的名稱,版本(精確版本)以及jdbc驅動的版本
d,出現亂碼的source code(比如是system out 出來的,還是jsp頁面中的,如果是jsp中的,那么頭
部聲明的情況也很重要)
=========================http://www.glgg.net/blog==============
3,如何初步分析亂碼出現的原因。
有了上述的信息,基本上就可以發帖求助了,相信放到javaworld等論壇上,很快就會有高手給你提出
有效的解決方案的。
當然不能總靠發帖求助,也要試試自行解決問題。如何下手呢?
a,分析一下你的”亂碼”到底是什么編碼。這個其實不難,比如
System.out.println(testString);
這一段出現了亂碼,那么不妨用窮舉法猜測一下它的實際編碼格式。
System.out.println(new String(testString.getBytes(”ISO-8859-1〃),”gb2312〃));
System.out.println(new String(testString.getBytes(”UTF8〃),”gb2312〃));
System.out.println(new String(testString.getBytes(”GB2312〃),”gb2312〃));
System.out.println(new String(testString.getBytes(”GBK”),”gb2312〃));
System.out.println(new String(testString.getBytes(”BIG5〃),”gb2312〃));
等等,上述代碼的意思是用制定的編碼格式去讀取testString這個”亂碼”,并轉換成gb2312(此處僅
以中文為例)
然后你看哪一個轉換出來的結果是ok的,那就。。。
b,如果用上面的步驟能得到正確的中文,說明你的數據肯定是在的,只不過是界面中沒有正確顯示而
已。那么第二步就該糾正你的view部分了
,通常需要檢查的是jsp中是否選擇了正確的頁面編碼。
在此要聲明被很多人誤解的一點,那就是<%@ page contentType=”text/html; charset=GB2312〃 %>
指令和<META http-equiv=Content-Type
content=”text/html; charset=gb2312〃>兩者的不同。通常網上的很多文章在提到中文問題時都是說
數據庫中選擇unicode或者gb2312存儲,同
時在jsp中用page指令聲明編碼就可以解決。但是我覺得這種說法很不負責任,害的我費了N多時間為本
來并不存在的亂碼而郁悶。實際上page
的作用是在jsp被編譯成為html的過程中提供編碼方式讓java來”讀取”表達式當中的String(有點類
似于上面的第三個語句的作用),而meta
的作用是眾所周知的為IE瀏覽器提供編碼選擇,是用來”顯示”最后的數據的。但是沒有看到有人提醒
這一點,我一直把page當成meta在用,
導致本來是iso-8859的數據,被page指令讀成gb2312,于是亂碼,所以又加了編碼轉化的函數把所有的
string數據都從iso8859轉到gb2312(為
什么這么轉,當時也沒考慮這么多,因為這么做可以正常顯示了,所以就這么改了,呵呵當時實在沒有
時間慢慢排查問題了)。
===========================http://www.glgg.net/blog==============
4,數據庫選擇什么樣的編碼比較好。
目前流行的DB主要有sql server,mysql,oracle,DB2等,其中mysql作為免費DB中的老大,性能和功
能是得到公認的,安裝配置比較方便,相
應的driver也比較完善,性價比是絕對的OK。所以就以mysql為例。
我個人建議采用mysql的默認編碼來存儲,也就是iso-8859-1(在mysql的選項中對應于latin-1)。理
由主要有這么幾個,一是iso-8859-1對中
文的支持不錯;二是跟java中的默認編碼一致,至少在很多地方免除了轉換編碼的麻煩;三是默認的比
較穩定,兼容性也更好,因為多編碼的
支持是由具體的DB產品提供的,別說跟其它的DB會不兼容,即使自身的不同版本也可能出現兼容性的問
題。
例如mysql 4.0以前的產品中,很多中文的解決方案是利用connection中的characterEncoding字段來制
定編碼,比如gb2312什么的,這樣是ok
的,因為原數據都是ISO8859_1編碼,jdbc驅動會采用url里面指定的character set來進行編碼,
resultSet.getString(*)取出的就是編碼后的
字符串。這樣就直接拿到gb2312的數據了。
但是mysql 4.1的推出給很多dbadmin帶來了不小的麻煩,因為mysql4.1支持column level的character
set,每個table,column都可以指定編碼
,不指定就是ISO8895_1,因此jdbc取出數據后會根據column的character set來進行編碼,而不再是用
一個全局的參數來取所有的數據了。
這從另一個方面也說明了亂碼問題的產生實在是很復雜的事情,原因太多了。我也只是針對自己遇
////////////////////////////////////////////////////////////////////////////////////////
???????????????? jsp中文問題解決之道[轉載]
和Java一樣,JSP是目前比較熱門的一個話題。它是一種在服務器端編譯執行的Web設計語言,因為腳本
語言采用了Java,所以JSP繼承了Java的所有優點。可是在使用JSP程序的過程中,常遇到中文亂碼問題
,很多人為此頭疼不已,初學的時候我就深受其害,而且使用平臺不同,中文亂碼問題的解決方法也不
同,無形中增加了學習JSP的難度。其實,在徹底了解相關原因后,問題還是比較容易解決的。,以下
是我總結的解決方法,相信對讀者會有一定的借鑒意義。??? (因為我使用得最多的是Tomcat環境,所以
主要是以Tomcat為例,其它的環境只會提及一下,但解決辦法也是差不多的!
每個國家(或區域)都規定了計算機信息交換用的字符編碼集,如美國的擴展ASCII碼、中國的GB2312
-80、日本的??? JIS??? 等,作為該國家(區域)信息處理的基礎,有著統一編碼的重要作用。由于各本地字
符集代碼范圍重疊,相互間信息交換困難,軟件本地化版本獨立維護成本較高。因此有必要將本地化工
作中的共性抽取出來,做一致性處理,將特殊的本地化處理內容降低到最少,這就是所謂的國際化
(I18N)。各種語言信息被規范為本地信息,而底層字符集采用包含了所有字符的Unicode。??
相信了解JSP代碼的讀者對ISO8859-1一定不陌生,ISO8859-1是我們平時使用比較多的一個CodePage,
它屬于西歐語系。GB2312-80??? 是在國內計算機漢字信息技術發展初始階段制訂的,其中包含了大部分
常用的一、二級漢字和9區的符號。該字符集是幾乎所有的中文系統和國際化的軟件都支持的中文字符
集,這也是最基本的中文字符集。??
GBK??? 是??? GB2312-80??? 的擴展,是向上兼容的。它包含了20902個漢字,其編碼范圍是??? 0x8140~
0xFEFE,剔除高位??? 0x80??? 的字位,其所有字符都可以一對一映射到??? Unicode??? 2.0,也就是說??? Java
實際上提供了對??? GBK??? 字符集的支持。??
>GB18030-2000(GBK2K)??? 在??? GBK??? 的基礎上進一步擴展了漢字,增加了藏、蒙等少數民族的文字。
GBK2K??? 從根本上解決了字位不夠、字形不足的問題。??
1.Tomcat??? 4開發平臺??
這個版本應該是我們經常用到的版本,所以討論得會比較詳細。
Windows??? 98/2000下的Tomcat??? 4以上版本都會出現中文問題(而在Linux下和Tomcat??? 3.x中則沒有問
題),主要表現是頁面顯示亂碼。
為解決這個問題,最簡單的方法就是在每個JSP的頁面開始處加上<%@??? page??? language=“Java”??
contentType=“text/html;??? charset=gb2312”%>。不過,這還不夠,雖然這時顯示了中文,但是發現
從數據庫讀出的字段變成了亂碼。經過分析發現:??? 在數據庫中保存的中文字符是正常的,數據庫用
ISO8859-1字符集存取數據,而Java程序在處理字符時默認采用統一的ISO8859-1字符集(這也體現了
Java國際化思想),所以在數據添加的時候Java和數據庫都是以ISO8859-1方式處理,這樣不會出錯。但
是在讀取數據的時候就出現問題了,因為數據讀出也采用ISO8859-1字符集,而??? JSP的文件頭中有語句
<%@??? page??? language=“Java”??? contentType=“text/html;??? charset=gb2312”%>,這說明頁面采用
GB2312的字符集顯示,這樣就和讀出的數據不一樣。這時頁面顯示從數據庫中讀出的字符是亂碼,解決
的方法是對這些字符轉碼,從ISO8859-1轉成GB2312,就可以正常顯示了。這個解決辦法對很多平臺具
有通用性,讀者可以靈活運用。具體的方法會在以下詳細講解。另外,對于不同的數據庫如SQL??
Server,Oracle,Mysql,Sybase等,字符集的選擇很重要。如果考慮多語言版本,數據庫的字符集就
應該統一采用ISO8859-1,需要輸出的時候在不同的字符集之間做轉換就可以了。??
以下是針對不同平臺的總結:??
(1)??? JSWDK只適合于普通開發,穩定性和其他問題可能不如商業軟件。??? 由于JDK??? 1.3版性能要好于
JDK??? 1.2.2很多,并且對中文的支持也較好,所以應該盡量采用。??? 現在jdk已經出到1.4版本了,所以
如果允許最好升級到最新的版本,這樣對中文的也會較好,而且還可以得到更多的支持。??
(2)??? Tomcat僅僅是一個對JSP??? 1.1、Servlet??? 2.2標準的實現,??? 我們不應該要求這個免費軟件在細節
和性能上都面面俱到,??? 它主要考慮英文用戶,??? 這也是為什么不做特殊轉換,漢字用URL方法傳遞就有
問題的原因。大部分IE瀏覽器缺省始終以UTF-8發送,??? 這似乎是Tomcat的一個不足,??? 另外Tomcat不管
當前的操作系統是什么語言,??? 都按ISO8859去編譯JSP,??? 似乎也欠妥。??
2.JSP代碼的中文處理
(1)如果與數據無關的操作,可以在頁面首行加入
(2)將Form中的值傳送到數據庫中再取出來后全變成了“?”。Form用POST提交數據,代碼中使用了語
句:
String??? st=new(request.getParameter(“name”).getBytes(“ISO8859_1”)),??? 而且也聲明了
charset=gb2312。??
要處理Form中傳遞的中文參數,應該在JSP中加入下面的代碼,另外定義一個專門解決這個問題的
getStr類,然后對接收到的參數進行轉換:??
String??? keyword1=request.getParameter(“keyword1”);??
keyword1=getStr(keyword1);??
這樣就可以解決問題了,代碼如下:??
<%@??? page??? contentType=“text/html;charset=gb2312”%>??
<%!??
public??? String??? getStr(String??? str){??
try{String??? temp_p=str;??
byte[]??? temp_t=temp_p.getBytes(“ISO8859-1”);??
String??? temp=new??? String(temp_t);??
return??? temp;??
}??
catch(Exception??? e){??? }??
return??? “NULL”;??
}??
%>??
<%--http://www.cndes.com測試--%>??
<%??? String??? keyword=“創聯網絡技術中心歡迎您的到來”;??
String??? keyword1=request.getParameter(“keyword1”);??
keyword1=getStr(keyword1);??
out.print(keyword);??
out.print(keyword1);??
%>??
另外,流行的關系數據庫系統都支持數據庫Encoding,也就是說在創建數據庫時可以指定它自己的字符
集設置,數據庫的數據以指定的編碼形式存儲。當應用程序訪問數據時,在入口和出口處都會有??
Encoding??? 轉換。對于中文數據,數據庫字符編碼的設置應當保證數據的完整性。??? GB2312、GBK、
UTF-8??? 等都是可選的數據庫??? Encoding,也可以選擇??? ISO8859-1??? (8-bit),??? 但會增加了編程的復
雜度,ISO8859-1不是推薦的數據庫??? Encoding。在JSP/Servlet編程時,可以先用數據庫管理系統提供
的管理功能檢查其中的中文數據是否正確。??
(3)JDBC??? Driver的字符轉換??
目前大多數JDBC??? Driver采用本地編碼格式來傳輸中文字符,例如中文字符“0x4175”會被轉成“0x41
”和“0x75”進行傳輸。因此需要對JDBC??? Driver返回的字符以及要發給JDBC??? Driver的字符進行轉換
。當用JDBC??? Driver向數據庫中插入數據時,需要先將Unicode轉成Native??? code;??? 當??? JDBC??? Driver
從數據庫中查詢數據時,則需要將Native??? code轉換成Unicode。下面給出了這兩種轉換的實現:??
String??? native2Unicode(String??? s)??? {??
if??? (s??? ==??? null??? ||??? s.length()??? ==??? 0)??? {??
return??? null;??
}??
byte[]??? buffer??? =??? new??? byte[s.length()];??
for??? (int??? i??? =??? 0;??? i??? s.length();??? i++)??? {??? if??? (s.charAt(i)>=??? 0x100)??? {??
c??? =??? s.charAt(i);??
byte??? []buf??? =??? (“”+c).getBytes();??
buffer[j++]??? =??? (char)buf[0];??
buffer[j++]??? =??? (char)buf[1];??
}??
else??? {buffer[j++]??? =??? s.charAt(i);}??
}??
return??? new??? String(buffer,??? 0,??? j);??
}??
要注意的是,有些JDBC??? Driver如果通過JDBC??? Driver??? Manager設置了正確的字符集屬性,以上方法
就不需要了。具體情況可參考相關JDBC的資料。??
其實理解了,中文亂碼就這么一回事!反復使用就會摸出一定的門道了!我覺得以上的三種方法,只要你
真的能弄懂,在遇到中文問題時,在這三種方法多試嘗,我保證你不再會使這種中文問題所煩!
以上只是自己的一些經驗所談,如果有什么不對,希望能提出,共同學習!???
//////////////////////////////////////////////////////////////////////////////////////////
我的亂碼之路——JSP與MySQL交互的中文亂碼解決方案及總結
?????? 首先實現了一個StringConvert bean(GBtoISO()和ISOtoGB()兩個方法),解決了與MySQL數據庫
交互的時候的部分中文亂碼問題:在JSP程序中讀取MySQL的中文內容,用這兩個方法可以解決亂碼問題
。
????? 但是從JSP寫入到MySQL的中文內容都成了亂碼,并且再讀出來的時候也顯示為“??”,在這里應
該出現了編碼轉換過程中的字符信息丟失。郁悶的是,我在命令行窗口中登陸到MySQL后,執行如
“Insert INTO customerVALUES('字符',...)”這樣的語句時,寫入到數據表中的中文內容又是顯示正
常的!!!數據庫使用的字符集是utf8。
?????
?????? 碰壁多次,終于發現一條解決問題的路徑:查看MySQL手冊的時候,看到一條這樣的語句:
Toallow multiple character sets to be sent from the client, the "UTF-8"encoding should be
used, either by configuring "utf8" as the defaultserver character set, or by configuring
the JDBC driver to use "UTF-8"through the characterEncoding property.
?????
?????? 此外,在查閱《MySQL權威指南》時,發現在查詢語句中可以使用這樣的語法將字符串轉換到一個
給定的字符集:_charset str。
?????? 其中charset必須是服務器支持的某個字符集。在本例中,shopdb數據庫使用的默認字符集是utf8
,于是開始測試:
?????? 先輸入Insert INTO publish Values('8',_gb2312 '高等教育出版社')??? 寫入后中文變成“??
”
?????? 再試Insert INTO publish Values('8',_gbk '高等教育出版社') 結果同上
?????? Insert INTO publish Values('8',_utf8 '高等教育出版社') 這下更干脆,什么都沒有!!
?????
?????? 快瘋了!!沒辦法,用show character set;命令查看MySQL支持的字符集,心想我都試一遍總
有一個能成功吧。瀏覽了一下,發現沒有幾個熟悉的字符集,就只剩下一個latin1(ISO-8859-1)比較常
見了,不會是它吧,一試之下果然便是。
?????? Insert INTO publish Values('8',_latin1 '高等教育出版社') 輸入中文能夠正確顯示。
?????
?????? 這下總算找到方法了,把Tomcat下配置的數據庫連接池的url改為
”...characterEncoding=UTF-8”,然后把寫入數據庫的中文內容用
?????? String s2 = new String(s1.getBytes("gb2312"),"ISO-8859-1")進行轉碼,其中s1為中文字符
串.然后再寫入到數據庫一切顯示正常。
?????
?????? 為解決這個問題查看了n多資料,現作一個總結:由于字符集和字符編碼方式的不同,在OS以
及程序之間傳遞數據(尤其是multiple character sets中的數據)時便會產生亂碼以及字符信息的丟
失.解決這個問題的關鍵便是了解數據輸出端和接收端使用的字符集和字符編碼方式,如果這兩種編碼
方式不同,便需要在數據出口或入口處進行 轉碼。一般的說,在編寫代碼,編譯,以及運行期間都會字
符數據的傳遞,因此需要特別小心。
??????? 在編寫代碼的時候,你可能會使用某種開發工具,例如我正在使用的Eclipse.或許在寫的時候
一切正常,可是一旦保存后再次打開文檔,所有的中文字符都變成了亂碼。這是因為在編寫的時候,這
些字符數據都在內存的某個stream中,ok,這沒問題,可是保存的時候這個stream中的數據會被寫入到
硬盤,使用的就是你的開發工具默認的編碼方式,如果很不幸你的開發工具默認編碼方式是ISO-8859-1
,中文字符信息就不能正確地存儲。Eclipse中可以這樣查看并修改默認字符編碼方式:Project-
>Properties->info,這里有”default encoding for text file”。如果設置為GBK,那么編寫代碼
并保存這關就過了。
?????? 對于JSP程序而言,編寫完代碼后就交給Container,首先它們會被轉成.java文件,然后編譯成
.class才能提交給服務器執行.這個過程也存在字符編碼問題.java編譯器(javac)使用操作系統的語
言環境作為默認的字符編碼方式,JRE(Java Runtime Environment)也是這樣。只有當編譯和運行環境
的字符編碼方式與存儲源文件的編碼方式相同時,中文字符才能正確地顯示。否則就需要在運行時進行
轉碼,使它們使用兼容的編碼。這里的設置可以分為幾個層次:操作系統層支持的語言,這是最重要的
,因為它會影響JVM的默認字符編碼方式,同時對字符的顯示,如字體等有直接影響;J2EE服務器層
,大多數服務器都可以對字符編碼進行自定義的配置,例如Tomcat就可以通過web.xml中設置
javaEncoding參數設置字符編碼,默認是UTF-8.
?????? IE也可以設置成總是使用UTF-8編碼來發送請求.應用程序層,每個配置在服務器下的程序都可以
設置自己的編碼方式,這個我目前還沒有用到,以后再學習。
?????? 運行時的轉碼,運行時期,應用程序很可能需要與外部系統進行交互,例如對數據庫進行讀寫
,對外部文件進行讀寫.在這些情況下,應用程序免不了要和外部系統進行數據交換。那么對于中文字
符, 數據出入口的編碼方式就顯得特別重要了。一般外部系統都有自己的字符編碼方式,我的例子中
配置的MySQL就是使用的UTF-8編碼。JSP頁面通過設定”charset=gb2312”,
????? 使用gb2312編碼,在它與數據庫交互的時候就需要進行顯式的轉碼才能正確處理中文字符。
posted @
2007-07-22 02:19 jadmin 閱讀(63) |
評論 (0) |
編輯 收藏
一、安裝篇
jspSmartUpload是由www.jspsmart.com網站開發的一個可免費使用的全功能的文件上傳下載組件,適于嵌入執行上傳下載操作的JSP文件中。該組件有以下幾個特點:
1、使用簡單。在JSP文件中僅僅書寫三五行JAVA代碼就可以搞定文件的上傳或下載,方便。
2、能全程控制上傳。利用jspSmartUpload組件提供的對象及其操作方法,可以獲得全部上傳文件的信息(包括文件名,大小,類型,擴展名,文件數據等),方便存取。
3、能對上傳的文件在大小、類型等方面做出限制。如此可以濾掉不符合要求的文件。
4、下載靈活。僅寫兩行代碼,就能把Web服務器變成文件服務器。不管文件在Web服務器的目錄下或在其它任何目錄下,都可以利用jspSmartUpload進行下載。
5、能將文件上傳到數據庫中,也能將數據庫中的數據下載下來。這種功能針對的是MYSQL數據庫,因為不具有通用性,所以本文不準備舉例介紹這種用法。
jspSmartUpload組件可以從www.jspsmart.com網站上自由下載,壓縮包的名字是jspSmartUpload.zip。下載后,用WinZip或WinRAR將其解壓到Tomcat的webapps目錄下(本文以Tomcat服務器為例進行介紹)。解壓后,將webapps/jspsmartupload目錄下的子目錄Web-inf名字改為全大寫的WEB-INF,這樣一改jspSmartUpload類才能使用。因為Tomcat對文件名大小寫敏感,它要求Web應用程序相關的類所在目錄為WEB-INF,且必須是大寫。接著重新啟動Tomcat,這樣就可以在JSP文件中使用jspSmartUpload組件了。
注意,按上述方法安裝后,只有webapps/jspsmartupload目錄下的程序可以使用jspSmartUpload組件,如果想讓Tomcat服務器的所有Web應用程序都能用它,必須做如下工作:
1.進入命令行狀態,將目錄切換到Tomcat的webapps/jspsmartupload/WEB-INF目錄下。
2.運行JAR打包命令:jar cvf jspSmartUpload.jar com
(也可以打開資源管理器,切換到當前目錄,用WinZip將com目錄下的所有文件壓縮成jspSmartUpload.zip,然后將jspSmartUpload.zip換名為jspSmartUpload.jar文件即可。)
3.將jspSmartUpload.jar拷貝到Tomcat的shared/lib目錄下。
二、相關類說明篇
㈠ File類
這個類包裝了一個上傳文件的所有信息。通過它,可以得到上傳文件的文件名、文件大小、擴展名、文件數據等信息。
File類主要提供以下方法:
1、saveAs作用:將文件換名另存。
原型:
public void saveAs(java.lang.String destFilePathName)
或
public void saveAs(java.lang.String destFilePathName, int optionSaveAs)
其中,destFilePathName是另存的文件名,optionSaveAs是另存的選項,該選項有三個值,分別是SAVEAS_PHYSICAL,SAVEAS_VIRTUAL,SAVEAS_AUTO。SAVEAS_PHYSICAL表明以操作系統的根目錄為文件根目錄另存文件,SAVEAS_VIRTUAL表明以Web應用程序的根目錄為文件根目錄另存文件,SAVEAS_AUTO則表示讓組件決定,當Web應用程序的根目錄存在另存文件的目錄時,它會選擇SAVEAS_VIRTUAL,否則會選擇SAVEAS_PHYSICAL。
例如,saveAs("/upload/sample.zip",SAVEAS_PHYSICAL)執行后若Web服務器安裝在C盤,則另存的文件名實際是c:\upload\sample.zip。而saveAs("/upload/sample.zip",SAVEAS_VIRTUAL)執行后若Web應用程序的根目錄是webapps/jspsmartupload,則另存的文件名實際是webapps/jspsmartupload/upload/sample.zip。saveAs("/upload/sample.zip",SAVEAS_AUTO)執行時若Web應用程序根目錄下存在upload目錄,則其效果同saveAs("/upload/sample.zip",SAVEAS_VIRTUAL),否則同saveAs("/upload/sample.zip",SAVEAS_PHYSICAL)。
建議:對于Web程序的開發來說,最好使用SAVEAS_VIRTUAL,以便移植。
2、isMissing
作用:這個方法用于判斷用戶是否選擇了文件,也即對應的表單項是否有值。選擇了文件時,它返回false。未選文件時,它返回true。
原型:public boolean isMissing()
3、getFieldName
作用:取HTML表單中對應于此上傳文件的表單項的名字。
原型:public String getFieldName()
4、getFileName
作用:取文件名(不含目錄信息)
原型:public String getFileName()
5、getFilePathName
作用:取文件全名(帶目錄)
原型:public String getFilePathName
6、getFileExt
作用:取文件擴展名(后綴)
原型:public String getFileExt()
7、getSize
作用:取文件長度(以字節計)
原型:public int getSize()
8、getBinaryData
作用:取文件數據中指定位移處的一個字節,用于檢測文件等處理。
原型:public byte getBinaryData(int index)。其中,index表示位移,其值在0到getSize()-1之間。
㈡ Files類
這個類表示所有上傳文件的集合,通過它可以得到上傳文件的數目、大小等信息。有以下方法:
1、getCount
作用:取得上傳文件的數目。
原型:public int getCount()
2、getFile
作用:取得指定位移處的文件對象File(這是com.jspsmart.upload.File,不是java.io.File,注意區分)。
原型:public File getFile(int index)。其中,index為指定位移,其值在0到getCount()-1之間。
3、getSize
作用:取得上傳文件的總長度,可用于限制一次性上傳的數據量大小。
原型:public long getSize()
4、getCollection
作用:將所有上傳文件對象以Collection的形式返回,以便其它應用程序引用,瀏覽上傳文件信息。
原型:public Collection getCollection()
5、getEnumeration
作用:將所有上傳文件對象以Enumeration(枚舉)的形式返回,以便其它應用程序瀏覽上傳文件信息。
原型:public Enumeration getEnumeration()
㈢ Request類
這個類的功能等同于JSP內置的對象request。只所以提供這個類,是因為對于文件上傳表單,通過request對象無法獲得表單項的值,必須通過jspSmartUpload組件提供的Request對象來獲取。該類提供如下方法:
1、getParameter
作用:獲取指定參數之值。當參數不存在時,返回值為null。
原型:public String getParameter(String name)。其中,name為參數的名字。
2、getParameterValues
作用:當一個參數可以有多個值時,用此方法來取其值。它返回的是一個字符串數組。當參數不存在時,返回值為null。
原型:public String[] getParameterValues(String name)。其中,name為參數的名字。
3、getParameterNames
作用:取得Request對象中所有參數的名字,用于遍歷所有參數。它返回的是一個枚舉型的對象。
原型:public Enumeration getParameterNames()
㈣ SmartUpload類這個類完成上傳下載工作。
A.上傳與下載共用的方法:
只有一個:initialize。
作用:執行上傳下載的初始化工作,必須第一個執行。
原型:有多個,主要使用下面這個:
public final void initialize(javax.servlet.jsp.PageContext pageContext)
其中,pageContext為JSP頁面內置對象(頁面上下文)。
B.上傳文件使用的方法:
1、upload
作用:上傳文件數據。對于上傳操作,第一步執行initialize方法,第二步就要執行這個方法。
原型:public void upload()
2、save
作用:將全部上傳文件保存到指定目錄下,并返回保存的文件個數。
原型:public int save(String destPathName)
和public int save(String destPathName,int option)
其中,destPathName為文件保存目錄,option為保存選項,它有三個值,分別是SAVE_PHYSICAL,SAVE_VIRTUAL和SAVE_AUTO。(同File類的saveAs方法的選項之值類似)SAVE_PHYSICAL指示組件將文件保存到以操作系統根目錄為文件根目錄的目錄下,SAVE_VIRTUAL指示組件將文件保存到以Web應用程序根目錄為文件根目錄的目錄下,而SAVE_AUTO則表示由組件自動選擇。
注:save(destPathName)作用等同于save(destPathName,SAVE_AUTO)。
3、getSize
作用:取上傳文件數據的總長度
原型:public int getSize()
4、getFiles
作用:取全部上傳文件,以Files對象形式返回,可以利用Files類的操作方法來獲得上傳文件的數目等信息。
原型:public Files getFiles()
5、getRequest
作用:取得Request對象,以便由此對象獲得上傳表單參數之值。
原型:public Request getRequest()
6、setAllowedFilesList
作用:設定允許上傳帶有指定擴展名的文件,當上傳過程中有文件名不允許時,組件將拋出異常。
原型:public void setAllowedFilesList(String allowedFilesList)
其中,allowedFilesList為允許上傳的文件擴展名列表,各個擴展名之間以逗號分隔。如果想允許上傳那些沒有擴展名的文件,可以用兩個逗號表示。例如:setAllowedFilesList("doc,txt,,")將允許上傳帶doc和txt擴展名的文件以及沒有擴展名的文件。
7、setDeniedFilesList
作用:用于限制上傳那些帶有指定擴展名的文件。若有文件擴展名被限制,則上傳時組件將拋出異常。
原型:public void setDeniedFilesList(String deniedFilesList)
其中,deniedFilesList為禁止上傳的文件擴展名列表,各個擴展名之間以逗號分隔。如果想禁止上傳那些沒有擴展名的文件,可以用兩個逗號來表示。例如:setDeniedFilesList("exe,bat,,")將禁止上傳帶exe和bat擴展名的文件以及沒有擴展名的文件。
8、setMaxFileSize
作用:設定每個文件允許上傳的最大長度。
原型:public void setMaxFileSize(long maxFileSize)
其中,maxFileSize為為每個文件允許上傳的最大長度,當文件超出此長度時,將不被上傳。
9、setTotalMaxFileSize
作用:設定允許上傳的文件的總長度,用于限制一次性上傳的數據量大小。
原型:public void setTotalMaxFileSize(long totalMaxFileSize)
其中,totalMaxFileSize為允許上傳的文件的總長度。
1、setContentDisposition
作用:將數據追加到MIME文件頭的CONTENT-DISPOSITION域。jspSmartUpload組件會在返回下載的信息時自動填寫MIME文件頭的CONTENT-DISPOSITION域,如果用戶需要添加額外信息,請用此方法。
原型:public void setContentDisposition(String contentDisposition)
其中,contentDisposition為要添加的數據。如果contentDisposition為null,則組件將自動添加"attachment;",以表明將下載的文件作為附件,結果是IE瀏覽器將會提示另存文件,而不是自動打開這個文件(IE瀏覽器一般根據下載的文件擴展名決定執行什么操作,擴展名為doc的將用word程序打開,擴展名為pdf的將用acrobat程序打開,等等)。
2、downloadFile
作用:下載文件。
原型:共有以下三個原型可用,第一個最常用,后兩個用于特殊情況下的文件下載(如更改內容類型,更改另存的文件名)。
① public void downloadFile(String sourceFilePathName)
其中,sourceFilePathName為要下載的文件名(帶目錄的文件全名)
② public void downloadFile(String sourceFilePathName,String contentType)
其中,sourceFilePathName為要下載的文件名(帶目錄的文件全名),contentType為內容類型(MIME格式的文件類型信息,可被瀏覽器識別)。
③ public void downloadFile(String sourceFilePathName,String contentType,String destFileName)
其中,sourceFilePathName為要下載的文件名(帶目錄的文件全名),contentType為內容類型(MIME格式的文件類型信息,可被瀏覽器識別),destFileName為下載后默認的另存文件名。
三、文件上傳篇
㈠ 表單要求
對于上傳文件的FORM表單,有兩個要求:
1、METHOD應用POST,即METHOD="POST"。
2、增加屬性:ENCTYPE="multipart/form-data"
下面是一個用于上傳文件的FORM表單的例子:
<FORM METHOD="POST" ENCTYPE="multipart/form-data"
ACTION="/jspSmartUpload/upload.jsp">
<INPUT TYPE="FILE" NAME="MYFILE">
<INPUT TYPE="SUBMIT">
</FORM>
㈡ 上傳的例子
1、上傳頁面upload.html
本頁面提供表單,讓用戶選擇要上傳的文件,點擊"上傳"按鈕執行上傳操作。
頁面源碼如下:
<!--
???? 文件名:upload.html
作?? 者:縱橫軟件制作中心雨亦奇(zhsoft88@sohu.com)
-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>文件上傳</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
</head>
<body>
<p> </p>
<p align="center">上傳文件選擇</p>
<FORM METHOD="POST" ACTION="jsp/do_upload.jsp"
ENCTYPE="multipart/form-data">
<input type="hidden" name="TEST" value="good">
?? <table width="75%" border="1" align="center">
???? <tr>
?????? <td><div align="center">1、
?????????? <input type="FILE" name="FILE1" size="30">
??? ???? </div></td>
</tr>
???? <tr>
?????? <td><div align="center">2、
?????????? <input type="FILE" name="FILE2" size="30">
???????? </div></td>
???? </tr>
???? <tr>
?????? <td><div align="center">3、
?????????? <input type="FILE" name="FILE3" size="30">
???????? </div></td>
???? </tr>
???? <tr>
?????? <td><div align="center">4、
?????????? <input type="FILE" name="FILE4" size="30">
???????? </div></td>
???? </tr>
???? <tr>
?????? <td><div align="center">
?????????? <input type="submit" name="Submit" value="上傳它!">
???????? </div></td>
???? </tr>
?? </table>
</FORM>
</body>
</html>
2、上傳處理頁面do_upload.jsp
本頁面執行文件上傳操作。頁面源碼中詳細介紹了上傳方法的用法,在此不贅述了。
頁面源碼如下:
<%--
文件名:do_upload.jsp
作?? 者:縱橫軟件制作中心雨亦奇(zhsoft88@sohu.com)
--%>
<%@ page contentType="text/html; charset=gb2312" language="java"
import="java.util.*,com.jspsmart.upload.*" errorPage="" %>
<html>
<head>
<title>文件上傳處理頁面</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
</head>
<body>
<%
// 新建一個SmartUpload對象
SmartUpload su = new SmartUpload();
// 上傳初始化
su.initialize(pageContext);
// 設定上傳限制
// 1.限制每個上傳文件的最大長度。
// su.setMaxFileSize(10000);
// 2.限制總上傳數據的長度。
// su.setTotalMaxFileSize(20000);
// 3.設定允許上傳的文件(通過擴展名限制),僅允許doc,txt文件。
// su.setAllowedFilesList("doc,txt");
// 4.設定禁止上傳的文件(通過擴展名限制),禁止上傳帶有exe,bat,
jsp,htm,html擴展名的文件和沒有擴展名的文件。
// su.setDeniedFilesList("exe,bat,jsp,htm,html,,");
// 上傳文件
su.upload();
// 將上傳文件全部保存到指定目錄
int count = su.save("/upload");
out.println(count+"個文件上傳成功!<br>");
// 利用Request對象獲取參數之值
out.println("TEST="+su.getRequest().getParameter("TEST")
+"<BR><BR>");
// 逐一提取上傳文件信息,同時可保存文件。
for (int i=0;i<su.getFiles().getCount();i++)
{
com.jspsmart.upload.File file = su.getFiles().getFile(i);
// 若文件不存在則繼續
if (file.isMissing()) continue;
// 顯示當前文件信息
out.println("<TABLE BORDER=1>");
out.println("<TR><TD>表單項名(FieldName)</TD><TD>"
+ file.getFieldName() + "</TD></TR>");
out.println("<TR><TD>文件長度(Size)</TD><TD>" +
file.getSize() + "</TD></TR>");
out.println("<TR><TD>文件名(FileName)</TD><TD>"
+ file.getFileName() + "</TD></TR>");
out.println("<TR><TD>文件擴展名(FileExt)</TD><TD>"
+ file.getFileExt() + "</TD></TR>");
out.println("<TR><TD>文件全名(FilePathName)</TD><TD>"
+ file.getFilePathName() + "</TD></TR>");
out.println("</TABLE><BR>");
// 將文件另存
// file.saveAs("/upload/" + myFile.getFileName());
// 另存到以WEB應用程序的根目錄為文件根目錄的目錄下
// file.saveAs("/upload/" + myFile.getFileName(),
su.SAVE_VIRTUAL);
// 另存到操作系統的根目錄為文件根目錄的目錄下
// file.saveAs("c:\\temp\\" + myFile.getFileName(),
su.SAVE_PHYSICAL);
}
%>
</body>
</html>
四、文件下載篇
1、下載鏈接頁面download.html
頁面源碼如下:
<!--
文件名:download.html
作?? 者:縱橫軟件制作中心雨亦奇(zhsoft88@sohu.com)
-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>下載</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
</head>
<body>
<a href="jsp/do_download.jsp">點擊下載</a>
</body>
</html>
2、下載處理頁面do_download.jsp do_download.jsp展示了如何利用jspSmartUpload組件來下載文件,從下面的源碼中就可以看到,下載何其簡單。
源碼如下:
<%@ page contentType="text/html;charset=gb2312"
import="com.jspsmart.upload.*" %><%
// 新建一個SmartUpload對象
SmartUpload su = new SmartUpload();
// 初始化
su.initialize(pageContext);
// 設定contentDisposition為null以禁止瀏覽器自動打開文件,
//保證點擊鏈接后是下載文件。若不設定,則下載的文件擴展名為
//doc時,瀏覽器將自動用word打開它。擴展名為pdf時,
//瀏覽器將用acrobat打開。
su.setContentDisposition(null);
// 下載文件
su.downloadFile("/upload/如何賺取我的第一桶金.doc");
%>
注意,執行下載的頁面,在Java腳本范圍外(即<% ... %>之外),不要包含HTML代碼、空格、回車或換行等字符,有的話將不能正確下載。不信的話,可以在上述源碼中%><%之間加入一個換行符,再下載一下,保證出錯。因為它影響了返回給瀏覽器的數據流,導致解析出錯。
3、如何下載中文文件
jspSmartUpload雖然能下載文件,但對中文支持不足。若下載的文件名中有漢字,則瀏覽器在提示另存的文件名時,顯示的是一堆亂碼,很掃人興。上面的例子就是這樣。(這個問題也是眾多下載組件所存在的問題,很少有人解決,搜索不到相關資料,可嘆!)
為了給jspSmartUpload組件增加下載中文文件的支持,我對該組件進行了研究,發現對返回給瀏覽器的另存文件名進行UTF-8編碼后,瀏覽器便能正確顯示中文名字了。這是一個令人高興的發現。于是我對jspSmartUpload組件的SmartUpload類做了升級處理,增加了toUtf8String這個方法,改動部分源碼如下:
public void downloadFile(String s, String s1, String s2, int i)
throws ServletException, IOException, SmartUploadException
???? {
if(s == null)
???? throw new IllegalArgumentException("File ''" + s +
???? "'' not found (1040).");
if(s.equals(""))
???? throw new IllegalArgumentException("File ''" + s +
???? "'' not found (1040).");
if(!isVirtual(s) && m_denyPhysicalPath)
???? throw new SecurityException("Physical path is
???? denied (1035).");
if(isVirtual(s))
???? s = m_application.getRealPath(s);
java.io.File file = new java.io.File(s);
FileInputStream fileinputstream = new FileInputStream(file);
long l = file.length();
boolean flag = false;
int k = 0;
byte abyte0[] = new byte[i];
if(s1 == null)
???? m_response.setContentType("application/x-msdownload");
else
if(s1.length() == 0)
???? m_response.setContentType("application/x-msdownload");
else
???? m_response.setContentType(s1);
m_response.setContentLength((int)l);
m_contentDisposition = m_contentDisposition != null ?
m_contentDisposition : "attachment;";
if(s2 == null)
???? m_response.setHeader("Content-Disposition",
???? m_contentDisposition + " filename=" +
???? toUtf8String(getFileName(s)));
else
if(s2.length() == 0)
???? m_response.setHeader("Content-Disposition",
???? m_contentDisposition);
else
???? m_response.setHeader("Content-Disposition",
???? m_contentDisposition + " filename=" + toUtf8String(s2));
while((long)k < l)
{
???? int j = fileinputstream.read(abyte0, 0, i);
???? k += j;
???? m_response.getOutputStream().write(abyte0, 0, j);
}
fileinputstream.close();
???? }
???? /**
????? * 將文件名中的漢字轉為UTF8編碼的串,以便下載時能正確顯示另存的文件名.
????? * 縱橫軟件制作中心雨亦奇2003.08.01
????? * @param s 原文件名
????? * @return 重新編碼后的文件名
????? */
???? public static String toUtf8String(String s) {
StringBuffer sb = new StringBuffer();
for (int i=0;i<s.length();i++) {
???? char c = s.charAt(i);
???? if (c >= 0 && c <= 255) {
sb.append(c);
???? } else {
byte[] b;
try {
???? b = Character.toString(c).getBytes("utf-8");
} catch (Exception ex) {
???? System.out.println(ex);
???? b = new byte[0];
}
for (int j = 0; j < b.length; j++) {
int k = b[j];
???? if (k < 0) k += 256;
???? sb.append("%" + Integer.toHexString(k).
???? toUpperCase());
}
???? }
}
return sb.toString();
???? }
注意源碼中粗體部分,原jspSmartUpload組件對返回的文件未作任何處理,現在做了編碼的轉換工作,將文件名轉換為UTF-8形式的編碼形式。UTF-8編碼對英文未作任何處理,對中文則需要轉換為%XX的形式。toUtf8String方法中,直接利用Java語言提供的編碼轉換方法獲得漢字字符的UTF-8編碼,之后將其轉換為%XX的形式。
將源碼編譯后打包成jspSmartUpload.jar,拷貝到Tomcat的shared/lib目錄下(可為所有WEB應用程序所共享),然后重啟Tomcat服務器就可以正常下載含有中文名字的文件了。另,toUtf8String方法也可用于轉換含有中文的超級鏈接,以保證鏈接的有效,因為有的WEB服務器不支持中文鏈接。
小結:jspSmartUpload組件是應用JSP進行B/S程序開發過程中經常使用的上傳下載組件,它使用簡單,方便。現在我又為其加上了下載中文名字的文件的支持,真個是如虎添翼,必將贏得更多開發者的青睞。
posted @
2007-07-17 16:06 jadmin 閱讀(66) |
評論 (0) |
編輯 收藏
要servlet里面支持中文的方法:
在dopost或者doget的第一句加上:
request.setCharacterEncoding("GB2312");
response.setCharacterEncoding("GB2312");
在jsp里面就把
<%@ page contentType="text/html; charset=gb2312" language="java" import="java.sql.*" errorPage="" %>
里設置成charset=gb2312
如果這樣還不行,就只有在取出中文后(getParameter)強制轉換了:
String str=new String(request.getParameter("text").getBytes("ISO-8859-1"),"GB2312");
很不錯的方法,因為在java里面,亂碼是個大問題,這些一定要銘記!
posted @
2007-07-17 16:02 jadmin 閱讀(79) |
評論 (0) |
編輯 收藏
//用命令行參數
import java.io.*;
public class AddArgs
{
??? public static void main(String args[]) throws IOException
????? {
??????? int sum;
??????? try
???????? {
??????????? sum = Integer.parseInt(args[0])+Integer.parseInt(args[1]);??
??????????? System.out.println("兩參數的和是:"+sum);???
???????? }
??????? catch (Exception e)
???????? {??
??????????? System.out.println("參數出現錯誤!");
???????? }
????
????? }
}
=========================================================
//用system.in
import java.io.*;
public class AddInput
{
??? public static void main(String args[]) throws IOException
????? {
??????? BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
??????? int x=0,y=0;
??????? try{
????????? System.out.println("請輸入第一個整數:");
????????? x=Integer.parseInt(br.readLine());
????????? System.out.println("請輸入第二個整數:");
????????? y=Integer.parseInt(br.readLine());
????????? System.out.println("它們的和是:"+(x+y));????????????
??????? }
??????? catch (Exception e)
??????? {
????????? System.out.println("輸入有錯誤,請重新運行!");
???????? }
????? }
}
=========================================================
//用scanner
import java.io.*;
import java.util.*;
public class AddScanner
{
??? public static void main(String args[]) throws IOException
??? {
??????? Scanner sc=new Scanner(System.in);
??????? int x=0,y=0;
??????? try
??????? {
????????? System.out.println("請輸入第一個整數:");
????????? x=sc.nextInt();
????????? System.out.println("請輸入第二個整數:");
????????? y=sc.nextInt();
????????? System.out.println("它們的和是:"+(x+y));????????????
??????? }
??????? catch (Exception e)
??????? {
????????? System.out.println("輸入有錯誤,請重新運行!");
??????? }
??? }
}
posted @
2007-07-17 00:03 jadmin 閱讀(112) |
評論 (0) |
編輯 收藏
輸入流FileInputStream和輸出流 FileOutputStream,實現的是對磁盤文件的順序讀寫,而且讀寫要分別創建不同對象。相比之下RandomAccessFile類則可對文件實現隨機讀寫操作。
RandomAccessFile對象的文件位置指針遵循下面的規律:
·新建RandomAccessFile對象的文件位置指針位于文件的開頭處;
·每次讀寫操作之后,文件位置的指針都相應后移到讀寫的字節數;
·可以通過getFilePointer方法來獲得文件位置指針的位置,通過seek方法來設置文件指針的位置。
RandomAccessFile例子:
package net;
import java.io.*;
class RandomAccessFileDemo
{
????public static void main(String args[]) throws IOException
???? {
????????//以讀和寫的方式創建RandomAccessFile對象
???????? RandomAccessFile f=new RandomAccessFile("myfile","rw");
???????? System.out.println("File length:"+(f.length())+"B");
???????? System.out.println("File Pointer Position:"+f.getFilePointer());
???????//下面從文件末尾處開始寫數據
??????? f.seek(f.length());
??????? f.writeBoolean(true);
??????? f.writeBoolean(false);
??????? f.writeChar('a');
??????? f.writeChars("Hello!!");
??????? System.out.println("File length:"+(f.length())+"B");
???????//下面從文件起始處開始讀數據
??????? f.seek(0);
??????? System.out.println("kkk::"+f.readBoolean());
??????? System.out.println("kkk::"+f.readBoolean());
???????while(f.getFilePointer()<f.length())
??????? {
??????????? System.out.println(f.readLine());
??????? }
??????? f.close();
???? }
}
posted @
2007-07-16 22:53 jadmin 閱讀(92) |
評論 (0) |
編輯 收藏
??? 最近經常有人問及在上網時,被惡意網站修改注冊表的問題,我整理了幾種常見的問題及解決辦法,供大家參考,希望對大家有所幫助。
???? 1.修改IE的標題欄和IE默認連接首頁:HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Internet Explorer\\Main HKEY_CURRENT_USER\\Software\\Microsoft\\Internet Explorer\\Main在注冊表中找到以上兩處主鍵,將其下的“Window Title”主鍵改為“IE瀏覽器”等你喜歡的名字,并關閉所有打開的IE瀏覽器窗口再重新打開就能看到效果。找到串值“Start Page”, 改為自己喜歡的網址即可。
???? 重啟以后又會變成了別人的網址的解決辦法:HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows\\Current Version\\Run主鍵,然后將其下的registry.exe子鍵刪除,然后刪除自運行程序c:\\Program Files\\registry.exe,最后從IE選項中重新設置起始頁就好了。
???? 改回IE的默認頁:HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Internet Explorer\\ Main\\Default_Page_URL“Default_Page_URL”這個子鍵的鍵值即起始頁的默認頁。
???? 2.修改IE的首頁:開始,運行,鍵入msconfig點擊“確定”,在彈出的窗口中切換到“啟動”選項卡,禁用可疑程序啟動項。
???? 3. 系統啟動時彈出對話框,點確定才能進去:方法(1):HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows\\CurrentVersion\\Winlogon在注冊表中找到此主鍵,“LegalNoticeCaption”是提示框的標題,“LegalNoticeText”是提示框的文本內容。刪除這兩個字符串即可。
???? 方法(2):對win2000或winxp:點擊“安全與多用戶”,再點擊左上角的“+”切換窗口后,清除“啟動時要顯示的標題”和“啟動時要顯示的信息”兩項內容即可。
???? 方法(3):看看run.
???? 4.修改IE鼠標右鍵菜單里顯示網頁廣告:HKEY_CURRENT_USER\\Software\\Microsoft\\Internet Explorer\\MenuExt
???? 5. IE首頁解鎖:[HKEY_CURRENT_USER\\Software\\Policies\\Microsoft\\Internet Explorer\\Control Panel], 一般此鍵是不存在的, 只存在[HKEY_CURRENT_USER\\Software\\Policies\\Microsoft], 所以后面一截要自己建立, 主鍵建立完后在Control Panel鍵下新建一個DWORD值數據, 鍵名為HOMEPAGE(不分大小寫), 鍵值為0. 此時再打開IE屬性時可以發現它改首頁設置的部分已經可用了。
???? IE設置項解鎖:[HKEY_CURRENT_USER\\Software\\Policies\\Microsoft\\Internet Explorer\\Control Pan el]"Settings"=dword:1 [HKEY_CURRENT_USER\\Software\\Policies\\Microsoft\\Internet Explorer\\Control Pan el]"Links"=dword:1 [HKEY_CURRENT_USER\\Software\\Policies\\Microsoft\\Internet Explorer\\Control Pan el]"SecAddSites"=dword:1將上面這些DWORD值改為“0”即可恢復功能。
???? IE的默認首頁灰色按扭不可選:HKEY_USERS\\.DEFAULT\\Software\\Policies\\Microsoft\\Internet Explorer\\Control Pan下的DWORD值“homepage”的鍵值修改為“0” “即可恢復功能。
???? 6. 去掉注冊表編輯器被鎖定:這是因為KEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System下的DWORD值“DisableRegistryTools”被修改為“1”的緣故,將其鍵值恢復為“0”即可恢復注冊表的使用。
???? win2000系統:Windows Registry Editor Version 5.00 [Hkey_current_user\\Software\\microsoft\\windows\\currentversion\\Policies\\system] "DisableRegistryTools"=dword:00000000 win98/me系統:REGEDIT4
face=Verdana>???? [HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System] "DisableRegistryTools"=dword:00000000將以上代碼copy到記事本中, 取一個任意名字的。reg文件,比如recover.reg,雙擊運行可以解除你的鎖定狀態。注意:“REGEDIT4”一定要大寫,并且它的后面一定要空一行,還有,“REGEDIT4”中的“4”和“T”之間一定不能有空格,否則將前功盡棄!
??? 7. IE默認搜索引擎被修改:HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Internet Explorer\\Search\\CustomizeSearch HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Internet Explorer\\Search\\SearchAssistant
???? 8. 查看源文件“菜單被禁用:惡意網頁修改了注冊表,具體的位置為:(1)在注冊表HKEY_CURRENT_USER\\Software\\Policies\\Microsoft\\Internet Explorer下建立子鍵”Restrictions“,然后在”Restrictions“下面建立兩DWORD值:”NoViewSource“和”NoBrowserContextMenu“,并為這兩個DWORD值賦值為”1“。
???? (2)在注冊表 HKEY_USERS\\.DEFAULT\\Software\\Policies\\Microsoft\\InternetExplorer\\Restrictions下,將兩個DWORD值:“NoViewSource”和“NoBrowserContextMenu”的鍵值都改為了“1”。第2點中提到的注冊表其實相當于第1點中提到的注冊表的分支,修改第1點中所說的注冊表鍵值,第2點中注冊表鍵值隨之改變。 具體解決辦法為:將以下內容另存為后綴名為reg的注冊表文件,比方說unlock.reg,雙擊unlock.reg導入注冊表,不用重啟電腦 ,重新運行IE就會發現IE的功能恢復正常了。
???? REGEDIT4
???? [HKEY_CURRENT_USER\\Software\\Policies\\Microsoft\\Internet Explorer \\Restrictions]“NoViewSource”=dword:00000000 "NoBrowserContextMenu"=dword:00000000 [HKEY_USERS\\.DEFAULT\\Software\\Policies\\Microsoft\\Internet Explorer \\Restrictions]“NoViewSource”=dword:00000000“NoBrowserContextMenu”=dword:00000000
???? 要特別注意的是,在你編制的注冊表文件unlock.reg中,“REGEDIT4”一定要大寫,并且它的后面一定要空一行,還有,“REGEDIT4”中的“4”和“T”之間一定不能有空格,否則將前功盡棄!許多朋友寫注冊表文件之所以不成功,就是因為沒有注意到上面所說的內容,這回該注意點嘍。請注意如果你是Win2000或WinXP用戶,請將 “REGEDIT4”改為Windows Registry Editor Version 5.00.
???? ★ 可以在IE中做一些設置以便永遠不進惡意站點:
???? 打開IE,點擊“工具”→“Internet選項”→“內容”→“分級審查”,點“啟用 ”按鈕,會調出“分級審查”對話框,然后點擊“許可站點”標簽,輸入不想去的網站網址,如輸入:http://***.****.com,按“從不”按鈕,再點擊“確定”即大功告成!
???? 9. IE不能打開新窗口的解決辦法:(1.)點擊“開始”→“運行”,在彈出的“運行”對話框中輸入“regsvr32 actxprxy.dll”(注意輸入時沒有引號),然后點擊“確定”按鈕,接著會出現一個信息對話框“DllRegisterServer in actxprxy.dll succeeded”;在該對話框中點“確定”按鈕;(2.)再次點擊“開始”→“運行”,在彈出的“運行”對話框中輸入“regsvr32 shdocvw.dll”(注意輸入時沒有引號),然后點擊“確定”按鈕,接著會出現一個信息對話框“DllRegisterServer in shdocvw.dll succeeded”,在該對話框中點“確定”按鈕;(3.)重新啟動Windows,
???? 10. 右鍵功能失效:HKEY_CURRENT_USER\Software\Policies\Microsoft\Internet Explorer\Restrictions,將其DWORD值"NoBrowserContextMenu"的值改為0.
???? 11. 篡改地址欄文字:解決辦法:1.地址欄下的文字。在HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\ToolBar下找到鍵值LinksFolderName,將其中的內容刪去即可。
???? 2.地址欄中無用的地址。在HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\TypeURLs中刪除無用的鍵值即可。
???? 12. IE窗口定時彈出:點擊"開始-運行-輸入msconfig",選擇"啟動",把里面后綴為hta的都勾掉,重啟。
???? 13. 修改IE工具欄:對工具欄按鈕點右鍵選“自定義”,在“當前工具欄按鈕”下拉框中選定不需要的按鈕后點擊“刪除”即可。
???? 要去掉多余的地址列表:[HKEY_CURRENT_USERSoftwareWicrosoftInternet ExplorerTypeURLs]主鍵,將右部窗口中“url1”、“url2”等鍵值名全部刪除即可。
???? 要修復鏈接欄標題,首先展開[HKEY_CURRENT_USERSoftwareWicrosoftInternet ExplorerToolbar]主鍵,在右部窗口中對鍵值名“LinksFolderName”雙擊,修改其鍵值為欲顯示的信息,或直接將該鍵值名刪除,鏈接欄的標題將恢復為默認的“鏈接”字樣。
???? 恢復Internet選項卡:在“HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer”下在右邊的窗口中找到一個二進制值“NoFolderOptions”,并設值為“00 00 00 00”。
???? 桌面上的圖標全部消失:HKEY_CURRENT_USER\\ Software\\Microsoft\\Windows\\ CurrentVersion\\Policies\\Explorer,找到“NoDesktop”值項,右鍵單擊它,選擇“修改”(或者干脆刪除也可以),把它的值改為0,然后重新啟動電腦。
posted @
2007-07-12 03:45 jadmin 閱讀(52) |
評論 (0) |
編輯 收藏
這只是個windows系統下不讓人注意的操作,有不少朋友為此摸不著頭腦,所以今天整理下給大家參考參考。呵呵
IE會記錄你上次關閉IE時候的設置.將IE最大化后關閉(關閉所有窗口),再打開就是最大化的了。
或者 在IE的快捷方式(注意!必須是快捷方式!!)上單擊鼠標右鍵,打開屬性,在彈出的窗口中有運行方式這一欄,選擇最大化,然后確定就可以了。
怎么樣?如果還是不行的話,你就用鼠標把窗口拖成最大,然后再關點IE,即重新啟動IE。就可以了
posted @
2007-07-03 13:02 jadmin 閱讀(75) |
評論 (0) |
編輯 收藏
??????? RoR是Ruby on Rails的縮寫。Ruby on Rails是一個用于編寫網絡應用程序的框架,它基于計算機軟件語言Ruby,給程序開發人員提供強大的框架支持。Ruby on Rails包括兩部分內容:Ruby語言和Rails框架。
什么是Ruby?
????? Ruby語言是一種動態語言,它與Python、Smalltalk和Perl這3種編程語言有些類似。Ruby語言起源于日本,它的研發者是日本人松本行弘(Matsumoto Yukihiro)。松本行弘在1993年開始著手Ruby語言的研發工作,他開發Ruby語言的初衷是為了提高編程的效率。1995年12月Matz推出了Ruby的第一個版本Ruby 0.95。
Ruby語言的主要特點如下。
1.純的面向對象語言
在Ruby中,一切皆是對象。下面舉一個例子來更直觀地說明Ruby語言的這一特點。
在Java中,求一個數的絕對值的代碼如下。
int c = Math.abs(-20);
而在Ruby語言中,一切皆是對象,也就是說“-20”這個數也是一個對象,因此,求一個數絕對值的Ruby代碼形式如下。
c = -20.abs
這樣的代碼編寫方式是不是更形象一些呢?
2.解釋型腳本語言
Ruby語言是解釋型腳本語言,它既有腳本語言強大的字符串處理能力和正則表達式,又不失解釋型語言的動態性。一方面,在最初設計Ruby語言時,Ruby的研發者松本行弘考慮到文字處理方面的需要,他借鑒了Perl語言在文字處理方面的成功經驗。另一方面,松本行弘將Ruby語言設定為一種解釋型語言,Ruby的動態性使得由Ruby語言編寫的程序不需要事先編譯即可直接運行,這為程序的調試帶來了方便。同時,這一特點可以實現開發過程中的快速反饋。
3.其他特點
(1)動態載入。可以在運行時候重定義自己,類也可以在運行時繼承或取消繼承。
(2)自動內存管理機制。
(3)多精度整數。
(4)迭代器和閉包。
(5)開源項目。有大量活躍的社區支持Ruby語言。
什么是Rails?
??????? 雖然Ruby語言有很多優點,但是一直以來,其流行的范圍也僅限于日本。直到2004年,Ruby才逐漸被世界上其他地區的人們所認識,那么是什么讓Ruby語言走向世界的呢?是Rails。
????? Rails框架首次提出是在2004年7月,它的研發者是26歲的丹麥人David Heinemeier Hansson。不同于已有復雜的Web 開發框架,Rails是一個更符合實際需要而且更高效的Web開發框架。Rails結合了PHP體系的優點(快速開發)和Java體系的優點(程序規整),因此,Rails在其提出后不長的時間里就受到了業內廣泛的關注。
Rails框架主要有如下的6大特點。
1.全棧式的MVC框架
????? Rails是一個全棧式的MVC框架,換句話說,通過Rails可以實現MVC模式中的各個層次,并使它們無縫地協同運轉起來。
????? 在實際開發一個MVC模式的Web應用項目時,如果使用Java開發,需要用到Struts(Model層)、Hibernate(Controller層)和Spring(View層)3個框架,而且需要額外整合3個框架開發出的內容。而使用Ruby語言開發相同的項目時,只需要用到Rails框架就可以完成。
2.約定優于配置
????? 為了說明各個對象之間的關聯關系,一般的Web應用開發框架往往采用寫入XML配置文件的方法。這種方式雖然可以解決一些問題,但是卻帶來了管理上的混亂。
????? Rails對此的態度是約定優于配置,這意味著在Rails中不會出現XML配置文件。Rails使用Web應用多年來積累的各種常見約定(更具體地說是命名規則)來代替XML配置文件,而在Rails內部的映射與發現機制根據這些約定可以實現對象之間的關聯。在第1章中,通過Rails的映射與發現機制實現了數據表與Ruby對象之間的關聯。
3.更少的代碼
????? 使用約定來代替XML配置文件說明Rails本身完成了大量的底層工作,這意味著使用更少的代碼來實現應用程序是極有可能的。此外,代碼量的縮減也減小了出現bug的可能性,降低了維護程序和升級程序的難度。
4.生成器
????? Rails使用的實時映射技術和元編程技術,免去了開發人員在開發過程中編寫大量樣板文件代碼的煩惱。在少數需要使用樣板文件代碼的時候,開發人員可以通過Rails內建的生成器腳本實時創建,而不再是通過手工編寫。Rails的這個特點可以使開發人員更專注于系統的邏輯結構,而不必為一些瑣碎的細節所煩擾。
5.零周轉時間
????? 對已有的Web應用系統進行修改后,其一般需要經過配置、編譯、發布、重新設置、測試等一系列步驟才能投入使用,這明顯浪費了許多時間。而使用Rails開發Web應用系統,可以通過瀏覽器即時查看程序運行結果,從而節約了大量的時間。
6.支架系統
????? Rails的支架系統可以自動為任何相關的數據庫表創建一套包含標準CRUD操作和前臺視圖的系統。通過支架系統,開發人員可以方便快捷地操縱數據庫中的數據表。此外,Rails也允許開發人員使用自己設計的代碼或視圖來替換自動生成的代碼和視圖。
????? 目前,Rails的最新版本是2005年12月13日發布的v1.0.0。從RoR正式提出到v1.0.0的發布,RoR在一年多的時間里受到了業內人士的廣泛關注。RoR受到廣泛關注主要有如下兩個原因:首先,RoR的開發效率高(部署容易)、功能豐富(支持Ajax等流行應用),有消息稱對于相同的Web開發項目,使用RoR開發比使用Java體系架構開發快5~10倍;此外,令人不可思議的高性能是其受到關注的另一個重要原因,根據CSDN上轉載的新聞稱使用RoR開發出來的項目性能,比基于Struts+Hibernate+Spring的Java應用還要高15%~20%。
????? RoR當前遇到的主要問題是使用RoR搭建的大型商業應用還很少,究其原因可以概括為兩點:第一,從開發能力的角度,RoR是一個基于Ruby語言的輕型Web開發框架,很多開發者對其是否適合大型應用難以把握。第二,本身使用RoR開發的大型商業應用較少,使得后來者持觀望態度。
????? 綜合分析來看,RoR的發展前景還是很光明的。RoR在短時間內取得了巨大的成就,它打破了Web開發領域的固有觀念,方便快捷的開發方式使其被廣泛接受。而事實上,現在已有幾家跨國公司正在使用RoR開發自己的Web應用程序,并且有多家大型公司在考慮使用RoR進行Web應用開發。
ROR開發環境的配置見如下鏈接
http://hi.baidu.com/jadmin/blog/item/a0d7f2ef456aca34acafd584.html
posted @
2007-07-03 12:56 jadmin 閱讀(93) |
評論 (0) |
編輯 收藏
一:理解多線程
多線程是這樣一種機制,它允許在程序中并發執行多個指令流,每個指令流都稱為一個線程,彼此間互相獨立。
線程又稱為輕量級進程,它和進程一樣擁有獨立的執行控制,由操作系統負責調度,區別在于線程沒有獨立的存儲空間,而是和所屬進程中的其它線程共享一個存儲空間,這使得線程間的通信遠較進程簡單。
多個線程的執行是并發的,也就是在邏輯上“同時”,而不管是否是物理上的“同時”。如果系統只有一個CPU,那么真正的“同時”是不可能的,但是由于CPU的速度非常快,用戶感覺不到其中的區別,因此我們也不用關心它,只需要設想各個線程是同時執行即可。
多線程和傳統的單線程在程序設計上最大的區別在于,由于各個線程的控制流彼此獨立,使得各個線程之間的代碼是亂序執行的,由此帶來的線程調度,同步等問題,將在以后探討。
二:在Java中實現多線程
我們不妨設想,為了創建一個新的線程,我們需要做些什么?很顯然,我們必須指明這個線程所要執行的代碼,而這就是在Java中實現多線程我們所需要做的一切!
真是神奇!Java是如何做到這一點的?通過類!作為一個完全面向對象的語言,Java提供了類 java.lang.Thread 來方便多線程編程,這個類提供了大量的方法來方便我們控制自己的各個線程,我們以后的討論都將圍繞這個類進行。
那么如何提供給 Java 我們要線程執行的代碼呢?讓我們來看一看 Thread 類。Thread 類最重要的方法是 run() ,它為Thread 類的方法 start() 所調用,提供我們的線程所要執行的代碼。為了指定我們自己的代碼,只需要覆蓋它!
方法一:繼承 Thread 類,覆蓋方法 run()
我們在創建的 Thread 類的子類中重寫 run() ,加入線程所要執行的代碼即可。
下面是一個例子:
public class MyThread extends Thread {
int count= 1, number;
public MyThread(int num) {
number = num;
System.out.println("創建線程 " + number);
}
public void run() {
while(true) {
System.out.println("線程 " + number + ":計數 " + count);
if(++count== 6) return;
}
}
public static void main(String args[]) {
for(int i = 0; i < 5; i++) new MyThread(i+1).start();
}
}
這種方法簡單明了,符合大家的習慣,但是,它也有一個很大的缺點,那就是如果我們的類已經從一個類繼承(如小程序必須繼承自 Applet 類),則無法再繼承 Thread 類,這時如果我們又不想建立一個新的類,應該怎么辦呢?
我們不妨來探索一種新的方法:我們不創建 Thread 類的子類,而是直接使用它,那么我們只能將我們的方法作為參數傳遞給 Thread 類的實例,有點類似回調函數。但是 Java 沒有指針,我們只能傳遞一個包含這個方法的類的實例。那么如何限制這個類必須包含這一方法呢?當然是使用接口!(雖然抽象類也可滿足,但是需要繼承,而我們之所以要采用這種新方法,不就是為了避免繼承帶來的限制嗎?)
Java 提供了接口 java.lang.Runnable 來支持這種方法。
方法二:實現 Runnable 接口
Runnable 接口只有一個方法 run(),我們聲明自己的類實現 Runnable 接口并提供這一方法,將我們的線程代碼寫入其中,就完成了這一部分的任務。
但是 Runnable 接口并沒有任何對線程的支持,我們還必須創建 Thread 類的實例,這一點通過 Thread 類的構造函數
public Thread(Runnable target);來實現。
下面是一個例子:
public class MyThread implements Runnable {
int count= 1, number;
public MyThread(int num) {
number = num;
System.out.println("創建線程 " + number);
}
public void run() {
while(true) {
System.out.println("線程 " + number + ":計數 " + count);
if(++count== 6) return;
}
}
public static void main(String args[]) {
for(int i = 0; i < 5; i++) new Thread(new MyThread(i+1)).start();
}
}
嚴格地說,創建 Thread 子類的實例也是可行的,但是必須注意的是,該子類必須沒有覆蓋 Thread 類的 run 方法,否則該線程執行的將是子類的 run 方法,而不是我
們用以實現Runnable 接口的類的 run 方法,對此大家不妨試驗一下。
使用 Runnable 接口來實現多線程使得我們能夠在一個類中包容所有的代碼,有利于封裝,它的缺點在于,我們只能使用一套代碼,若想創建多個線程并使各個線程執行不同的代碼,則仍必須額外創建類,如果這樣的話,在大多數情況下也許還不如直接用多個類分別繼承 Thread 來得緊湊。
綜上所述,兩種方法各有千秋,大家可以靈活運用。
下面讓我們一起來研究一下多線程使用中的一些問題。
三:線程的四種狀態
1. 新狀態:線程已被創建但尚未執行(start() 尚未被調用)。
2. 可執行狀態:線程可以執行,雖然不一定正在執行。CPU 時間隨時可能被分配給該線程,從而使得它執行。
3. 死亡狀態:正常情況下 run() 返回使得線程死亡。調用 stop()或 destroy() 亦有同樣效果,但是不被推薦,前者會產生異常,后者是強制終止,不會釋放鎖。
4. 阻塞狀態:線程不會被分配 CPU 時間,無法執行。
四:線程的優先級
線程的優先級代表該線程的重要程度,當有多個線程同時處于可執行狀態并等待獲得 CPU 時間時,線程調度系統根據各個線程的優先級來決定給誰分配 CPU 時間,優先級高的線程有更大的機會獲得 CPU 時間,優先級低的線程也不是沒有機會,只是機會要小一些罷了。
你可以調用 Thread 類的方法 getPriority() 和 setPriority()來存取線程的優先級,線程的優先級界于1(MIN_PRIORITY)和10(MAX_PRIORITY)之間,缺省是5(NORM_PRIORITY)。
五:線程的同步
由于同一進程的多個線程共享同一片存儲空間,在帶來方便的同時,也帶來了訪問沖突這個嚴重的問題。Java語言提供了專門機制以解決這種沖突,有效避免了同一個數據對象被多個線程同時訪問。
由于我們可以通過 private 關鍵字來保證數據對象只能被方法訪問,所以我們只需針對方法提出一套機制,這套機制就是 synchronized 關鍵字,它包括兩種用法:synchronized 方法和 synchronized 塊。
1. synchronized 方法:通過在方法聲明中加入 synchronized關鍵字來聲明 synchronized 方法。如:
public synchronized void accessVal(int newVal);
synchronized 方法控制對類成員變量的訪問:每個類實例對應一把鎖,每個 synchronized 方法都必須獲得調用該方法的類實例的鎖方能執行,否則所屬線程阻塞,方
法一旦執行,就獨占該鎖,直到從該方法返回時才將鎖釋放,此后被阻塞的線程方能獲得該鎖,重新進入可執行狀態。這種機制確保了同一時刻對于每一個類實例,其所有聲明為 synchronized 的成員函數中至多只有一個處于可執行狀態(因為至多只有一個能夠獲得該類實例對應的鎖),從而有效避免了類成員變量的訪問沖突(只要所有可能訪問類成員變量的方法均被聲明為 synchronized)。
在 Java 中,不光是類實例,每一個類也對應一把鎖,這樣我們也可將類的靜態成員函數聲明為 synchronized ,以控制其對類的靜態成員變量的訪問。
synchronized 方法的缺陷:若將一個大的方法聲明為synchronized 將會大大影響效率,典型地,若將線程類的方法 run() 聲明為 synchronized ,由于在線程的整個生命期內它一直在運行,因此將導致它對本類任何 synchronized 方法的調用都永遠不會成功。當然我們可以通過將訪問類成員變量的代碼放到專門的方法中,將其聲明為 synchronized ,并在主方法中調用來解決這一問題,但是 Java 為我們提供了更好的解決辦法,那就是 synchronized 塊。
2. synchronized 塊:通過 synchronized關鍵字來聲明synchronized 塊。語法如下:
synchronized(syncObject) {
//允許訪問控制的代碼
}
synchronized 塊是這樣一個代碼塊,其中的代碼必須獲得對象 syncObject (如前所述,可以是類實例或類)的鎖方能執行,具體機制同前所述。由于可以針對任意代碼塊,且可任意指定上鎖的對象,故靈活性較高。
六:線程的阻塞
為了解決對共享存儲區的訪問沖突,Java 引入了同步機制,現在讓我們來考察多個線程對共享資源的訪問,顯然同步機制已經不夠了,因為在任意時刻所要求的資源不一定已經準備好了被訪問,反過來,同一時刻準備好了的資源也可能不止一個。為了解決這種情況下的訪問控制問題,Java 引入了對阻塞機制的支持。
阻塞指的是暫停一個線程的執行以等待某個條件發生(如某資源就緒),學過操作系統的同學對它一定已經很熟悉了。Java 提供了大量方法來支持阻塞,下面讓我們逐一分析。
1. sleep() 方法:sleep() 允許 指定以毫秒為單位的一段時間作為參數,它使得線程在指定的時間內進入阻塞狀態,不能得到CPU 時間,指定的時間一過,線程重新進入可執行狀態。
典型地,sleep() 被用在等待某個資源就緒的情形:測試發現條件不滿足后,讓線程阻塞一段時間后重新測試,直到條件滿足為止。
2. suspend() 和 resume() 方法:兩個方法配套使用,suspend()使得線程進入阻塞狀態,并且不會自動恢復,必須其對應的resume() 被調用,才能使得線程重新進入可執行狀態。典型地,suspend() 和 resume() 被用在等待另一個線程產生的結果的情形:測試發現結果還沒有產生后,讓線程阻塞,另一個線程產生了結果后,調用 resume() 使其恢復。
3. yield() 方法:yield() 使得線程放棄當前分得的 CPU 時間,但是不使線程阻塞,即線程仍處于可執行狀態,隨時可能再次分得 CPU 時間。調用 yield() 的效果等價于調度程序認為該線程已執行了足夠的時間從而轉到另一個線程。
4. wait() 和 notify() 方法:兩個方法配套使用,wait() 使得線程進入阻塞狀態,它有兩種形式,一種允許 指定以毫秒為單位的一段時間作為參數,另一種沒有參數,前者當對應的 notify() 被調用或者超出指定時間時線程重新進入可執行狀態,后者則必須對應的 notify() 被調用。
初看起來它們與 suspend() 和 resume() 方法對沒有什么分別,但是事實上它們是截然不同的。區別的核心在于,前面敘述的所有方法,阻塞時都不會釋放占用的鎖(如果占用了的話),而這一對方法則相反。
上述的核心區別導致了一系列的細節上的區別。
首先,前面敘述的所有方法都隸屬于 Thread 類,但是這一對卻直接隸屬于 Object 類,也就是說,所有對象都擁有這一對方法。初看起來這十分不可思議,但是實際上卻是很自然的,因為這一對方法阻塞時要釋放占用的鎖,而鎖是任何對象都具有的,調用任意對象的 wait() 方法導致線程阻塞,并且該對象上的鎖被釋放。而調用 任意對象的notify()方法則導致因調用該對象的 wait() 方法而阻塞的線程中隨機選擇的一個解除阻塞(但要等到獲得鎖后才真正可執行)。
其次,前面敘述的所有方法都可在任何位置調用,但是這一對方法卻必須在 synchronized 方法或塊中調用,理由也很簡單,只有在synchronized 方法或塊中當前線程才占有鎖,才有鎖可以釋放。同樣的道理,調用這一對方法的對象上的鎖必須為當前線程所擁有,這樣才有鎖可以釋放。因此,這一對方法調用必須放置在這樣的 synchronized 方法或塊中,該方法或塊的上鎖對象就是調用這一對方法的對象。若不滿足這一條件,則程序雖然仍能編譯,但在運行時會出現IllegalMonitorStateException 異常。
wait() 和 notify() 方法的上述特性決定了它們經常和synchronized 方法或塊一起使用,將它們和操作系統的進程間通信機制作一個比較就會發現它們的相似性:synchronized方法或塊提供了類似于操作系統原語的功能,它們的執行不會受到多線程機制的干擾,而這一對方法則相當于 block 和wakeup 原語(這一對方法均聲明為 synchronized)。它們的結合使得我們可以實現操作系統上一系列精妙的進程間通信的算法(如信號量算法),并用于解決各種復雜的線程間通信問題。
關于 wait() 和 notify() 方法最后再說明兩點:
第一:調用 notify() 方法導致解除阻塞的線程是從因調用該對象的 wait() 方法而阻塞的線程中隨機選取的,我們無法預料哪一個線程將會被選擇,所以編程時要特別小心,避免因這種不確定性而產生問題。
第二:除了 notify(),還有一個方法 notifyAll() 也可起到類似作用,唯一的區別在于,調用 notifyAll() 方法將把因調用該對象的 wait() 方法而阻塞的所有線程一次性全部解除阻塞。當然,只有獲得鎖的那一個線程才能進入可執行狀態。
談到阻塞,就不能不談一談死鎖,略一分析就能發現,suspend() 方法和不指定超時期限的 wait() 方法的調用都可能產生死鎖。遺憾的是,Java 并不在語言級別上支持死鎖的避免,我們在編程中必須小心地避免死鎖。
以上我們對 Java 中實現線程阻塞的各種方法作了一番分析,我們重點分析了 wait() 和 notify() 方法,因為它們的功能最強大,使用也最靈活,但是這也導致了它們的效率較低,較容易出錯。實際使用中我們應該靈活使用各種方法,以便更好地達到我們的目的。
七:守護線程
守護線程是一類特殊的線程,它和普通線程的區別在于它并不是應用程序的核心部分,當一個應用程序的所有非守護線程終止運行時,即使仍然有守護線程在運行,應用程序也將終止,反之,只要有一個非守護線程在運行,應用程序就不會終止。守護線程一般被用于在后臺為其它線程提供服務。
可以通過調用方法 isDaemon() 來判斷一個線程是否是守護線程,也可以調用方法 setDaemon() 來將一個線程設為守護線程。
八:線程組
線程組是一個 Java 特有的概念,在 Java 中,線程組是類ThreadGroup 的對象,每個線程都隸屬于唯一一個線程組,這個線程組在線程創建時指定并在線程的整個生命期內都不能更改。你可以通過調用包含 ThreadGroup 類型參數的 Thread 類構造函數來指定線程屬的線程組,若沒有指定,則線程缺省地隸屬于名為 system 的系統線程組。
在 Java 中,除了預建的系統線程組外,所有線程組都必須顯式創建。
在 Java 中,除系統線程組外的每個線程組又隸屬于另一個線程組,你可以在創建線程組時指定其所隸屬的線程組,若沒有指定,則缺省地隸屬于系統線程組。這樣,所有線程組組成了一棵以系統線程組為根的樹。
Java 允許我們對一個線程組中的所有線程同時進行操作,比如我們可以通過調用線程組的相應方法來設置其中所有線程的優先級,也可以啟動或阻塞其中的所有線程。
Java 的線程組機制的另一個重要作用是線程安全。線程組機制允許我們通過分組來區分有不同安全特性的線程,對不同組的線程進行不同的處理,還可以通過線程組的分層結構來支持不對等安全措施的采用。Java 的 ThreadGroup 類提供了大量的方法來方便我們對線程組樹中的每一個線程組以及線程組中的每一個線程進行操作。
九:總結
在這一講中,我們一起學習了 Java 多線程編程的方方面面,包括創建線程,以及對多個線程進行調度、管理。我們深刻認識到了多線程編程的復雜性,以及線程切換開銷帶來的多線程程序的低效性,這也促使我們認真地思考一個問題:我們是否需要多線程?何時需要多線程?
多線程的核心在于多個代碼塊并發執行,本質特點在于各代碼塊之間的代碼是亂序執行的。我們的程序是否需要多線程,就是要看這是否也是它的內在特點。
假如我們的程序根本不要求多個代碼塊并發執行,那自然不需要使用多線程;假如我們的程序雖然要求多個代碼塊并發執行,但是卻不要求亂序,則我們完全可以用一個循環來簡單高效地實現,也不需要使用多線程;只有當它完全符合多線程的特點時,多線程機制對線程間通信和線程管理的強大支持才能有用武之地,這時使用多線程才是值得的。
posted @
2007-07-01 03:40 jadmin 閱讀(79) |
評論 (0) |
編輯 收藏