當前位置:
首頁 >
前端技术
> javascript
>内容正文
javascript
JSP中文问题解决方案
生活随笔
收集整理的這篇文章主要介紹了
JSP中文问题解决方案
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
中文問題-技術篇
JSP中文問題解決方案
只需要保持下面幾處地方設置統一,你的JSP就不會有中文問題
1、JSP的charset,
2、你的JSP SERVER編譯JSP是使用的字符集,默認和操作系統是一樣的。你可能需要進行修改
3、你的BEAN編譯時候所采用的字符集,一般用JAVAC編譯,都是和操作系統一樣的,但你可以通過帶參數來改變。如果用其它的編程工具,可以編譯的話,你可能需要修改其默認參數。
4、和數據庫連接時,大多數JDBC驅動程序都可以設置其字符集的,這樣JDBC驅動會自己進行轉換,也不會出現漢字問題。
以jConnect為例,就有這樣一個屬性參數:
CHARSET
Specifies the character set for strings passed through TDS. If you specify a CHARSET, it must match a CHARSET listed in syscharsets.
If null, jConnect uses the server’s default CHARSET.
明白?jdbc-odbc橋也有這樣的參數的(charSet)。 不同的驅動,請參閱文檔。
對于中文處理的常見對策,在網上經常可見的主要是下面2種:
或者:
String Hi="你好";
byte[] tmpbyte=Hi.getBytes("ISO8859_1");
Hi=new String(tmpbyte);
out.print(Hi);
% >
通過簡單總結,示例中的中文處理發生于以下幾個地方:
1 在url附帶中文參數,可以直接讀取。
例如:
2 與數據庫有關的各種sql操作
這里使用的Access沒有發生問題。
3 讀取HTML form表單中遞交的中文值
在jswdk中需要加以編碼,較為簡潔的寫法如:
String name1=new String(request.getParameter("user_id").getBytes("ISO8859_1"));
另外,在jdk1.3的支持下,不需要加入
而在jdk1.2.2下面,即使2種方法同時運用也很不穩定。
而在resin平臺,情況較好。只要在頁面第一行加入:
即可正確處理中文。
如果再加編碼則反而不對。
5 session中包含的中文
在jswdk中,奇怪的是如果從form中讀出的值經過編碼則可正確顯示;但直接賦予中文值則不行。
resin平臺很好,同上。
6 對于對變量賦中文值后正確顯示中文。
例如以下程序:
String Hi="你好";
byte[] tmpbyte=Hi.getBytes("ISO8859_1");
Hi=new String(tmpbyte);
out.print(Hi);
% >
同樣是jswdk1.0.1,以上的表示方法在jdk1.2.2中沒有問題,但在jdk1.3下卻無法顯示。
resin平臺很好,同上,經過測試,只需要在中補上
而不需要也能正確顯示中文。
體會:
jswdk也許只能用于普通開發,穩定性和其它問題可能不如商業軟件。
由于jdk1.3版性能要好于jdk1.2.2很多倍,并且對中文的支持也較好,所以應該加以采用。
作為免費的商業軟件,resin不僅速度快,穩定,自動編譯,可指出出錯行,可在服務器端支持使用javascript等,而且,至少我覺得對中文的支持很好。
當然,如果不必做任何處理即可正確顯示中文將是我們所期待的。
另外,相信在unix/linux/solaris下應該沒有這樣的問題.
一般來說,只要你做到了以上幾點,你的JSP幾乎(根本各人的配置吧)不會再有中文問題了!
JSP/Servlet 中的漢字編碼問題
網上就 JSP/Servlet 中 DBCS 字符編碼問題有許多優秀的文章和討論,本文對它們作一些整理,并結合 IBM WebSphere Application Server 3.5(WAS)的解決方法作一些說明,希望它不是多余的。
內容:
問題的起源
GB2312-80,GBK,GB18030-2000 漢字字符集及 Encoding
中文轉碼時´?´、亂碼的由來
JSP/Servlet 漢字編碼問題及在 WAS 中的解決辦法
結束語
參考文章
1. 問題的起源
每個國家(或區域)都規定了計算機信息交換用的字符編碼集,如美國的擴展 ASCII碼, 中國的 GB2312-80,日本的 JIS 等,作為該國家/區域內信息處理的基礎,有著統一編碼的重要作用。字符編碼集按長度分為 SBCS(單字節字符集),DBCS(雙字節字符集)兩大類。早期的軟件(尤其是操作系統),為了解決本地字符信息的計算機處理,出現了各種本地化版本(L10N),為了區分,引進了 LANG, Codepage 等概念。但是由于各個本地字符集代碼范圍重疊,相互間信息交換困難;軟件各個本地化版本獨立維護成本較高。因此有必要將本地化工作中的共性抽取出來,作一致處理,將特別的本地化處理內容降低到最少。這也就是所謂的國際化(I18N)。各種語言信息被進一步規范為 Locale 信息。處理的底層字符集變成了幾乎包含了所有字形的 Unicode。
現在大部分具有國際化特征的軟件核心字符處理都是以 Unicode 為基礎的,在軟件運行時根據當時的 Locale/Lang/Codepage 設置確定相應的本地字符編碼設置,并依此處理本地字符。在處理過程中需要實現 Unicode 和本地字符集的相互轉換,甚或以 Unicode 為中間的兩個不同本地字符集的相互轉換。這種方式在網絡環境下被進一步延伸,任何網絡兩端的字符信息也需要根據字符集的設置轉換成可接受的內容。
Java 語言內部是用 Unicode 表示字符的,遵守 Unicode V2.0。Java 程序無論是從/往文件系統以字符流讀/寫文件,還是往 URL 連接寫 HTML 信息,或從 URL 連接讀取參數值,都會有字符編碼的轉換。這樣做雖然增加了編程的復雜度,容易引起混淆,但卻是符合國際化的思想的。
從理論上來說,這些根據字符集設置而進行的字符轉換不應該產生太多問題。而事實是由于應用程序的實際運行環境不同,Unicode 和各個本地字符集的補充、完善,以及系統或應用程序實現的不規范,轉碼時出現的問題時時困擾著程序員和用戶。
2. GB2312-80,GBK,GB18030-2000 漢字字符集及 Encoding
其實解決 JAVA 程序中的漢字編碼問題的方法往往很簡單,但理解其背后的原因,定位問題,還需要了解現有的漢字編碼和編碼轉換。
GB2312-80 是在國內計算機漢字信息技術發展初始階段制定的,其中包含了大部分常用的一、二級漢字,和 9 區的符號。該字符集是幾乎所有的中文系統和國際化的軟件都支持的中文字符集,這也是最基本的中文字符集。其編碼范圍是高位0xa1-0xfe,低位也是 0xa1-0xfe;漢字從 0xb0a1 開始,結束于 0xf7fe;
GBK 是 GB2312-80 的擴展,是向上兼容的。它包含了 20902 個漢字,其編碼范圍是 0x8140-0xfefe,剔除高位 0x80 的字位。其所有字符都可以一對一映射到 Unicode 2.0,也就是說 JAVA 實際上提供了 GBK 字符集的支持。這是現階段 Windows 和其它一些中文操作系統的缺省字符集,但并不是所有的國際化軟件都支持該字符集,感覺是他們并不完全知道 GBK 是怎么回事。值得注意的是它不是國家標準,而只是規范。隨著 GB18030-2000國標的發布,它將在不久的將來完成它的歷史使命。
GB18030-2000(GBK2K) 在 GBK 的基礎上進一步擴展了漢字,增加了藏、蒙等少數民族的字形。GBK2K 從根本上解決了字位不夠,字形不足的問題。它有幾個特點,
它并沒有確定所有的字形,只是規定了編碼范圍,留待以后擴充。
編碼是變長的,其二字節部分與 GBK 兼容;四字節部分是擴充的字形、字位,其編碼范圍是首字節 0x81-0xfe、二字節0x30-0x39、三字節 0x81-0xfe、四字節0x30-0x39。
它的推廣是分階段的,首先要求實現的是能夠完全映射到 Unicode 3.0 標準的所有字形。
它是國家標準,是強制性的。
現在還沒有任何一個操作系統或軟件實現了 GBK2K 的支持,這是現階段和將來漢化的工作內容。
Unicode 的介紹......就免了吧。
JAVA 支持的encoding中與中文編程相關的有:(有幾個在JDK文檔中未列出)
ASCII 7-bit, 同 ascii7
ISO8859-1 8-bit, 同 8859_1,ISO-8859-1,ISO_8859-1,latin1...
GB2312-80 同gb2312,gb2312-1980,EUC_CN,euccn,1381,Cp1381, 1383, Cp1383, ISO2022CN,ISO2022CN_GB......
GBK (注意大小寫),同MS936
UTF8 UTF-8
GB18030 (現在只有IBM JDK1.3.?有支持), 同Cp1392,1392
JAVA 語言采用Unicode處理字符. 但從另一個角度來說,在java程序中也可以采用非Unicode的轉碼,重要的是保證程序入口和出口的漢字信息不失真。如完全采用ISO-8859-1來處理漢字也能達到正確的結果。網絡上流行的許多解決方法,都屬于這種類型。為了不致引起混淆,本文不對這種方法作討論。
3. 中文轉碼時´?´、亂碼的由來
兩個方向轉換都有可能得到錯誤的結果:
Unicode-->Byte, 如果目標代碼集不存在對應的代碼,則得到的結果是0x3f.
如:
"u00d6u00ecu00e9u0046u00bbu00f9".getBytes("GBK") 的結果是 "?ìéF?ù", Hex 值是3fa8aca8a6463fa8b4.
仔細看一下上面的結果,你會發現u00ec被轉換為0xa8ac, u00e9被轉換為xa8a6... 它的實際有效位變長了!這是因為GB2312符號區中的一些符號被映射到一些公共的符號編碼,由于這些符號出現在ISO-8859-1或其它一些SBCS字符集中,故它們在Unicode中編碼比較靠前,有一些其有效位只有8位,和漢字的編碼重疊(其實這種映射只是編碼的映射,在顯示時仔細不是一樣的。Unicode 中的符號是單字節寬,漢字中的符號是雙字節寬) . 在Unicodeu00a0--u00ff 之間這樣的符號有20個。了解這個特征非常重要!由此就不難理解為什么JAVA編程中,漢字編碼的錯誤結果中常常會出現一些亂碼(其實是符號字符), 而不全是´?´字符, 就比如上面的例子。
Byte-->Unicode, 如果Byte標識的字符在源代碼集不存在,則得到的結果是0xfffd.
如:
Byte ba[] = {(byte)0x81,(byte)0x40,(byte)0xb0,(byte)0xa1}; new String(ba,"gb2312");
結果是"?啊", hex 值是"ufffdu554a". 0x8140 是GBK字符,按GB2312轉換表沒有對應的值,取ufffd. (請注意:在顯示該uniCode時,因為沒有對應的本地字符,所以也適用上一種情況,顯示為一個"?".)
實際編程中,JSP/Servlet 程序得到錯誤的漢字信息,往往是這兩個過程的疊加,有時甚至是兩個過程疊加后反復作用的結果.
4. JSP/Servlet 漢字編碼問題及在 WAS 中的解決辦法
4.1 常見的 encoding 問題的現象
網上常出現的 JSP/Servlet encoding 問題一般都表現在 browser 或應用程序端,如:
瀏覽器中看到的 Jsp/Servlet 頁面中的漢字怎么都成了 ’?’ ?
瀏覽器中看到的 Servlet 頁面中的漢字怎么都成了亂碼?
JAVA 應用程序界面中的漢字怎么都成了方塊?
Jsp/Servlet 頁面無法顯示 GBK 漢字。
JSP 頁面中內嵌在,等Tag包含的 JAVA code 中的中文成了亂碼,但頁面的其它漢字是對的。
Jsp/Servlet 不能接收 form 提交的漢字。
JSP/Servlet 數據庫讀寫無法獲得正確的內容。
隱藏在這些問題后面的是各種錯誤的字符轉換和處理(除第3個外,是因為 Java font 設置錯誤引起的)。解決類似的字符 encoding 問題,需要了解 Jsp/Servlet 的運行過程,檢查可能出現問題的各個點。
4.2 JSP/Servlet web 編程時的 encoding 問題
運行于Java 應用服務器的 JSP/Servlet 為 Browser 提供 HTML 內容,其過程如下圖所示:
其中有字符編碼轉換的地方有:
JSP 編譯。Java 應用服務器將根據 JVM 的 file.encoding 值讀取 JSP 源文件,編譯生成 JAVA 源文件,再根據 file.encoding 值寫回文件系統。如果當前系統語言支持 GBK,那么這時候不會出現 encoding 問題。如果是英文的系統,如 LANG 是 en_US 的 Linux, AIX 或 Solaris,則要將 JVM 的 file.encoding 值置成 GBK 。系統語言如果是 GB2312,則根據需要,確定要不要設置 file.encoding,將 file.encoding 設為 GBK 可以解決潛在的 GBK 字符亂碼問題
Java 需要被編譯為 .class 才能在 JVM 中執行,這個過程存在與a.同樣的 file.encoding 問題。從這里開始 servlet 和 jsp 的運行就類似了,只不過 Servlet 的編譯不是自動進行的。對于JSP程序, 對產生的JAVA 中間文件的編譯是自動進行的(在程序中直接調用sun.tools.javac.Main類). 因此如果在這一步出現問題的話, 也要檢查encoding和OS的語言環境,或者將內嵌在JSP JAVA Code 中的靜態漢字轉為 Unicode, 要么靜態文本輸出不要放在 JAVA code 中。對于Servlet, javac 編譯時手工指定-encoding 參數就可以了。
Servlet 需要將 HTML 頁面內容轉換為 browser 可接受的 encoding 內容發送出去。依賴于各 JAVA App Server 的實現方式,有的將查詢 Browser 的 accept-charset 和 accept-language 參數或以其它猜的方式確定 encoding 值,有的則不管。因此采用固定encoding 也許是最好的解決方法。對于中文網頁,可在 JSP 或 Servlet 中設置 contentType="text/html; charset=GB2312";如果頁面中有GBK字符,則設置為contentType="text/html; charset=GBK",由于IE 和 Netscape對GBK的支持程度不一樣,作這種設置時需要測試一下。
因為16位 JAVA char在網絡傳送時高8位會被丟棄,也為了確保Servlet頁面中的漢字(包括內嵌的和servlet運行過程中得到的)是期望的內碼,可以用 PrintWriter out=res.getWriter() 取代 ServletOutputStream out=res.getOutputStream(). PrinterWriter 將根據contentType中指定的charset作轉換 (ContentType需在此之前指定!); 也可以用OutputStreamWriter封裝 ServletOutputStream 類并用write(String)輸出漢字字符串。
對于 JSP,JAVA Application Server 應當能夠確保在這個階段將嵌入的漢字正確傳送出去。
這是解釋 URL 字符 encoding 問題。如果通過 get/post 方式從 browser 返回的參數值中包含漢字信息, servlet 將無法得到正確的值。SUN的 J2SDK 中,HttpUtils.parseName 在解析參數時根本沒有考慮 browser 的語言設置,而是將得到的值按 byte 方式解析。這是網上討論得最多的 encoding 問題。因為這是設計缺陷,只能以 bin 方式重新解析得到的字符串;或者以 hack HttpUtils 類的方式解決。參考文章 2 均有介紹,不過最好將其中的中文 encoding GB2312、 CP1381 都改為 GBK,否則遇到 GBK 漢字時,還是會有問題。
Servlet API 2.3 提供一個新的函數 HttpServeletRequest.setCharacterEncoding 用于在調用 request.getParameter(“param_name”) 前指定應用程序希望的 encoding,這將有助于徹底解決這個問題。
4.3 IBM Websphere Application Server 中的解決方法
WebSphere Application Server 對標準的 Servlet API 2.x 作了擴展,提供較好的多語言支持。運行在中文的操作系統中,可以不作任何設置就可以很好地處理漢字。下面的說明只是對WAS是運行在英文的系統中,或者需要有GBK支持時有效。
上述c,d情況,WAS 都要查詢 Browser 的語言設置,在缺省狀況下, zh, zh-cn 等均被映射為 JAVA encoding CP1381(注意: CP1381 只是等同于 GB2312 的一個 codepage,沒有 GBK 支持)。這樣做我想是因為無法確認 Browser 運行的操作系統是支持GB2312, 還是 GBK,所以取其小。但是實際的應用系統還是要求頁面中出現 GBK 漢字,最著名的是朱總理名字中的“?"(rong2 ,0xe946,u9555),所以有時還是需要將 Encoding/Charset 指定為 GBK。當然 WAS 中變更缺省的 encoding 沒有上面說的那么麻煩,針對 a,b,參考文章 5,在 Application Server 的命令行參數中指定 -Dfile.encoding=GBK 即可; 針對 d,在 Application Server 的命令行參數中指定-Ddefault.client.encoding=GBK。如果指定了-Ddefault.client.encoding=GBK,那么c情況下可以不再指定charset。
上面列出的問題中還有一個關于Tag,中的 JAVA 代碼里包含的靜態文本未能正確顯示的問題,在WAS中的解決方法是除了設置正確的file.encoding, 還需要以相同方法設置-Duser.language=zh -Duser.region=CN。這與JAVA locale的設置有關。
4.4 數據庫讀寫時的 encoding 問題
JSP/Servlet 編程中經常出現 encoding 問題的另一個地方是讀寫數據庫中的數據。
流行的關系數據庫系統都支持數據庫 encoding,也就是說在創建數據庫時可以指定它自己的字符集設置,數據庫的數據以指定的編碼形式存儲。當應用程序訪問數據時,在入口和出口處都會有 encoding 轉換。對于中文數據,數據庫字符編碼的設置應當保證數據的完整性. GB2312,GBK,UTF-8 等都是可選的數據庫 encoding;也可以選擇 ISO8859-1 (8-bit),那么應用程序在寫數據之前須將 16Bit 的一個漢字或 Unicode 拆分成兩個 8-bit 的字符,讀數據之后則需將兩個字節合并起來,同時還要判別其中的 SBCS 字符。沒有充分利用數據庫 encoding 的作用,反而增加了編程的復雜度,ISO8859-1不是推薦的數據庫 encoding。JSP/Servlet編程時,可以先用數據庫管理系統提供的管理功能檢查其中的中文數據是否正確。
然后應當注意的是讀出來的數據的 encoding,JAVA 程序中一般得到的是 Unicode。寫數據時則相反。
4.5 定位問題時常用的技巧
定位中文encoding問題通常采用最笨的也是最有效的辦法??在你認為有嫌疑的程序處理后打印字符串的內碼。通過打印字符串的內碼,你可以發現什么時候中文字符被轉換成Unicode,什么時候Unicode被轉回中文內碼,什么時候一個中文字成了兩個 Unicode 字符,什么時候中文字符串被轉成了一串問號,什么時候中文字符串的高位被截掉了……
取用合適的樣本字符串也有助于區分問題的類型。如:”aa啊aa?aa” 等中英相間、GB、GBK特征字符均有的字符串。一般來說,英文字符無論怎么轉換或處理,都不會失真(如果遇到了,可以嘗試著增加連續的英文字母長度)。
5. 結束語
其實 JSP/Servlet 的中文encoding 并沒有想像的那么復雜,雖然定位和解決問題沒有定規,各種運行環境也各不盡然,但后面的原理是一樣的。了解字符集的知識是解決字符問題的基礎。不過,隨著中文字符集的變化,不僅僅是 java 編程,中文信息處理中的問題還是會存在一段時間的。
關于Servlet、Jsp中的多國語言顯示
因為一直不信Java竟會有不能混排顯示多國語言的BUG,這個周末研究了一下Servlet、Jsp的多國語言顯示的問題,也就是Servlet的多字符集問題,由于我對字符集的概念還不是很清晰所以寫出的東西未必是準確的,我是這樣理解Java中的字符集的:在運行時,每個字符串對象中存儲的都是編碼為UNICODE內碼的(我覺得所有的語言中都是有相應編碼的,因為在計算機內部字符串總是用內碼來表示的,只不過一般計算機語言中的字符串編碼時平臺相關的,而Java則采用了平臺無關的UNICODE)。
Java從一個byte流中讀取一個字符串時,將把平臺相關的byte轉變為平臺無關的Unicode字符串。在輸出時Java將把Unicode字符串轉變為平臺相關的byte流,如果某個Unicode字符在某個平臺上不存在,將會輸出一個´?´。舉個例子:在中文Windows中,Java讀出一個"GB2312"編碼的文件(可以是任何流)到內存中構造字符串對象,將會把GB2312編碼的文字轉變為Unicode編碼的字符串,如果把這個字符串輸出又將會把Unicode字符串轉化為GB2312的byte流或數組:"中文測試"----->"u4e2du6587u6d4bu8bd5"----->"中文測試"。
如下例程:
byte[] bytes = new byte[]{(byte)0xd6, (byte)0xd0, (byte)0xce, (byte)0xc4, (byte)0xb2, (byte)0xe2, (byte)0xca, (byte)0xd4};//GBK編碼的"中文測試"
java.io.ByteArrayInputStream bin = new java.io.ByteArrayInputStream(bytes);
java.io.BufferedReader reader = new java.io.BufferedReader(new java.io. InputStreamReader (bin,"GBK"));
String msg = reader.readLine();
System.out.println(msg)
這段程序放到包含"中文測試"這四個字的系統(如中文系統)中,可以正確地打印出這些字。msg字符串中包含了正確的"中文測試"的Unicode編碼:"u4e2du6587u6d4bu8bd5",打印時轉換為操作系統的默認字符集,是否可以正確顯示依賴于操作系統的字符集,只有在支持相應字符集的系統中,我們的信息才能正確的輸出,否則得到的將會是垃圾。
話入正題,我們來看看Servlet/Jsp中的多語言問題。我們的目標是,任一國家的客戶端通過Form向Server發送信息,Server把信息存入數據庫中,客戶端在檢索時仍然能夠看到自己發送的正確信息。事實上,我們要保證,最終Server中的SQL語句中保存的時包含客戶端發送文字的正確Unicode編碼;DBC與數據庫通訊時采用的編碼方式能包含客戶端發送的文字信息,事實上,最好讓JDBC直接使用UNICODE/UTF8與數據庫通訊!這樣就可以確保不會丟失信息;Server向客戶端發送的信息時也要采用不丟失信息的編碼方式,也可以是Unicode/Utf8。
如果不指定Form的Enctype屬性,Form將把輸入的內容依照當前頁面的編碼字符集urlencode之后再提交,服務器端得到是urlencoding的字符串。編碼后得到的urlencoding字符串是與頁面的編碼相關的,如gb2312編碼的頁面提交"中文測試",得到的是"%D6%D0%CE%C4%B2%E2%CA%D4",每個"%"后跟的是16進制的字符串;而在UTF8編碼時得到的卻是"%E4%B8%AD%E6%96%87%E6%B5%8B%E8%AF%95",因為GB2312編碼中一個漢字是16位的,而UTF8中一個漢字卻是24位的。中日韓三國的ie4以上瀏覽器均支持UTF8編碼,這種方案肯定包涵了這三國語言,所以我們如果讓Html頁面使用UTF8編碼那么將至少可以支持這三國語言。
但是,如果我們html/Jsp頁面使用UTF8編碼,因為應用程序服務器可能不知道這種情況,因為如果瀏覽器發送的信息不包含charset信息,至多Server知道讀到Accept-Language請求投標,我們知道僅靠這個投標是不能獲知瀏覽器所采用編碼的,所以應用程序服務器不能正確解析提交的內容,為什么?因為Java中的所有字符串都是Unicode16位編碼的,HttpServletRequest.request(String)的功能就是把客戶端提交的Urlencode編碼的信息轉為Unicode字符串,有些Server只能認為客戶端的編碼和Server平臺相同,簡單地使用URLDecoder.decode(String)方法直接解碼,如果客戶端編碼恰好和Server相同,那么就可以得到正確地字符串,否則,如果提交地字符串中包含了當地字符,那么將會導致垃圾信息。
在我提出的這個解決方案里,已經指定了采用Utf8編碼,所以,可以避免這個問題,我們可以自己定制出decode方法:
public static String decode(String s,String encoding) throws Exception {
StringBuffer sb = new StringBuffer();
for(int i=0; ichar c = s.charAt(i);
switch (c) {
case ´+´:
sb.append(´ ´);
break;
case ´%´:
try {
sb.append((char)Integer.parseInt(
s.substring(i+1,i+3),16));
}
catch (NumberFormatException e) {
throw new IllegalArgumentException();
}
i += 2;
break;
default:
sb.append(c);
break;
}
}
// Undo conversion to external encoding
String result = sb.toString();
byte[] inputBytes = result.getBytes("8859_1");
return new String(inputBytes,encoding);
}
這個方法可以指定encoding,如果把它指定為UTF8就滿足了我們的需要。比如用它解析:"%E4%B8%AD%E6%96%87%E6%B5%8B%E8%AF%95"就可以得到正確的漢字"中文測試"的Unicode字符串。
現在的問題就是我們必須得到客戶端提交的Urlencode的字符串。對于method為get的form提交的信息,可以用HttpServletRequest.getQueryString()方法讀到,而對于post方法的form提交的信息,只能從ServletInputStream中讀到,事實上標準的getParameter方法被第一次調用后,form提交的信息就被讀取出來了,而ServletInputStream是不能重復讀出的。所以我們應在第一次使用getParameter方法前讀取并解析form提交的信息。
我是這么做的,建立一個Servlet基類,覆蓋service方法,在調用父類的service方法前讀取并解析form提交的內容,請看下面的源代碼:
package com.hto.servlet;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
/**
* Insert the type´s description here.
* Creation date: (2001-2-4 15:43:46)
* @author: 錢衛春
*/
public class UTF8ParameterReader {
Hashtable pairs = new Hashtable();
/**
* UTF8ParameterReader constructor comment.
*/
public UTF8ParameterReader(HttpServletRequest request) throws java.io.IOException{
super();
parse(request.getQueryString());
parse(request.getReader().readLine());
}
/**
* UTF8ParameterReader constructor comment.
*/
public UTF8ParameterReader(HttpServletRequest request,String encoding) throws java.io.IOException{
super();
parse(request.getQueryString(),encoding);
parse(request.getReader().readLine(),encoding);
}
public static String decode(String s) throws Exception {
StringBuffer sb = new StringBuffer();
for(int i=0; ichar c = s.charAt(i);
switch (c) {
case ´+´:
sb.append(´ ´);
break;
case ´%´:
try {
sb.append((char)Integer.parseInt(
s.substring(i+1,i+3),16));
}
catch (NumberFormatException e) {
throw new IllegalArgumentException();
}
i += 2;
break;
default:
sb.append(c);
break;
}
}
// Undo conversion to external encoding
String result = sb.toString();
byte[] inputBytes = result.getBytes("8859_1");
return new String(inputBytes,"UTF8");
}
public static String decode(String s,String encoding) throws Exception {
StringBuffer sb = new StringBuffer();
for(int i=0; ichar c = s.charAt(i);
switch (c) {
case ´+´:
sb.append(´ ´);
break;
case ´%´:
try {
sb.append((char)Integer.parseInt(
s.substring(i+1,i+3),16));
}
catch (NumberFormatException e) {
throw new IllegalArgumentException();
}
i += 2;
break;
default:
sb.append(c);
break;
}
}
// Undo conversion to external encoding
String result = sb.toString();
byte[] inputBytes = result.getBytes("8859_1");
return new String(inputBytes,encoding);
}
/**
* Insert the method´s description here.
* Creation date: (2001-2-4 17:30:59)
* @return java.lang.String
* @param name java.lang.String
*/
public String getParameter(String name) {
if (pairs == null || !pairs.containsKey(name)) return null;
return (String)(((ArrayList) pairs.get(name)).get(0));
}
/**
* Insert the method´s description here.
* Creation date: (2001-2-4 17:28:17)
* @return java.util.Enumeration
*/
public Enumeration getParameterNames() {
if (pairs == null) return null;
return pairs.keys();
}
/**
* Insert the method´s description here.
* Creation date: (2001-2-4 17:33:40)
* @return java.lang.String[]
* @param name java.lang.String
*/
public String[] getParameterValues(String name) {
if (pairs == null || !pairs.containsKey(name)) return null;
ArrayList al = (ArrayList) pairs.get(name);
String[] values = new String[al.size()];
for(int i=0;ireturn values;
}
/**
* Insert the method´s description here.
* Creation date: (2001-2-4 20:34:37)
* @param urlenc java.lang.String
*/
private void parse(String urlenc) throws java.io.IOException{
if (urlenc == null) return;
StringTokenizer tok = new StringTokenizer(urlenc,"&");
try{
while (tok.hasMoreTokens()){
String aPair = tok.nextToken();
int pos = aPair.indexOf("=");
String name = null;
String value = null;
if(pos != -1){
name = decode(aPair.substring(0,pos));
value = decode(aPair.substring(pos+1));
}else{
name = aPair;
value = "";
}
if(pairs.containsKey(name)){
ArrayList values = (ArrayList)pairs.get(name);
values.add(value);
}else{
ArrayList values = new ArrayList();
values.add(value);
pairs.put(name,values);
}
}
}catch(Exception e){
throw new java.io.IOException(e.getMessage());
}
}
/**
* Insert the method´s description here.
* Creation date: (2001-2-4 20:34:37)
* @param urlenc java.lang.String
*/
private void parse(String urlenc,String encoding) throws java.io.IOException{
if (urlenc == null) return;
StringTokenizer tok = new StringTokenizer(urlenc,"&");
try{
while (tok.hasMoreTokens()){
String aPair = tok.nextToken();
int pos = aPair.indexOf("=");
String name = null;
String value = null;
if(pos != -1){
name = decode(aPair.substring(0,pos),encoding);
value = decode(aPair.substring(pos+1),encoding);
}else{
name = aPair;
value = "";
}
if(pairs.containsKey(name)){
ArrayList values = (ArrayList)pairs.get(name);
values.add(value);
}else{
ArrayList values = new ArrayList();
values.add(value);
pairs.put(name,values);
}
}
}catch(Exception e){
throw new java.io.IOException(e.getMessage());
}
}
}
這個類的功能就是讀取并保存form提交的信息,并實現常用的getParameter方法。
package com.hto.servlet;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
/**
* Insert the type´s description here.
* Creation date: (2001-2-5 8:28:20)
* @author: 錢衛春
*/
public class UtfBaseServlet extends HttpServlet {
public static final String PARAMS_ATTR_NAME = "PARAMS_ATTR_NAME";
/**
* Process incoming HTTP GET requests
*
* @param request Object that encapsulates the request to the servlet
* @param response Object that encapsulates the response from the servlet
*/
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
performTask(request, response);
}
/**
* Process incoming HTTP POST requests
*
* @param request Object that encapsulates the request to the servlet
* @param response Object that encapsulates the response from the servlet
*/
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
performTask(request, response);
}
/**
* Insert the method´s description here.
* Creation date: (2001-2-5 8:52:43)
* @return int
* @param request javax.servlet.http.HttpServletRequest
* @param name java.lang.String
* @param required boolean
* @param defValue int
*/
public static java.sql.Date getDateParameter(HttpServletRequest request, String name, boolean required, java.sql.Date defValue) throws ServletException{
String value = getParameter(request,name,required,String.valueOf(defValue));
return java.sql.Date.valueOf(value);
}
/**
* Insert the method´s description here.
* Creation date: (2001-2-5 8:52:43)
* @return int
* @param request javax.servlet.http.HttpServletRequest
* @param name java.lang.String
* @param required boolean
* @param defValue int
*/
public static double getDoubleParameter(HttpServletRequest request, String name, boolean required, double defValue) throws ServletException{
String value = getParameter(request,name,required,String.valueOf(defValue));
return Double.parseDouble(value);
}
/**
* Insert the method´s description here.
* Creation date: (2001-2-5 8:52:43)
* @return int
* @param request javax.servlet.http.HttpServletRequest
* @param name java.lang.String
* @param required boolean
* @param defValue int
*/
public static float getFloatParameter(HttpServletRequest request, String name, boolean required, float defValue) throws ServletException{
String value = getParameter(request,name,required,String.valueOf(defValue));
return Float.parseFloat(value);
}
/**
* Insert the method´s description here.
* Creation date: (2001-2-5 8:52:43)
* @return int
* @param request javax.servlet.http.HttpServletRequest
* @param name java.lang.String
* @param required boolean
* @param defValue int
*/
public static int getIntParameter(HttpServletRequest request, String name, boolean required, int defValue) throws ServletException{
String value = getParameter(request,name,required,String.valueOf(defValue));
return Integer.parseInt(value);
}
/**
* Insert the method´s description here.
* Creation date: (2001-2-5 8:43:36)
* @return java.lang.String
* @param request javax.servlet.http.HttpServletRequest
* @param name java.lang.String
* @param required boolean
* @param defValue java.lang.String
*/
public static String getParameter(HttpServletRequest request, String name, boolean required, String defValue) throws ServletException{
if(request.getAttribute(UtfBaseServlet.PARAMS_ATTR_NAME) != null) {
UTF8ParameterReader params = (UTF8ParameterReader)request.getAttribute(UtfBaseServlet.PARAMS_ATTR_NAME);
if (params.getParameter(name) != null) return params.getParameter(name);
if (required) throw new ServletException("The Parameter "+name+" Required but not provided!");
else return defValue;
}else{
if (request.getParameter(name) != null) return request.getParameter(name);
if (required) throw new ServletException("The Parameter "+name+" Required but not provided!");
else return defValue;
}
}
/**
* Returns the servlet info string.
*/
public String getServletInfo() {
return super.getServletInfo();
}
/**
* Insert the method´s description here.
* Creation date: (2001-2-5 8:52:43)
* @return int
* @param request javax.servlet.http.HttpServletRequest
* @param name java.lang.String
* @param required boolean
* @param defValue int
*/
public static java.sql.Timestamp getTimestampParameter(HttpServletRequest request, String name, boolean required, java.sql.Timestamp defValue) throws ServletException{
String value = getParameter(request,name,required,String.valueOf(defValue));
return java.sql.Timestamp.valueOf(value);
}
/**
* Initializes the servlet.
*/
public void init() {
// insert code to initialize the servlet here
}
/**
* Process incoming requests for information
*
* @param request Object that encapsulates the request to the servlet
* @param response Object that encapsulates the response from the servlet
*/
public void performTask(HttpServletRequest request, HttpServletResponse response) {
try
{
// Insert user code from here.
}
catch(Throwable theException)
{
// uncomment the following line when unexpected exceptions
// are occuring to aid in debugging the problem.
//theException.printStackTrace();
}
}
/**
* Insert the method´s description here.
* Creation date: (2001-2-5 8:31:54)
* @param request javax.servlet.ServletRequest
* @param response javax.servlet.ServletResponse
* @exception javax.servlet.ServletException The exception description.
* @exception java.io.IOException The exception description.
*/
public void service(ServletRequest request, ServletResponse response) throws javax.servlet.ServletException, java.io.IOException {
String content = request.getContentType();
if(content == null || content != null && content.toLowerCase().startsWith("application/x-www-form-urlencoded"))
request.setAttribute(PARAMS_ATTR_NAME,new UTF8ParameterReader((HttpServletRequest)request));
super.service(request,response);
}
}
這個就是Servlet基類,它覆蓋了父類的service方法,在調用父類service前,創建了UTF8ParameterReader對象,其中保存了form中提交的信息。然后把這個對象作為一個Attribute保存到Request對象中。然后照樣調用父類的service方法。
對于繼承這個類的Servlet,要注意的是,"標準"getParameter在也不能讀到post的數據,因為在這之前這個類中已經從ServletInputStream中讀出了數據了。所以應該使用該類中提供的getParameter方法。
剩下的就是輸出問題了,我們要把輸出的信息,轉為UTF8的二進制流輸出。只要我們設置Content-Type時指定charset為UTF8,然后使用PrintWriter輸出,那么這些轉換是自動進行的,Servlet中這樣設置:
response.setContentType("text/html;charset=UTF8");
Jsp中這樣設置:
這樣就可以保證輸出是UTF8流,客戶端能否顯示,就看客戶端的了。
對于multipart/form-data的form提交的內容,我也提供一個類用來處理,在這個類的構造子中可以指定頁面使用的charset,默認還是UTF-8,限于篇幅不貼出源碼。
在Jsp程序解決向DB讀取或寫入時的亂碼問題
在基于JAVA的編程中,經常會碰到漢字的處里及顯示的問題,比如一大堆亂碼或問號。
這是因為JAVA中默認的編碼方式是UNICODE,而中國人通常使用的文件和DB都是基于GB2312或者BIG5等編碼,故會出現此問題。以前我也經常為這個問題而苦惱,后來經查了些資料,終于解決了,我知道一定有很多朋友也會碰到這個問題,所以特就總結了一下,來拿出來讓大家一起分享了。
1、在網頁中輸出中文。
JAVA在網絡傳輸中使用的編碼是"ISO-8859-1",故在輸出時需要進行轉化,如:
String str="中文";
str=new String(str.getBytes("GB2312"),"8859_1");
但如果在編譯程序時,使用的編碼是“GB2312”,且在中文平臺上運行此程序,不會出現此問題,一定要注意。
2、從參數中讀取中文
這正好與在網頁中輸出相反如:
str=new String(str.getBytes("8859_1"),"GB2312");
3、操作DB中的中文問題
一個較簡單的方法是:在“控制面扳”中,把“區域”設置為“英語(美國)”。如果還會出現亂碼,還可進行如下設置:
取中文時:str=new String(str.getBytes("GB2312"));
向DB中輸入中文:str=new String(str.getBytes("ISO-8859-1"));
4、在JSP中的中文解決:
在“控制面扳”中,把“區域”設置為“英語(美國)”.
在JSP頁面中加入:
如果還不行正常顯示,則還要進行下面的轉換:
如:name=new String(name.getBytes("ISO-8859-1"),"GBK");
就不會出現中文問題了。
Tomcat中Java/jsp中文問題完全解決方案
Tomcat 3.23以下的版本
對于Tomcat 3.23以下版本,Java中的中文問題網上已經談了不少,一般遇到中文問題使用轉換函數轉換.toChinese()
public static String toChinese(String strvalue)
{
try{
if(strvalue==null)
return null;
else
{
strvalue = new String(strvalue.getBytes("ISO8859_1"), "GBK");
return strvalue;
}
}catch(Exception e){
return null;
}
}
凡是涉及中文字符串,如從數據庫中讀取中文字符串,或變量名賦值時,使用toChinese函數:
toChinese("這是中文字符串")
注:該辦法在使用javamail發送中文信息時似乎有問題
Tomcat 4.0以上的版本
在4.0以后的版本,已經不需要象3.23版本中使用字符轉換函數:
(1)編譯javabean時 javac 命令行加上-encoding ISO8859_1
(2)在Jsp頭部中加入
是不是很簡單? 使用本辦法基本可以對付實際應用,推薦!
但也有一個缺點是,通過form表單get參數;或在url后附帶中文,這個辦法就失效,我相信應該有辦法解決.
該辦法原理就是在java的各個環節統一編碼為:ISO8859_1.
修改tomcat
該辦法是一位網友在論壇貼出的,我沒有試驗,轉載于此:
只要修改一個地方就行了,文件為:
tomcat4/src/catalina/src/share/org/apache/catalina/connector/HttpReque
stBase.java
找到protected void parseParameters()方法,把
if (encoding == null)
encoding = "ISO-8859-1";
改為
if (encoding == null)
encoding = "GBK";
編譯:
解開jakarta-servletapi-4的原碼包,找到servlet.jar文件設置到CLASSPATH
找到tomcat4.0.1的bin包將catalina.jar設置到CLASSPATH.
因為編譯時要使用這些api.
然后javac HttpRequestBase.java生成兩個class文件.
解開catalina.jar jar xvf catalina.jar(tomcat bin包中的)
覆蓋調原來的兩個class文件:
jar cvf catalina.jar org
即可
重啟tomcat4,一切OK!,你再也不用編寫煩人的編碼轉換了。
jsp中框架頁面請求中的中文編碼問題
最近有這么一個需求,一個主頁面從request中拿到請求的參數(中文),主頁面里有兩個Frame,每個Frame嵌著一個jsp,如何把主頁面中得到的中文參數值傳入Frame里去呢,后來發現應該先把中文編碼成unicode,然后傳給frame中的jsp,frame中的jsp再解碼,程序清單如下:index.jsp
========================================================
String flowname = request.getParameter("flowname");
% >
業務相關資料
" name="topFrame" frameborder="1" scrolling="auto" noresize >
assetlist.jsp
========================================================
String cond ="flowname = '"+ request.getParameter("flowname")+"'";
// out.println(cond);
HttpSession sess = request.getSession();
int allpage = 0;//頁數
String pageNo = request.getParameter("pageNo");
//pageNo為null,則賦值為1
if(pageNo==null){
pageNo="1";
sess.setAttribute("flowname",cond);
}
else{
cond = (String)sess.getAttribute("flowname");
// out.println(cond);
}
int p = Integer.parseInt(pageNo);//當前頁
ArrayList al = new ArrayList();
int size=0;
try{
DAMInterfaceApp dapp = new DAMInterfaceApp();
Verify ver = new Verify(dapp);
ver.login("admin","admin");
QueryAssetExt quExt = QueryAssetExt.getInstance(dapp);
String strQueryResult = "";
try
{
strQueryResult = quExt.queryAllAssets(150,cond, "", "", 0);
}
catch(Exception qe)
{
System.err.print("錯誤:調用博思查詢接口QueryAssetExt.queryAllAssets出錯,錯誤信息為:"+qe.getMessage());
}
//對得到的查詢結果進行解析
//System.out.println("提示:查詢結果為: "+strQueryResult);
al = (ArrayList)QueryAssetAdapter.getQueryAssets(strQueryResult);
allpage = PageUtil.getAllpage(al);
//out.println(allpage);
al = PageUtil.getPageItems(al,p);
size = al.size();
//out.println(size);
}
catch(Exception e){
e.printStackTrace();
}
% >
html >
業務相關資料
/css/csstop.css" rel="stylesheet" type="text/css" >
/css/link_sty.css" rel="stylesheet" type="text/css" >
var swd = null;
function selected(t)
{
if(swd!=null)
swd.className = "";
if(t==swd)
{
swd = null;
return;
}
t.className = "xz";
swd=t;
submit();
}
function submit()
{
document.frmAssets.assetid.value = swd.id;
document.frmAssets.submit();
}
#Table1 tr{ cursor:hand; }
.xz { color: #FFFFFF; background-color: #66CCCC; }
業務相關資料
標題
業務名稱
處室
聯系人
聯系電話
版本
for(int j=0;j
"??>
共??頁
首頁
int ii = 0;
if(p>1){
ii = p - 1;
}
% >
" >上一頁
if(p}
else if(p==allpage){
ii = p;
}
% >
">下一頁
">末頁
編碼解碼的java程序Escape.java
========================================================
package gov.police.tech.application.appdata;
public class Escape {
private final static String[] hex = { "00", "01", "02", "03", "04", "05",
"06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F", "10",
"11", "12", "13", "14", "15", "16", "17", "18", "19", "1A", "1B",
"1C", "1D", "1E", "1F", "20", "21", "22", "23", "24", "25", "26",
"27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F", "30", "31",
"32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B", "3C",
"3D", "3E", "3F", "40", "41", "42", "43", "44", "45", "46", "47",
"48", "49", "4A", "4B", "4C", "4D", "4E", "4F", "50", "51", "52",
"53", "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D",
"5E", "5F", "60", "61", "62", "63", "64", "65", "66", "67", "68",
"69", "6A", "6B", "6C", "6D", "6E", "6F", "70", "71", "72", "73",
"74", "75", "76", "77", "78", "79", "7A", "7B", "7C", "7D", "7E",
"7F", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89",
"8A", "8B", "8C", "8D", "8E", "8F", "90", "91", "92", "93", "94",
"95", "96", "97", "98", "99", "9A", "9B", "9C", "9D", "9E", "9F",
"A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "AA",
"AB", "AC", "AD", "AE", "AF", "B0", "B1", "B2", "B3", "B4", "B5",
"B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF", "C0",
"C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB",
"CC", "CD", "CE", "CF", "D0", "D1", "D2", "D3", "D4", "D5", "D6",
"D7", "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF", "E0", "E1",
"E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC",
"ED", "EE", "EF", "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7",
"F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF" };
private final static byte[] val = { 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x01,
0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F };
/**
* 編碼
*
* @param s
* @return
*/
public static String escape(String s) {
StringBuffer sbuf = new StringBuffer();
int len = s.length();
for (int i = 0; i int ch = s.charAt(i);
if ('A' sbuf.append((char) ch);
} else if ('a' sbuf.append((char) ch);
} else if ('0' sbuf.append((char) ch);
} else if (ch == '-' || ch == '_' // unreserved : as it was
|| ch == '.' || ch == '!' || ch == '~' || ch == '*'
|| ch == '\'' || ch == '(' || ch == ')') {
sbuf.append((char) ch);
} else if (ch sbuf.append('%');
sbuf.append(hex[ch]);
} else { // unicode : map to %uXXXX
sbuf.append('%');
sbuf.append('u');
sbuf.append(hex[(ch >>> 8)]);
sbuf.append(hex[(0x00FF & ch)]);
}
}
return sbuf.toString();
}
/**
* 解碼 說明:本方法保證 不論參數s是否經過escape()編碼,均能得到正確的“解碼”結果
*
* @param s
* @return
*/
public static String unescape(String s) {
StringBuffer sbuf = new StringBuffer();
int i = 0;
int len = s.length();
while (i int ch = s.charAt(i);
if ('A' sbuf.append((char) ch);
} else if ('a' sbuf.append((char) ch);
} else if ('0' sbuf.append((char) ch);
} else if (ch == '-' || ch == '_' // unreserved : as it was
|| ch == '.' || ch == '!' || ch == '~' || ch == '*'
|| ch == '\'' || ch == '(' || ch == ')') {
sbuf.append((char) ch);
} else if (ch == '%') {
int cint = 0;
if ('u' != s.charAt(i + 1)) { // %XX : map to ascii(XX)
cint = (cint cint = (cint i += 2;
} else { // %uXXXX : map to unicode(XXXX)
cint = (cint cint = (cint cint = (cint cint = (cint i += 5;
}
sbuf.append((char) cint);
} else { // 對應的字符未經過編碼
sbuf.append((char) ch);
}
i++;
}
return sbuf.toString();
}
public static void main(String[] args) {
String stest = "中文1234 abcd[](),.~\\";
System.out.println(stest);
System.out.println(escape(stest));
System.out.println(unescape(escape(stest)));
}
}
用filter來解決Struts中文亂碼的問題
filter的用法,的確是比較有擴展性的一種方法...可以通過filter結合讀取web.xml中的filter參數來完成一系列的動作,做法如下:
首先,實現javax.servlet.Filter接口,編寫一個處理request編碼的過濾器類...
package tutorial.struts.filter;
import javax.servlet.Filter;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.FilterChain;
import java.io.IOException;
public class SetCharacterEncodingFilter implements Filter {
??protected FilterConfig filterConfig;
??protected String encodingName;
??protected boolean enable;
??public SetCharacterEncodingFilter() {
? ? this.encodingName = "UTF-8";
? ? this.enable = false;
??}
??public void init(FilterConfig filterConfig) throws ServletException {
? ? this.filterConfig = filterConfig;
? ? loadConfigParams();
??}
??private void loadConfigParams() {
? ? //encoding
? ? this.encodingName = this.filterConfig.getInitParameter("encoding");
? ? //filter enable flag...
? ? String strIgnoreFlag = this.filterConfig.getInitParameter("enable");
? ? if (strIgnoreFlag.equalsIgnoreCase("true")) {
? ?? ?this.enable = true;
? ? } else {
? ?? ?this.enable = false;
? ? }
??}
??public void doFilter(ServletRequest request, ServletResponse response,
? ?? ?? ?? ?? ?? ?? ???FilterChain chain) throws IOException, ServletException {
? ? if(this.enable) {
? ?? ?request.setCharacterEncoding(this.encodingName);
? ? }
? ? chain.doFilter(request, response);
??}
??public void destroy() {
??}
}
然后,需要在web.xml中注冊我們的過濾器類:
< filter >
? ? < filter-name >Set Character Encoding< /filter-name >
? ? < filter-class >tutorial.struts.filter.SetCharacterEncodingFilter< /filter-class >
? ? < init-param >
? ?? ?< param-name >encoding< /param-name >
? ?? ?< param-value >UTF-8< /param-value >
? ? < /init-param >
? ? < init-param >
? ?? ?< param-name >enable< /param-name >
? ?? ?< param-value >true< /param-value >
? ? < /init-param >
??< /filter >
??< filter-mapping >
? ? < filter-name >Set Character Encoding< /filter-name >
? ? < servlet-name >Action Servlet< /servlet-name >
??< /filter-mapping >
??< filter-mapping >
? ? < filter-name >Set Character Encoding< /filter-name >
? ? < servlet-name >Faces Servlet< /servlet-name >
??< /filter-mapping >
這樣,任何通過Struts,或是JSF的Controller Servlet處理的request,都會在過濾器中先行處理,才把控制權交還給Struts或是JSF,而且Filter中有一個Process Chain的概念,是一個很吸引人的東東~~!
J2EE WEB-Tomcat5.5.9中文問題解決方案
1、html
無論是獨立的html,還是其他程序生成的,如Servlet等,注意在最終的html的和之間必須加入meta標簽,用來指定html中輸入字符的編碼,如:
測試GET && POST-Send
2、jsp和servlet
首先必須解決程序輸出(如response.writeln(String s))和接受從客戶端傳來的數據(如request.getParameter(String sname))編碼問題,我們可以利用文件過濾功能,具體需要所用的jsp/servlet容器或者服務器提供的功能設置,如在Tomcat5.5.9中可以在webapps/yourAppDirectory/WEB-INF/web.xml中設置如下:
SetCharsetEncodingFilter
SetCharsetEncodingFilter
Set CharsetEncoding Filter
com.gg.comm.web.SetCharsetEncodingFilter
??
encoding
gb2312
??
SetCharsetEncodingFilter
/*
其中SetCharsetEncodingFilter Class就是用來設置request和reponse字符編碼的filter類,其中設置語句如下:
request.setCharacterEncoding(targetEncoding);
response.setContentType("text/html");
response.setCharacterEncoding(targetEncoding);
另外為了解決通過get(url中帶有參數)方式傳遞參數的亂碼問題,我們還需要設置一下url傳遞參數所需要的編碼,具體在Tomcat5.5.9中可以在${Tomcat_home}\conf\server.xml中的和之間設置,如下:
URIEncoding="GBK":Force GET method String(Chinese) can be transferd properly by http:uri
note:Tomcat only support GBK specification,so not set charset gb2312
-- >
最后為了解決jsp的亂碼問題,我們還需要作如下處理,即在左右的jsp頭均加上如下指令:
或者
3、jdbc和數據庫
關于寫入數據庫和讀取數據庫數據的亂碼問題,可以通過如下方式輕松解決:
對于JAVA程序的處理方法按我們指定的方法處理。
把數據庫默認支持的編碼格式改為GBK或GB2312的。
到此,一般來說對于WEB方式的應用來說,中文問題就可以解決了。當然以上方法是根據統一編碼的原則解決的以及WEB方式的文件轉換關系
(file->class->load->execute or transfered or response or request)來做的。
網友評論
定義三個類,A,B,C。在A中申明一個Button變量button1,在B再申明Button變量button2,把A中的變量button1賦給button2? ? 在C中再申明一個Button變量button3,把給B中的變量button2賦給button3,為什么在C中button1就不等于button3
2007-03-19 15:06:29
賽迪網友
不錯,比較全面,值得收藏~
2007-02-12 03:48:12
DIY
Java Programmer群號:18615413 技術聯盟-軟件交流! 歡迎任何熱愛JAVA的人進群切磋 !
本文來自ChinaUnix博客,如果查看原文請點:http://blog.chinaunix.net/u1/44781/showart_352828.html
JSP中文問題解決方案
只需要保持下面幾處地方設置統一,你的JSP就不會有中文問題
1、JSP的charset,
2、你的JSP SERVER編譯JSP是使用的字符集,默認和操作系統是一樣的。你可能需要進行修改
3、你的BEAN編譯時候所采用的字符集,一般用JAVAC編譯,都是和操作系統一樣的,但你可以通過帶參數來改變。如果用其它的編程工具,可以編譯的話,你可能需要修改其默認參數。
4、和數據庫連接時,大多數JDBC驅動程序都可以設置其字符集的,這樣JDBC驅動會自己進行轉換,也不會出現漢字問題。
以jConnect為例,就有這樣一個屬性參數:
CHARSET
Specifies the character set for strings passed through TDS. If you specify a CHARSET, it must match a CHARSET listed in syscharsets.
If null, jConnect uses the server’s default CHARSET.
明白?jdbc-odbc橋也有這樣的參數的(charSet)。 不同的驅動,請參閱文檔。
對于中文處理的常見對策,在網上經常可見的主要是下面2種:
或者:
String Hi="你好";
byte[] tmpbyte=Hi.getBytes("ISO8859_1");
Hi=new String(tmpbyte);
out.print(Hi);
% >
通過簡單總結,示例中的中文處理發生于以下幾個地方:
1 在url附帶中文參數,可以直接讀取。
例如:
2 與數據庫有關的各種sql操作
這里使用的Access沒有發生問題。
3 讀取HTML form表單中遞交的中文值
在jswdk中需要加以編碼,較為簡潔的寫法如:
String name1=new String(request.getParameter("user_id").getBytes("ISO8859_1"));
另外,在jdk1.3的支持下,不需要加入
而在jdk1.2.2下面,即使2種方法同時運用也很不穩定。
而在resin平臺,情況較好。只要在頁面第一行加入:
即可正確處理中文。
如果再加編碼則反而不對。
5 session中包含的中文
在jswdk中,奇怪的是如果從form中讀出的值經過編碼則可正確顯示;但直接賦予中文值則不行。
resin平臺很好,同上。
6 對于對變量賦中文值后正確顯示中文。
例如以下程序:
String Hi="你好";
byte[] tmpbyte=Hi.getBytes("ISO8859_1");
Hi=new String(tmpbyte);
out.print(Hi);
% >
同樣是jswdk1.0.1,以上的表示方法在jdk1.2.2中沒有問題,但在jdk1.3下卻無法顯示。
resin平臺很好,同上,經過測試,只需要在中補上
而不需要也能正確顯示中文。
體會:
jswdk也許只能用于普通開發,穩定性和其它問題可能不如商業軟件。
由于jdk1.3版性能要好于jdk1.2.2很多倍,并且對中文的支持也較好,所以應該加以采用。
作為免費的商業軟件,resin不僅速度快,穩定,自動編譯,可指出出錯行,可在服務器端支持使用javascript等,而且,至少我覺得對中文的支持很好。
當然,如果不必做任何處理即可正確顯示中文將是我們所期待的。
另外,相信在unix/linux/solaris下應該沒有這樣的問題.
一般來說,只要你做到了以上幾點,你的JSP幾乎(根本各人的配置吧)不會再有中文問題了!
JSP/Servlet 中的漢字編碼問題
網上就 JSP/Servlet 中 DBCS 字符編碼問題有許多優秀的文章和討論,本文對它們作一些整理,并結合 IBM WebSphere Application Server 3.5(WAS)的解決方法作一些說明,希望它不是多余的。
內容:
問題的起源
GB2312-80,GBK,GB18030-2000 漢字字符集及 Encoding
中文轉碼時´?´、亂碼的由來
JSP/Servlet 漢字編碼問題及在 WAS 中的解決辦法
結束語
參考文章
1. 問題的起源
每個國家(或區域)都規定了計算機信息交換用的字符編碼集,如美國的擴展 ASCII碼, 中國的 GB2312-80,日本的 JIS 等,作為該國家/區域內信息處理的基礎,有著統一編碼的重要作用。字符編碼集按長度分為 SBCS(單字節字符集),DBCS(雙字節字符集)兩大類。早期的軟件(尤其是操作系統),為了解決本地字符信息的計算機處理,出現了各種本地化版本(L10N),為了區分,引進了 LANG, Codepage 等概念。但是由于各個本地字符集代碼范圍重疊,相互間信息交換困難;軟件各個本地化版本獨立維護成本較高。因此有必要將本地化工作中的共性抽取出來,作一致處理,將特別的本地化處理內容降低到最少。這也就是所謂的國際化(I18N)。各種語言信息被進一步規范為 Locale 信息。處理的底層字符集變成了幾乎包含了所有字形的 Unicode。
現在大部分具有國際化特征的軟件核心字符處理都是以 Unicode 為基礎的,在軟件運行時根據當時的 Locale/Lang/Codepage 設置確定相應的本地字符編碼設置,并依此處理本地字符。在處理過程中需要實現 Unicode 和本地字符集的相互轉換,甚或以 Unicode 為中間的兩個不同本地字符集的相互轉換。這種方式在網絡環境下被進一步延伸,任何網絡兩端的字符信息也需要根據字符集的設置轉換成可接受的內容。
Java 語言內部是用 Unicode 表示字符的,遵守 Unicode V2.0。Java 程序無論是從/往文件系統以字符流讀/寫文件,還是往 URL 連接寫 HTML 信息,或從 URL 連接讀取參數值,都會有字符編碼的轉換。這樣做雖然增加了編程的復雜度,容易引起混淆,但卻是符合國際化的思想的。
從理論上來說,這些根據字符集設置而進行的字符轉換不應該產生太多問題。而事實是由于應用程序的實際運行環境不同,Unicode 和各個本地字符集的補充、完善,以及系統或應用程序實現的不規范,轉碼時出現的問題時時困擾著程序員和用戶。
2. GB2312-80,GBK,GB18030-2000 漢字字符集及 Encoding
其實解決 JAVA 程序中的漢字編碼問題的方法往往很簡單,但理解其背后的原因,定位問題,還需要了解現有的漢字編碼和編碼轉換。
GB2312-80 是在國內計算機漢字信息技術發展初始階段制定的,其中包含了大部分常用的一、二級漢字,和 9 區的符號。該字符集是幾乎所有的中文系統和國際化的軟件都支持的中文字符集,這也是最基本的中文字符集。其編碼范圍是高位0xa1-0xfe,低位也是 0xa1-0xfe;漢字從 0xb0a1 開始,結束于 0xf7fe;
GBK 是 GB2312-80 的擴展,是向上兼容的。它包含了 20902 個漢字,其編碼范圍是 0x8140-0xfefe,剔除高位 0x80 的字位。其所有字符都可以一對一映射到 Unicode 2.0,也就是說 JAVA 實際上提供了 GBK 字符集的支持。這是現階段 Windows 和其它一些中文操作系統的缺省字符集,但并不是所有的國際化軟件都支持該字符集,感覺是他們并不完全知道 GBK 是怎么回事。值得注意的是它不是國家標準,而只是規范。隨著 GB18030-2000國標的發布,它將在不久的將來完成它的歷史使命。
GB18030-2000(GBK2K) 在 GBK 的基礎上進一步擴展了漢字,增加了藏、蒙等少數民族的字形。GBK2K 從根本上解決了字位不夠,字形不足的問題。它有幾個特點,
它并沒有確定所有的字形,只是規定了編碼范圍,留待以后擴充。
編碼是變長的,其二字節部分與 GBK 兼容;四字節部分是擴充的字形、字位,其編碼范圍是首字節 0x81-0xfe、二字節0x30-0x39、三字節 0x81-0xfe、四字節0x30-0x39。
它的推廣是分階段的,首先要求實現的是能夠完全映射到 Unicode 3.0 標準的所有字形。
它是國家標準,是強制性的。
現在還沒有任何一個操作系統或軟件實現了 GBK2K 的支持,這是現階段和將來漢化的工作內容。
Unicode 的介紹......就免了吧。
JAVA 支持的encoding中與中文編程相關的有:(有幾個在JDK文檔中未列出)
ASCII 7-bit, 同 ascii7
ISO8859-1 8-bit, 同 8859_1,ISO-8859-1,ISO_8859-1,latin1...
GB2312-80 同gb2312,gb2312-1980,EUC_CN,euccn,1381,Cp1381, 1383, Cp1383, ISO2022CN,ISO2022CN_GB......
GBK (注意大小寫),同MS936
UTF8 UTF-8
GB18030 (現在只有IBM JDK1.3.?有支持), 同Cp1392,1392
JAVA 語言采用Unicode處理字符. 但從另一個角度來說,在java程序中也可以采用非Unicode的轉碼,重要的是保證程序入口和出口的漢字信息不失真。如完全采用ISO-8859-1來處理漢字也能達到正確的結果。網絡上流行的許多解決方法,都屬于這種類型。為了不致引起混淆,本文不對這種方法作討論。
3. 中文轉碼時´?´、亂碼的由來
兩個方向轉換都有可能得到錯誤的結果:
Unicode-->Byte, 如果目標代碼集不存在對應的代碼,則得到的結果是0x3f.
如:
"u00d6u00ecu00e9u0046u00bbu00f9".getBytes("GBK") 的結果是 "?ìéF?ù", Hex 值是3fa8aca8a6463fa8b4.
仔細看一下上面的結果,你會發現u00ec被轉換為0xa8ac, u00e9被轉換為xa8a6... 它的實際有效位變長了!這是因為GB2312符號區中的一些符號被映射到一些公共的符號編碼,由于這些符號出現在ISO-8859-1或其它一些SBCS字符集中,故它們在Unicode中編碼比較靠前,有一些其有效位只有8位,和漢字的編碼重疊(其實這種映射只是編碼的映射,在顯示時仔細不是一樣的。Unicode 中的符號是單字節寬,漢字中的符號是雙字節寬) . 在Unicodeu00a0--u00ff 之間這樣的符號有20個。了解這個特征非常重要!由此就不難理解為什么JAVA編程中,漢字編碼的錯誤結果中常常會出現一些亂碼(其實是符號字符), 而不全是´?´字符, 就比如上面的例子。
Byte-->Unicode, 如果Byte標識的字符在源代碼集不存在,則得到的結果是0xfffd.
如:
Byte ba[] = {(byte)0x81,(byte)0x40,(byte)0xb0,(byte)0xa1}; new String(ba,"gb2312");
結果是"?啊", hex 值是"ufffdu554a". 0x8140 是GBK字符,按GB2312轉換表沒有對應的值,取ufffd. (請注意:在顯示該uniCode時,因為沒有對應的本地字符,所以也適用上一種情況,顯示為一個"?".)
實際編程中,JSP/Servlet 程序得到錯誤的漢字信息,往往是這兩個過程的疊加,有時甚至是兩個過程疊加后反復作用的結果.
4. JSP/Servlet 漢字編碼問題及在 WAS 中的解決辦法
4.1 常見的 encoding 問題的現象
網上常出現的 JSP/Servlet encoding 問題一般都表現在 browser 或應用程序端,如:
瀏覽器中看到的 Jsp/Servlet 頁面中的漢字怎么都成了 ’?’ ?
瀏覽器中看到的 Servlet 頁面中的漢字怎么都成了亂碼?
JAVA 應用程序界面中的漢字怎么都成了方塊?
Jsp/Servlet 頁面無法顯示 GBK 漢字。
JSP 頁面中內嵌在,等Tag包含的 JAVA code 中的中文成了亂碼,但頁面的其它漢字是對的。
Jsp/Servlet 不能接收 form 提交的漢字。
JSP/Servlet 數據庫讀寫無法獲得正確的內容。
隱藏在這些問題后面的是各種錯誤的字符轉換和處理(除第3個外,是因為 Java font 設置錯誤引起的)。解決類似的字符 encoding 問題,需要了解 Jsp/Servlet 的運行過程,檢查可能出現問題的各個點。
4.2 JSP/Servlet web 編程時的 encoding 問題
運行于Java 應用服務器的 JSP/Servlet 為 Browser 提供 HTML 內容,其過程如下圖所示:
其中有字符編碼轉換的地方有:
JSP 編譯。Java 應用服務器將根據 JVM 的 file.encoding 值讀取 JSP 源文件,編譯生成 JAVA 源文件,再根據 file.encoding 值寫回文件系統。如果當前系統語言支持 GBK,那么這時候不會出現 encoding 問題。如果是英文的系統,如 LANG 是 en_US 的 Linux, AIX 或 Solaris,則要將 JVM 的 file.encoding 值置成 GBK 。系統語言如果是 GB2312,則根據需要,確定要不要設置 file.encoding,將 file.encoding 設為 GBK 可以解決潛在的 GBK 字符亂碼問題
Java 需要被編譯為 .class 才能在 JVM 中執行,這個過程存在與a.同樣的 file.encoding 問題。從這里開始 servlet 和 jsp 的運行就類似了,只不過 Servlet 的編譯不是自動進行的。對于JSP程序, 對產生的JAVA 中間文件的編譯是自動進行的(在程序中直接調用sun.tools.javac.Main類). 因此如果在這一步出現問題的話, 也要檢查encoding和OS的語言環境,或者將內嵌在JSP JAVA Code 中的靜態漢字轉為 Unicode, 要么靜態文本輸出不要放在 JAVA code 中。對于Servlet, javac 編譯時手工指定-encoding 參數就可以了。
Servlet 需要將 HTML 頁面內容轉換為 browser 可接受的 encoding 內容發送出去。依賴于各 JAVA App Server 的實現方式,有的將查詢 Browser 的 accept-charset 和 accept-language 參數或以其它猜的方式確定 encoding 值,有的則不管。因此采用固定encoding 也許是最好的解決方法。對于中文網頁,可在 JSP 或 Servlet 中設置 contentType="text/html; charset=GB2312";如果頁面中有GBK字符,則設置為contentType="text/html; charset=GBK",由于IE 和 Netscape對GBK的支持程度不一樣,作這種設置時需要測試一下。
因為16位 JAVA char在網絡傳送時高8位會被丟棄,也為了確保Servlet頁面中的漢字(包括內嵌的和servlet運行過程中得到的)是期望的內碼,可以用 PrintWriter out=res.getWriter() 取代 ServletOutputStream out=res.getOutputStream(). PrinterWriter 將根據contentType中指定的charset作轉換 (ContentType需在此之前指定!); 也可以用OutputStreamWriter封裝 ServletOutputStream 類并用write(String)輸出漢字字符串。
對于 JSP,JAVA Application Server 應當能夠確保在這個階段將嵌入的漢字正確傳送出去。
這是解釋 URL 字符 encoding 問題。如果通過 get/post 方式從 browser 返回的參數值中包含漢字信息, servlet 將無法得到正確的值。SUN的 J2SDK 中,HttpUtils.parseName 在解析參數時根本沒有考慮 browser 的語言設置,而是將得到的值按 byte 方式解析。這是網上討論得最多的 encoding 問題。因為這是設計缺陷,只能以 bin 方式重新解析得到的字符串;或者以 hack HttpUtils 類的方式解決。參考文章 2 均有介紹,不過最好將其中的中文 encoding GB2312、 CP1381 都改為 GBK,否則遇到 GBK 漢字時,還是會有問題。
Servlet API 2.3 提供一個新的函數 HttpServeletRequest.setCharacterEncoding 用于在調用 request.getParameter(“param_name”) 前指定應用程序希望的 encoding,這將有助于徹底解決這個問題。
4.3 IBM Websphere Application Server 中的解決方法
WebSphere Application Server 對標準的 Servlet API 2.x 作了擴展,提供較好的多語言支持。運行在中文的操作系統中,可以不作任何設置就可以很好地處理漢字。下面的說明只是對WAS是運行在英文的系統中,或者需要有GBK支持時有效。
上述c,d情況,WAS 都要查詢 Browser 的語言設置,在缺省狀況下, zh, zh-cn 等均被映射為 JAVA encoding CP1381(注意: CP1381 只是等同于 GB2312 的一個 codepage,沒有 GBK 支持)。這樣做我想是因為無法確認 Browser 運行的操作系統是支持GB2312, 還是 GBK,所以取其小。但是實際的應用系統還是要求頁面中出現 GBK 漢字,最著名的是朱總理名字中的“?"(rong2 ,0xe946,u9555),所以有時還是需要將 Encoding/Charset 指定為 GBK。當然 WAS 中變更缺省的 encoding 沒有上面說的那么麻煩,針對 a,b,參考文章 5,在 Application Server 的命令行參數中指定 -Dfile.encoding=GBK 即可; 針對 d,在 Application Server 的命令行參數中指定-Ddefault.client.encoding=GBK。如果指定了-Ddefault.client.encoding=GBK,那么c情況下可以不再指定charset。
上面列出的問題中還有一個關于Tag,中的 JAVA 代碼里包含的靜態文本未能正確顯示的問題,在WAS中的解決方法是除了設置正確的file.encoding, 還需要以相同方法設置-Duser.language=zh -Duser.region=CN。這與JAVA locale的設置有關。
4.4 數據庫讀寫時的 encoding 問題
JSP/Servlet 編程中經常出現 encoding 問題的另一個地方是讀寫數據庫中的數據。
流行的關系數據庫系統都支持數據庫 encoding,也就是說在創建數據庫時可以指定它自己的字符集設置,數據庫的數據以指定的編碼形式存儲。當應用程序訪問數據時,在入口和出口處都會有 encoding 轉換。對于中文數據,數據庫字符編碼的設置應當保證數據的完整性. GB2312,GBK,UTF-8 等都是可選的數據庫 encoding;也可以選擇 ISO8859-1 (8-bit),那么應用程序在寫數據之前須將 16Bit 的一個漢字或 Unicode 拆分成兩個 8-bit 的字符,讀數據之后則需將兩個字節合并起來,同時還要判別其中的 SBCS 字符。沒有充分利用數據庫 encoding 的作用,反而增加了編程的復雜度,ISO8859-1不是推薦的數據庫 encoding。JSP/Servlet編程時,可以先用數據庫管理系統提供的管理功能檢查其中的中文數據是否正確。
然后應當注意的是讀出來的數據的 encoding,JAVA 程序中一般得到的是 Unicode。寫數據時則相反。
4.5 定位問題時常用的技巧
定位中文encoding問題通常采用最笨的也是最有效的辦法??在你認為有嫌疑的程序處理后打印字符串的內碼。通過打印字符串的內碼,你可以發現什么時候中文字符被轉換成Unicode,什么時候Unicode被轉回中文內碼,什么時候一個中文字成了兩個 Unicode 字符,什么時候中文字符串被轉成了一串問號,什么時候中文字符串的高位被截掉了……
取用合適的樣本字符串也有助于區分問題的類型。如:”aa啊aa?aa” 等中英相間、GB、GBK特征字符均有的字符串。一般來說,英文字符無論怎么轉換或處理,都不會失真(如果遇到了,可以嘗試著增加連續的英文字母長度)。
5. 結束語
其實 JSP/Servlet 的中文encoding 并沒有想像的那么復雜,雖然定位和解決問題沒有定規,各種運行環境也各不盡然,但后面的原理是一樣的。了解字符集的知識是解決字符問題的基礎。不過,隨著中文字符集的變化,不僅僅是 java 編程,中文信息處理中的問題還是會存在一段時間的。
關于Servlet、Jsp中的多國語言顯示
因為一直不信Java竟會有不能混排顯示多國語言的BUG,這個周末研究了一下Servlet、Jsp的多國語言顯示的問題,也就是Servlet的多字符集問題,由于我對字符集的概念還不是很清晰所以寫出的東西未必是準確的,我是這樣理解Java中的字符集的:在運行時,每個字符串對象中存儲的都是編碼為UNICODE內碼的(我覺得所有的語言中都是有相應編碼的,因為在計算機內部字符串總是用內碼來表示的,只不過一般計算機語言中的字符串編碼時平臺相關的,而Java則采用了平臺無關的UNICODE)。
Java從一個byte流中讀取一個字符串時,將把平臺相關的byte轉變為平臺無關的Unicode字符串。在輸出時Java將把Unicode字符串轉變為平臺相關的byte流,如果某個Unicode字符在某個平臺上不存在,將會輸出一個´?´。舉個例子:在中文Windows中,Java讀出一個"GB2312"編碼的文件(可以是任何流)到內存中構造字符串對象,將會把GB2312編碼的文字轉變為Unicode編碼的字符串,如果把這個字符串輸出又將會把Unicode字符串轉化為GB2312的byte流或數組:"中文測試"----->"u4e2du6587u6d4bu8bd5"----->"中文測試"。
如下例程:
byte[] bytes = new byte[]{(byte)0xd6, (byte)0xd0, (byte)0xce, (byte)0xc4, (byte)0xb2, (byte)0xe2, (byte)0xca, (byte)0xd4};//GBK編碼的"中文測試"
java.io.ByteArrayInputStream bin = new java.io.ByteArrayInputStream(bytes);
java.io.BufferedReader reader = new java.io.BufferedReader(new java.io. InputStreamReader (bin,"GBK"));
String msg = reader.readLine();
System.out.println(msg)
這段程序放到包含"中文測試"這四個字的系統(如中文系統)中,可以正確地打印出這些字。msg字符串中包含了正確的"中文測試"的Unicode編碼:"u4e2du6587u6d4bu8bd5",打印時轉換為操作系統的默認字符集,是否可以正確顯示依賴于操作系統的字符集,只有在支持相應字符集的系統中,我們的信息才能正確的輸出,否則得到的將會是垃圾。
話入正題,我們來看看Servlet/Jsp中的多語言問題。我們的目標是,任一國家的客戶端通過Form向Server發送信息,Server把信息存入數據庫中,客戶端在檢索時仍然能夠看到自己發送的正確信息。事實上,我們要保證,最終Server中的SQL語句中保存的時包含客戶端發送文字的正確Unicode編碼;DBC與數據庫通訊時采用的編碼方式能包含客戶端發送的文字信息,事實上,最好讓JDBC直接使用UNICODE/UTF8與數據庫通訊!這樣就可以確保不會丟失信息;Server向客戶端發送的信息時也要采用不丟失信息的編碼方式,也可以是Unicode/Utf8。
如果不指定Form的Enctype屬性,Form將把輸入的內容依照當前頁面的編碼字符集urlencode之后再提交,服務器端得到是urlencoding的字符串。編碼后得到的urlencoding字符串是與頁面的編碼相關的,如gb2312編碼的頁面提交"中文測試",得到的是"%D6%D0%CE%C4%B2%E2%CA%D4",每個"%"后跟的是16進制的字符串;而在UTF8編碼時得到的卻是"%E4%B8%AD%E6%96%87%E6%B5%8B%E8%AF%95",因為GB2312編碼中一個漢字是16位的,而UTF8中一個漢字卻是24位的。中日韓三國的ie4以上瀏覽器均支持UTF8編碼,這種方案肯定包涵了這三國語言,所以我們如果讓Html頁面使用UTF8編碼那么將至少可以支持這三國語言。
但是,如果我們html/Jsp頁面使用UTF8編碼,因為應用程序服務器可能不知道這種情況,因為如果瀏覽器發送的信息不包含charset信息,至多Server知道讀到Accept-Language請求投標,我們知道僅靠這個投標是不能獲知瀏覽器所采用編碼的,所以應用程序服務器不能正確解析提交的內容,為什么?因為Java中的所有字符串都是Unicode16位編碼的,HttpServletRequest.request(String)的功能就是把客戶端提交的Urlencode編碼的信息轉為Unicode字符串,有些Server只能認為客戶端的編碼和Server平臺相同,簡單地使用URLDecoder.decode(String)方法直接解碼,如果客戶端編碼恰好和Server相同,那么就可以得到正確地字符串,否則,如果提交地字符串中包含了當地字符,那么將會導致垃圾信息。
在我提出的這個解決方案里,已經指定了采用Utf8編碼,所以,可以避免這個問題,我們可以自己定制出decode方法:
public static String decode(String s,String encoding) throws Exception {
StringBuffer sb = new StringBuffer();
for(int i=0; ichar c = s.charAt(i);
switch (c) {
case ´+´:
sb.append(´ ´);
break;
case ´%´:
try {
sb.append((char)Integer.parseInt(
s.substring(i+1,i+3),16));
}
catch (NumberFormatException e) {
throw new IllegalArgumentException();
}
i += 2;
break;
default:
sb.append(c);
break;
}
}
// Undo conversion to external encoding
String result = sb.toString();
byte[] inputBytes = result.getBytes("8859_1");
return new String(inputBytes,encoding);
}
這個方法可以指定encoding,如果把它指定為UTF8就滿足了我們的需要。比如用它解析:"%E4%B8%AD%E6%96%87%E6%B5%8B%E8%AF%95"就可以得到正確的漢字"中文測試"的Unicode字符串。
現在的問題就是我們必須得到客戶端提交的Urlencode的字符串。對于method為get的form提交的信息,可以用HttpServletRequest.getQueryString()方法讀到,而對于post方法的form提交的信息,只能從ServletInputStream中讀到,事實上標準的getParameter方法被第一次調用后,form提交的信息就被讀取出來了,而ServletInputStream是不能重復讀出的。所以我們應在第一次使用getParameter方法前讀取并解析form提交的信息。
我是這么做的,建立一個Servlet基類,覆蓋service方法,在調用父類的service方法前讀取并解析form提交的內容,請看下面的源代碼:
package com.hto.servlet;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
/**
* Insert the type´s description here.
* Creation date: (2001-2-4 15:43:46)
* @author: 錢衛春
*/
public class UTF8ParameterReader {
Hashtable pairs = new Hashtable();
/**
* UTF8ParameterReader constructor comment.
*/
public UTF8ParameterReader(HttpServletRequest request) throws java.io.IOException{
super();
parse(request.getQueryString());
parse(request.getReader().readLine());
}
/**
* UTF8ParameterReader constructor comment.
*/
public UTF8ParameterReader(HttpServletRequest request,String encoding) throws java.io.IOException{
super();
parse(request.getQueryString(),encoding);
parse(request.getReader().readLine(),encoding);
}
public static String decode(String s) throws Exception {
StringBuffer sb = new StringBuffer();
for(int i=0; ichar c = s.charAt(i);
switch (c) {
case ´+´:
sb.append(´ ´);
break;
case ´%´:
try {
sb.append((char)Integer.parseInt(
s.substring(i+1,i+3),16));
}
catch (NumberFormatException e) {
throw new IllegalArgumentException();
}
i += 2;
break;
default:
sb.append(c);
break;
}
}
// Undo conversion to external encoding
String result = sb.toString();
byte[] inputBytes = result.getBytes("8859_1");
return new String(inputBytes,"UTF8");
}
public static String decode(String s,String encoding) throws Exception {
StringBuffer sb = new StringBuffer();
for(int i=0; ichar c = s.charAt(i);
switch (c) {
case ´+´:
sb.append(´ ´);
break;
case ´%´:
try {
sb.append((char)Integer.parseInt(
s.substring(i+1,i+3),16));
}
catch (NumberFormatException e) {
throw new IllegalArgumentException();
}
i += 2;
break;
default:
sb.append(c);
break;
}
}
// Undo conversion to external encoding
String result = sb.toString();
byte[] inputBytes = result.getBytes("8859_1");
return new String(inputBytes,encoding);
}
/**
* Insert the method´s description here.
* Creation date: (2001-2-4 17:30:59)
* @return java.lang.String
* @param name java.lang.String
*/
public String getParameter(String name) {
if (pairs == null || !pairs.containsKey(name)) return null;
return (String)(((ArrayList) pairs.get(name)).get(0));
}
/**
* Insert the method´s description here.
* Creation date: (2001-2-4 17:28:17)
* @return java.util.Enumeration
*/
public Enumeration getParameterNames() {
if (pairs == null) return null;
return pairs.keys();
}
/**
* Insert the method´s description here.
* Creation date: (2001-2-4 17:33:40)
* @return java.lang.String[]
* @param name java.lang.String
*/
public String[] getParameterValues(String name) {
if (pairs == null || !pairs.containsKey(name)) return null;
ArrayList al = (ArrayList) pairs.get(name);
String[] values = new String[al.size()];
for(int i=0;ireturn values;
}
/**
* Insert the method´s description here.
* Creation date: (2001-2-4 20:34:37)
* @param urlenc java.lang.String
*/
private void parse(String urlenc) throws java.io.IOException{
if (urlenc == null) return;
StringTokenizer tok = new StringTokenizer(urlenc,"&");
try{
while (tok.hasMoreTokens()){
String aPair = tok.nextToken();
int pos = aPair.indexOf("=");
String name = null;
String value = null;
if(pos != -1){
name = decode(aPair.substring(0,pos));
value = decode(aPair.substring(pos+1));
}else{
name = aPair;
value = "";
}
if(pairs.containsKey(name)){
ArrayList values = (ArrayList)pairs.get(name);
values.add(value);
}else{
ArrayList values = new ArrayList();
values.add(value);
pairs.put(name,values);
}
}
}catch(Exception e){
throw new java.io.IOException(e.getMessage());
}
}
/**
* Insert the method´s description here.
* Creation date: (2001-2-4 20:34:37)
* @param urlenc java.lang.String
*/
private void parse(String urlenc,String encoding) throws java.io.IOException{
if (urlenc == null) return;
StringTokenizer tok = new StringTokenizer(urlenc,"&");
try{
while (tok.hasMoreTokens()){
String aPair = tok.nextToken();
int pos = aPair.indexOf("=");
String name = null;
String value = null;
if(pos != -1){
name = decode(aPair.substring(0,pos),encoding);
value = decode(aPair.substring(pos+1),encoding);
}else{
name = aPair;
value = "";
}
if(pairs.containsKey(name)){
ArrayList values = (ArrayList)pairs.get(name);
values.add(value);
}else{
ArrayList values = new ArrayList();
values.add(value);
pairs.put(name,values);
}
}
}catch(Exception e){
throw new java.io.IOException(e.getMessage());
}
}
}
這個類的功能就是讀取并保存form提交的信息,并實現常用的getParameter方法。
package com.hto.servlet;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
/**
* Insert the type´s description here.
* Creation date: (2001-2-5 8:28:20)
* @author: 錢衛春
*/
public class UtfBaseServlet extends HttpServlet {
public static final String PARAMS_ATTR_NAME = "PARAMS_ATTR_NAME";
/**
* Process incoming HTTP GET requests
*
* @param request Object that encapsulates the request to the servlet
* @param response Object that encapsulates the response from the servlet
*/
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
performTask(request, response);
}
/**
* Process incoming HTTP POST requests
*
* @param request Object that encapsulates the request to the servlet
* @param response Object that encapsulates the response from the servlet
*/
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
performTask(request, response);
}
/**
* Insert the method´s description here.
* Creation date: (2001-2-5 8:52:43)
* @return int
* @param request javax.servlet.http.HttpServletRequest
* @param name java.lang.String
* @param required boolean
* @param defValue int
*/
public static java.sql.Date getDateParameter(HttpServletRequest request, String name, boolean required, java.sql.Date defValue) throws ServletException{
String value = getParameter(request,name,required,String.valueOf(defValue));
return java.sql.Date.valueOf(value);
}
/**
* Insert the method´s description here.
* Creation date: (2001-2-5 8:52:43)
* @return int
* @param request javax.servlet.http.HttpServletRequest
* @param name java.lang.String
* @param required boolean
* @param defValue int
*/
public static double getDoubleParameter(HttpServletRequest request, String name, boolean required, double defValue) throws ServletException{
String value = getParameter(request,name,required,String.valueOf(defValue));
return Double.parseDouble(value);
}
/**
* Insert the method´s description here.
* Creation date: (2001-2-5 8:52:43)
* @return int
* @param request javax.servlet.http.HttpServletRequest
* @param name java.lang.String
* @param required boolean
* @param defValue int
*/
public static float getFloatParameter(HttpServletRequest request, String name, boolean required, float defValue) throws ServletException{
String value = getParameter(request,name,required,String.valueOf(defValue));
return Float.parseFloat(value);
}
/**
* Insert the method´s description here.
* Creation date: (2001-2-5 8:52:43)
* @return int
* @param request javax.servlet.http.HttpServletRequest
* @param name java.lang.String
* @param required boolean
* @param defValue int
*/
public static int getIntParameter(HttpServletRequest request, String name, boolean required, int defValue) throws ServletException{
String value = getParameter(request,name,required,String.valueOf(defValue));
return Integer.parseInt(value);
}
/**
* Insert the method´s description here.
* Creation date: (2001-2-5 8:43:36)
* @return java.lang.String
* @param request javax.servlet.http.HttpServletRequest
* @param name java.lang.String
* @param required boolean
* @param defValue java.lang.String
*/
public static String getParameter(HttpServletRequest request, String name, boolean required, String defValue) throws ServletException{
if(request.getAttribute(UtfBaseServlet.PARAMS_ATTR_NAME) != null) {
UTF8ParameterReader params = (UTF8ParameterReader)request.getAttribute(UtfBaseServlet.PARAMS_ATTR_NAME);
if (params.getParameter(name) != null) return params.getParameter(name);
if (required) throw new ServletException("The Parameter "+name+" Required but not provided!");
else return defValue;
}else{
if (request.getParameter(name) != null) return request.getParameter(name);
if (required) throw new ServletException("The Parameter "+name+" Required but not provided!");
else return defValue;
}
}
/**
* Returns the servlet info string.
*/
public String getServletInfo() {
return super.getServletInfo();
}
/**
* Insert the method´s description here.
* Creation date: (2001-2-5 8:52:43)
* @return int
* @param request javax.servlet.http.HttpServletRequest
* @param name java.lang.String
* @param required boolean
* @param defValue int
*/
public static java.sql.Timestamp getTimestampParameter(HttpServletRequest request, String name, boolean required, java.sql.Timestamp defValue) throws ServletException{
String value = getParameter(request,name,required,String.valueOf(defValue));
return java.sql.Timestamp.valueOf(value);
}
/**
* Initializes the servlet.
*/
public void init() {
// insert code to initialize the servlet here
}
/**
* Process incoming requests for information
*
* @param request Object that encapsulates the request to the servlet
* @param response Object that encapsulates the response from the servlet
*/
public void performTask(HttpServletRequest request, HttpServletResponse response) {
try
{
// Insert user code from here.
}
catch(Throwable theException)
{
// uncomment the following line when unexpected exceptions
// are occuring to aid in debugging the problem.
//theException.printStackTrace();
}
}
/**
* Insert the method´s description here.
* Creation date: (2001-2-5 8:31:54)
* @param request javax.servlet.ServletRequest
* @param response javax.servlet.ServletResponse
* @exception javax.servlet.ServletException The exception description.
* @exception java.io.IOException The exception description.
*/
public void service(ServletRequest request, ServletResponse response) throws javax.servlet.ServletException, java.io.IOException {
String content = request.getContentType();
if(content == null || content != null && content.toLowerCase().startsWith("application/x-www-form-urlencoded"))
request.setAttribute(PARAMS_ATTR_NAME,new UTF8ParameterReader((HttpServletRequest)request));
super.service(request,response);
}
}
這個就是Servlet基類,它覆蓋了父類的service方法,在調用父類service前,創建了UTF8ParameterReader對象,其中保存了form中提交的信息。然后把這個對象作為一個Attribute保存到Request對象中。然后照樣調用父類的service方法。
對于繼承這個類的Servlet,要注意的是,"標準"getParameter在也不能讀到post的數據,因為在這之前這個類中已經從ServletInputStream中讀出了數據了。所以應該使用該類中提供的getParameter方法。
剩下的就是輸出問題了,我們要把輸出的信息,轉為UTF8的二進制流輸出。只要我們設置Content-Type時指定charset為UTF8,然后使用PrintWriter輸出,那么這些轉換是自動進行的,Servlet中這樣設置:
response.setContentType("text/html;charset=UTF8");
Jsp中這樣設置:
這樣就可以保證輸出是UTF8流,客戶端能否顯示,就看客戶端的了。
對于multipart/form-data的form提交的內容,我也提供一個類用來處理,在這個類的構造子中可以指定頁面使用的charset,默認還是UTF-8,限于篇幅不貼出源碼。
在Jsp程序解決向DB讀取或寫入時的亂碼問題
在基于JAVA的編程中,經常會碰到漢字的處里及顯示的問題,比如一大堆亂碼或問號。
這是因為JAVA中默認的編碼方式是UNICODE,而中國人通常使用的文件和DB都是基于GB2312或者BIG5等編碼,故會出現此問題。以前我也經常為這個問題而苦惱,后來經查了些資料,終于解決了,我知道一定有很多朋友也會碰到這個問題,所以特就總結了一下,來拿出來讓大家一起分享了。
1、在網頁中輸出中文。
JAVA在網絡傳輸中使用的編碼是"ISO-8859-1",故在輸出時需要進行轉化,如:
String str="中文";
str=new String(str.getBytes("GB2312"),"8859_1");
但如果在編譯程序時,使用的編碼是“GB2312”,且在中文平臺上運行此程序,不會出現此問題,一定要注意。
2、從參數中讀取中文
這正好與在網頁中輸出相反如:
str=new String(str.getBytes("8859_1"),"GB2312");
3、操作DB中的中文問題
一個較簡單的方法是:在“控制面扳”中,把“區域”設置為“英語(美國)”。如果還會出現亂碼,還可進行如下設置:
取中文時:str=new String(str.getBytes("GB2312"));
向DB中輸入中文:str=new String(str.getBytes("ISO-8859-1"));
4、在JSP中的中文解決:
在“控制面扳”中,把“區域”設置為“英語(美國)”.
在JSP頁面中加入:
如果還不行正常顯示,則還要進行下面的轉換:
如:name=new String(name.getBytes("ISO-8859-1"),"GBK");
就不會出現中文問題了。
Tomcat中Java/jsp中文問題完全解決方案
Tomcat 3.23以下的版本
對于Tomcat 3.23以下版本,Java中的中文問題網上已經談了不少,一般遇到中文問題使用轉換函數轉換.toChinese()
public static String toChinese(String strvalue)
{
try{
if(strvalue==null)
return null;
else
{
strvalue = new String(strvalue.getBytes("ISO8859_1"), "GBK");
return strvalue;
}
}catch(Exception e){
return null;
}
}
凡是涉及中文字符串,如從數據庫中讀取中文字符串,或變量名賦值時,使用toChinese函數:
toChinese("這是中文字符串")
注:該辦法在使用javamail發送中文信息時似乎有問題
Tomcat 4.0以上的版本
在4.0以后的版本,已經不需要象3.23版本中使用字符轉換函數:
(1)編譯javabean時 javac 命令行加上-encoding ISO8859_1
(2)在Jsp頭部中加入
是不是很簡單? 使用本辦法基本可以對付實際應用,推薦!
但也有一個缺點是,通過form表單get參數;或在url后附帶中文,這個辦法就失效,我相信應該有辦法解決.
該辦法原理就是在java的各個環節統一編碼為:ISO8859_1.
修改tomcat
該辦法是一位網友在論壇貼出的,我沒有試驗,轉載于此:
只要修改一個地方就行了,文件為:
tomcat4/src/catalina/src/share/org/apache/catalina/connector/HttpReque
stBase.java
找到protected void parseParameters()方法,把
if (encoding == null)
encoding = "ISO-8859-1";
改為
if (encoding == null)
encoding = "GBK";
編譯:
解開jakarta-servletapi-4的原碼包,找到servlet.jar文件設置到CLASSPATH
找到tomcat4.0.1的bin包將catalina.jar設置到CLASSPATH.
因為編譯時要使用這些api.
然后javac HttpRequestBase.java生成兩個class文件.
解開catalina.jar jar xvf catalina.jar(tomcat bin包中的)
覆蓋調原來的兩個class文件:
jar cvf catalina.jar org
即可
重啟tomcat4,一切OK!,你再也不用編寫煩人的編碼轉換了。
jsp中框架頁面請求中的中文編碼問題
最近有這么一個需求,一個主頁面從request中拿到請求的參數(中文),主頁面里有兩個Frame,每個Frame嵌著一個jsp,如何把主頁面中得到的中文參數值傳入Frame里去呢,后來發現應該先把中文編碼成unicode,然后傳給frame中的jsp,frame中的jsp再解碼,程序清單如下:index.jsp
========================================================
String flowname = request.getParameter("flowname");
% >
業務相關資料
" name="topFrame" frameborder="1" scrolling="auto" noresize >
assetlist.jsp
========================================================
String cond ="flowname = '"+ request.getParameter("flowname")+"'";
// out.println(cond);
HttpSession sess = request.getSession();
int allpage = 0;//頁數
String pageNo = request.getParameter("pageNo");
//pageNo為null,則賦值為1
if(pageNo==null){
pageNo="1";
sess.setAttribute("flowname",cond);
}
else{
cond = (String)sess.getAttribute("flowname");
// out.println(cond);
}
int p = Integer.parseInt(pageNo);//當前頁
ArrayList al = new ArrayList();
int size=0;
try{
DAMInterfaceApp dapp = new DAMInterfaceApp();
Verify ver = new Verify(dapp);
ver.login("admin","admin");
QueryAssetExt quExt = QueryAssetExt.getInstance(dapp);
String strQueryResult = "";
try
{
strQueryResult = quExt.queryAllAssets(150,cond, "", "", 0);
}
catch(Exception qe)
{
System.err.print("錯誤:調用博思查詢接口QueryAssetExt.queryAllAssets出錯,錯誤信息為:"+qe.getMessage());
}
//對得到的查詢結果進行解析
//System.out.println("提示:查詢結果為: "+strQueryResult);
al = (ArrayList)QueryAssetAdapter.getQueryAssets(strQueryResult);
allpage = PageUtil.getAllpage(al);
//out.println(allpage);
al = PageUtil.getPageItems(al,p);
size = al.size();
//out.println(size);
}
catch(Exception e){
e.printStackTrace();
}
% >
html >
業務相關資料
/css/csstop.css" rel="stylesheet" type="text/css" >
/css/link_sty.css" rel="stylesheet" type="text/css" >
var swd = null;
function selected(t)
{
if(swd!=null)
swd.className = "";
if(t==swd)
{
swd = null;
return;
}
t.className = "xz";
swd=t;
submit();
}
function submit()
{
document.frmAssets.assetid.value = swd.id;
document.frmAssets.submit();
}
#Table1 tr{ cursor:hand; }
.xz { color: #FFFFFF; background-color: #66CCCC; }
業務相關資料
標題
業務名稱
處室
聯系人
聯系電話
版本
for(int j=0;j
"??>
共??頁
首頁
int ii = 0;
if(p>1){
ii = p - 1;
}
% >
" >上一頁
if(p}
else if(p==allpage){
ii = p;
}
% >
">下一頁
">末頁
編碼解碼的java程序Escape.java
========================================================
package gov.police.tech.application.appdata;
public class Escape {
private final static String[] hex = { "00", "01", "02", "03", "04", "05",
"06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F", "10",
"11", "12", "13", "14", "15", "16", "17", "18", "19", "1A", "1B",
"1C", "1D", "1E", "1F", "20", "21", "22", "23", "24", "25", "26",
"27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F", "30", "31",
"32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B", "3C",
"3D", "3E", "3F", "40", "41", "42", "43", "44", "45", "46", "47",
"48", "49", "4A", "4B", "4C", "4D", "4E", "4F", "50", "51", "52",
"53", "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D",
"5E", "5F", "60", "61", "62", "63", "64", "65", "66", "67", "68",
"69", "6A", "6B", "6C", "6D", "6E", "6F", "70", "71", "72", "73",
"74", "75", "76", "77", "78", "79", "7A", "7B", "7C", "7D", "7E",
"7F", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89",
"8A", "8B", "8C", "8D", "8E", "8F", "90", "91", "92", "93", "94",
"95", "96", "97", "98", "99", "9A", "9B", "9C", "9D", "9E", "9F",
"A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "AA",
"AB", "AC", "AD", "AE", "AF", "B0", "B1", "B2", "B3", "B4", "B5",
"B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF", "C0",
"C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB",
"CC", "CD", "CE", "CF", "D0", "D1", "D2", "D3", "D4", "D5", "D6",
"D7", "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF", "E0", "E1",
"E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC",
"ED", "EE", "EF", "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7",
"F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF" };
private final static byte[] val = { 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x01,
0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F };
/**
* 編碼
*
* @param s
* @return
*/
public static String escape(String s) {
StringBuffer sbuf = new StringBuffer();
int len = s.length();
for (int i = 0; i int ch = s.charAt(i);
if ('A' sbuf.append((char) ch);
} else if ('a' sbuf.append((char) ch);
} else if ('0' sbuf.append((char) ch);
} else if (ch == '-' || ch == '_' // unreserved : as it was
|| ch == '.' || ch == '!' || ch == '~' || ch == '*'
|| ch == '\'' || ch == '(' || ch == ')') {
sbuf.append((char) ch);
} else if (ch sbuf.append('%');
sbuf.append(hex[ch]);
} else { // unicode : map to %uXXXX
sbuf.append('%');
sbuf.append('u');
sbuf.append(hex[(ch >>> 8)]);
sbuf.append(hex[(0x00FF & ch)]);
}
}
return sbuf.toString();
}
/**
* 解碼 說明:本方法保證 不論參數s是否經過escape()編碼,均能得到正確的“解碼”結果
*
* @param s
* @return
*/
public static String unescape(String s) {
StringBuffer sbuf = new StringBuffer();
int i = 0;
int len = s.length();
while (i int ch = s.charAt(i);
if ('A' sbuf.append((char) ch);
} else if ('a' sbuf.append((char) ch);
} else if ('0' sbuf.append((char) ch);
} else if (ch == '-' || ch == '_' // unreserved : as it was
|| ch == '.' || ch == '!' || ch == '~' || ch == '*'
|| ch == '\'' || ch == '(' || ch == ')') {
sbuf.append((char) ch);
} else if (ch == '%') {
int cint = 0;
if ('u' != s.charAt(i + 1)) { // %XX : map to ascii(XX)
cint = (cint cint = (cint i += 2;
} else { // %uXXXX : map to unicode(XXXX)
cint = (cint cint = (cint cint = (cint cint = (cint i += 5;
}
sbuf.append((char) cint);
} else { // 對應的字符未經過編碼
sbuf.append((char) ch);
}
i++;
}
return sbuf.toString();
}
public static void main(String[] args) {
String stest = "中文1234 abcd[](),.~\\";
System.out.println(stest);
System.out.println(escape(stest));
System.out.println(unescape(escape(stest)));
}
}
用filter來解決Struts中文亂碼的問題
filter的用法,的確是比較有擴展性的一種方法...可以通過filter結合讀取web.xml中的filter參數來完成一系列的動作,做法如下:
首先,實現javax.servlet.Filter接口,編寫一個處理request編碼的過濾器類...
package tutorial.struts.filter;
import javax.servlet.Filter;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.FilterChain;
import java.io.IOException;
public class SetCharacterEncodingFilter implements Filter {
??protected FilterConfig filterConfig;
??protected String encodingName;
??protected boolean enable;
??public SetCharacterEncodingFilter() {
? ? this.encodingName = "UTF-8";
? ? this.enable = false;
??}
??public void init(FilterConfig filterConfig) throws ServletException {
? ? this.filterConfig = filterConfig;
? ? loadConfigParams();
??}
??private void loadConfigParams() {
? ? //encoding
? ? this.encodingName = this.filterConfig.getInitParameter("encoding");
? ? //filter enable flag...
? ? String strIgnoreFlag = this.filterConfig.getInitParameter("enable");
? ? if (strIgnoreFlag.equalsIgnoreCase("true")) {
? ?? ?this.enable = true;
? ? } else {
? ?? ?this.enable = false;
? ? }
??}
??public void doFilter(ServletRequest request, ServletResponse response,
? ?? ?? ?? ?? ?? ?? ???FilterChain chain) throws IOException, ServletException {
? ? if(this.enable) {
? ?? ?request.setCharacterEncoding(this.encodingName);
? ? }
? ? chain.doFilter(request, response);
??}
??public void destroy() {
??}
}
然后,需要在web.xml中注冊我們的過濾器類:
< filter >
? ? < filter-name >Set Character Encoding< /filter-name >
? ? < filter-class >tutorial.struts.filter.SetCharacterEncodingFilter< /filter-class >
? ? < init-param >
? ?? ?< param-name >encoding< /param-name >
? ?? ?< param-value >UTF-8< /param-value >
? ? < /init-param >
? ? < init-param >
? ?? ?< param-name >enable< /param-name >
? ?? ?< param-value >true< /param-value >
? ? < /init-param >
??< /filter >
??< filter-mapping >
? ? < filter-name >Set Character Encoding< /filter-name >
? ? < servlet-name >Action Servlet< /servlet-name >
??< /filter-mapping >
??< filter-mapping >
? ? < filter-name >Set Character Encoding< /filter-name >
? ? < servlet-name >Faces Servlet< /servlet-name >
??< /filter-mapping >
這樣,任何通過Struts,或是JSF的Controller Servlet處理的request,都會在過濾器中先行處理,才把控制權交還給Struts或是JSF,而且Filter中有一個Process Chain的概念,是一個很吸引人的東東~~!
J2EE WEB-Tomcat5.5.9中文問題解決方案
1、html
無論是獨立的html,還是其他程序生成的,如Servlet等,注意在最終的html的和之間必須加入meta標簽,用來指定html中輸入字符的編碼,如:
測試GET && POST-Send
2、jsp和servlet
首先必須解決程序輸出(如response.writeln(String s))和接受從客戶端傳來的數據(如request.getParameter(String sname))編碼問題,我們可以利用文件過濾功能,具體需要所用的jsp/servlet容器或者服務器提供的功能設置,如在Tomcat5.5.9中可以在webapps/yourAppDirectory/WEB-INF/web.xml中設置如下:
SetCharsetEncodingFilter
SetCharsetEncodingFilter
Set CharsetEncoding Filter
com.gg.comm.web.SetCharsetEncodingFilter
??
encoding
gb2312
??
SetCharsetEncodingFilter
/*
其中SetCharsetEncodingFilter Class就是用來設置request和reponse字符編碼的filter類,其中設置語句如下:
request.setCharacterEncoding(targetEncoding);
response.setContentType("text/html");
response.setCharacterEncoding(targetEncoding);
另外為了解決通過get(url中帶有參數)方式傳遞參數的亂碼問題,我們還需要設置一下url傳遞參數所需要的編碼,具體在Tomcat5.5.9中可以在${Tomcat_home}\conf\server.xml中的和之間設置,如下:
URIEncoding="GBK":Force GET method String(Chinese) can be transferd properly by http:uri
note:Tomcat only support GBK specification,so not set charset gb2312
-- >
最后為了解決jsp的亂碼問題,我們還需要作如下處理,即在左右的jsp頭均加上如下指令:
或者
3、jdbc和數據庫
關于寫入數據庫和讀取數據庫數據的亂碼問題,可以通過如下方式輕松解決:
對于JAVA程序的處理方法按我們指定的方法處理。
把數據庫默認支持的編碼格式改為GBK或GB2312的。
到此,一般來說對于WEB方式的應用來說,中文問題就可以解決了。當然以上方法是根據統一編碼的原則解決的以及WEB方式的文件轉換關系
(file->class->load->execute or transfered or response or request)來做的。
網友評論
定義三個類,A,B,C。在A中申明一個Button變量button1,在B再申明Button變量button2,把A中的變量button1賦給button2? ? 在C中再申明一個Button變量button3,把給B中的變量button2賦給button3,為什么在C中button1就不等于button3
2007-03-19 15:06:29
賽迪網友
不錯,比較全面,值得收藏~
2007-02-12 03:48:12
DIY
Java Programmer群號:18615413 技術聯盟-軟件交流! 歡迎任何熱愛JAVA的人進群切磋 !
本文來自ChinaUnix博客,如果查看原文請點:http://blog.chinaunix.net/u1/44781/showart_352828.html
總結
以上是生活随笔為你收集整理的JSP中文问题解决方案的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Iphone手机数据恢复软件
- 下一篇: gradle idea java ssm