您好,登錄后才能下訂單哦!
這篇文章給大家分享的是有關J2EE Web組件中中文及相關問題的示例分析的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。
XML:namespace prefix = o ns = "urn:schemas-microsoft-com:Office:office" />
三、 向服務器發送中文
雖然大家一般都不用JSP甚至servlet來處理處理客戶提交的數據或訪問請求參數,但JSP的使用或更新總是比Servlet或 JavaBean來得方便(至少在tomcat 4.0.4中是如此,因為我們常常不得不為修改了Servlet或JavaBean而重啟服務器),所以在這里我們還是要用JSP來訪問請求參數了。
不管是在JSP還是在Servlet中,我們都是用ServletRequest(或其子類)的方法getParameter(String name)來訪問請求參數的,這個方法返回的是String,也就是說我們能得到的是已經對Inte.NET傳來的字節流解碼所得的字符串。如果服務器能對這些字節流進行正確的解碼,那將是件完美的事。其實說來也很簡單,要做到這一點只需要服務器知道這些字節流在客戶端是用什么編碼進行編碼也就行了。如圖 2-17我們希望decoding==encoding。
圖 3-1 數據從瀏覽器到服務器
可理想與現實往往是沒有交集的,我們怎么也不能讓服務器知道這些字節到底是用什么編碼被編碼的,即使在萬維網相關技術的主要設計組織w3c(World Wide web Consortium)的《HTML 4.01 Specification》和Internet工程任務組(Internet Engineering Task Force, IETF)定義HTTP1.1的rfc2616(《Hypertext Transfer Protocol -- HTTP/1.1》)中也沒有發現有什么相關的推薦辦法,能在現有的瀏覽器和HTML Web頁下讓服務器知道這個編碼是什么(如果你知道該怎么做,一定請記得告訴我),所以在缺省情況下,Tomcat 4.0.4又一廂情愿的用起了ISO8859-1來對客戶端提交的數據進行解碼。如圖 2-17,decoding=ISO8859-1,可如果encoding!=ISO8859-1呢,很明顯這就是一個數據錯誤傳輸了。注意,我們這里所講的數據,僅僅是客戶端給服務器發送的數據中的實體(Entity Body)中的數據。
1. 誰決定了Encoding
誰決定了瀏覽器的當前Web頁通過Form向Internet(最終的對象當然是服務器)發送數據字節流的編碼呢?當然是瀏覽器了。那瀏覽器又是靠什么決定這個編碼的呢?那是繼承的瀏覽器解碼當前頁(它當然也要對當前Web頁解碼了,別忘了任何文件或Internet上的元數據都是字節)所使用的decoding了,其實說是繼承也不全對,后面你就會發現的。
2. 靠什么決定了Encoding
大約是這六個方面來的信息使瀏覽器決定用什么encoding:
1) xsl所決定的
2) 實體(Entity Body)中的特殊標記
3) 用戶手動對該Web頁設置的decoding
4) 響應頭(Response Header Field)中的Content-Type
5) HTML元素META中的charset
6) 瀏覽器以前所用的decoding
它們的優先級可能會因為瀏覽器的不同而不同,但在IE6.0中是遞減的,微軟這種做法確實曖昧、耐人尋味,難怪它會在瀏覽器大戰中取得勝利。下面僅對這六點一一解釋。
XSL(eXtensible Stylesheet Language, 可擴展樣式單語言)可以方便地將XML(eXtensible Markup Language, 可擴展標記語言)轉換為其他很多種內容,我們這里只關心它把XML轉換為HTML,而對瀏覽器編碼設置的影響。如果該XSL遵循 W3C在1998年發布的有關XSL的第一個工作草案標準(設置XSL文件中的xmlns:xsl="http://www.w3.org/TR/WD-xsl"),則可以通過在XSL中添加元素meta,并作相類似的設置達到設置瀏覽器編碼的目的:
如果該XSL是事實上的XSLT(eXtensible Stylesheet Language Transformation, 可擴展樣式單轉換語言),即xmlns:xsl=”http://www.w3.org/1999/XSL/Transform”,則瀏覽器編碼無條件使用UTF=16,即使在XSL文件中添加meta元素來設置編碼都將被忽略。
實體是指服務器給瀏覽器返回的數據中的實體,也可以簡單理解為返回數據中除附加頭和空白行之外的所有數據。在前面說過,windows 2000 Server(我實驗所用的操作系統)會在以UTF-8編碼的文件前加三個流氓字節(0xEF0xBB0xBF),如果當前Web頁是靜態資源,則服務器會不加任何處理直接把這個Web 頁返回到客戶端,如果這個靜態Web頁也是在Windows 2000 Server中生成的話,那么實體的最初三個字節將是0xEF0xBB0xBF,瀏覽器很快檢測到這三個字節,于是就用UTF-8對正確解碼,后面那四點都會被忽略。
手動設置decoding就是在瀏覽器窗口中對編碼進行設置,這是明確的告訴瀏覽器該Web頁應該使用的編碼,用戶永遠是對的。
Tomcat 4.0.4是不會在返回靜態Web頁設置響應頭中的Content-Type,我們在JSP中所使用的:
<%@ page="" contenttype="text/html;charset=gb2312">
或在Servlet中使用的:
response.setContentType(“text/html;charset=gb21312”);
就是對響應頭(Response Header)中的Content-Type的設置,它的值遵循MIME(Multipurpose Internet Mail Extension protocol, 多用途的網際郵件擴充協議)規范,如圖 3-2,請求JSP頁面http://localhost/scqdac/t.jsp在客戶端收到的所有數據,0x7d是實體中有效數據的長度。
圖3-2服務器通過http協議返回給瀏覽器的所有數據
由圖中可以看出,響應頭中的Content-Type與HTML中的meta的Content-Type完全無關,這是可以理解的。t.jsp的所有源代碼如下:
<%@ page="" contenttype="text/html;charset=gb2312">
JSP文件中的
。
已經沒有什么意義了,沒有誰會去理會它。關于響應頭中的Content-Type,RFC2616中有詳細的定義和說明,請參閱:http://www.ietf.org/rfc/rfc2616.txt。
我們也可以通過設置Web頁中的HTML元素meta來達到設置Web頁編碼的目的:
關于HTML文檔的字符集(Document Character Set)請參閱《HTML 4.01 Specification》,http://www.w3c.org/TR/html401/html401.html(你同時還可以了解到HTML元素form的屬性enctype的設置以及它的作用)。
如果實在找不到charset及相關的信息,瀏覽器就使用最近一次使用過的編碼。
在前面提到了瀏覽器的編碼并不完全繼承于decoding,當解碼Web頁面所使用的decoding是UTF-16時,向服務器發送數據的實體還是使用UTF-8,至少在IE6.0的默認設置下是如此的。還有一個有趣的就是當encoding=ISO8859-1時,請求頭(Request Header Field)
Content-Type:application/x-www-form-urlencoded
時,通過Form向服務器發送數據“我是中國人”(name=”text”)時,被編碼成:
%26%2325105%3B%26%2326159%3B%26%2320013%3B%26%2322269%3B%
26%2320154%3B
這的確是一種有趣的編碼方式,我們略加分析就可以發現這個轉義字符串就是
我是中國人
那么在服務器端我們通過
request.getParameter(“text”);
所得到的字符串也將是”我是中國人”,這明顯是SGML(Standard Generalized Markup Language, 標準通用標記語言)所采用的實體字符嘛,HTML當然也就能很好地處理它了,所以如果form屬性action所對應的JSP中有:
<%=request.getparameter(“text”)%>
那么瀏覽器將重現“我是中國人”。所以我們可以由得它,當然也可以很容易地處理它,畢竟它是標準的東西。
3. 把字節串還給我們
服務器在沒有得到我們的通知的情況下,自我主張地執行了類似
String str = new String(bytes,”ISO8859-1”);
的操作,而且還不讓我們能夠直接獲得客戶傳輸的字節串(Servlet api中沒有這個方法)。但我們還是可以讓ServletRequest把字節串還給我們,那就是執行它的逆運算,用ISO8859-1編碼:
String str = request.getParameter(“text”);
byte bs[] = str.getBytes(“ISO8859-1”);
這時所得的bs,我們有足夠的理由相信它完全就是客戶端發給服務器的,因為用ISO8859-1對字節流解碼,是不會失真的,它得到的字符串,所有的字符高位字節都等于0,也就是說用ISO8859-1對它編碼,也不會丟失數據,我們將得到本來的字節串。
4. 重新解碼
只要我們對這些字節串用正確的編碼重新解碼,我們將得到客戶提交的真實字符,也許它們和客戶端的字符的內碼不同,但絕對是相同的字符。
String str = request.getParameter(“text”);
byte bs[] = str.getBytes(“ISO8859-1”);
String text = new String(bs, ”GBK”);
當然最簡單和有效的莫過于:
request.setCharacterEncoding(“GBK”);
String text = request.getParameter(“text”);
有時我們在學習中沒有使用String的第二個參數,直接使用
String text = new String(bs);
其實是我們系統的缺省編碼是GBK,而String正是引用了這個缺省編碼。
也許在這個時候,我們才真正地感覺到,如果能夠知道客戶端瀏覽器使用了什么編碼,那將是多么愉快的事,可是我們不能。不要指望ServletRequest.getCharacterEncoding()能給你帶來什么,如果沒有在服務器端明確使用ServletRequest對象的方法:setCharacterEncoding(String encoding)設置該對象所描述的請求中的數據的編碼,那么該對象的getCharacterEncoding()將返回null,而我們認為的完美組合:
request.setCharacterEncoding(request. getCharacterEncoding());
不管getCharacterEncoding()有沒有幫助,都是沒有意義的——你本就是從我這里知道的,我還用得著你告訴我么。
既然決定瀏覽器編碼的六種方法中,有三種都可以被服務器所使用(但我們的確不屑于用第一種方法,盡管在IE面前它是最有效的)。如果向服務器提交數據的表單是包含在一個靜態Web頁面中的,那么我們就設置HTML元素meta的屬性,如果該表單是包含在JSP的,我們就設置page指令中的contentType。那么在處理該表單所提交的數據時,我們可以用相應的編碼對字節串重解碼。但不要大意,這種方法并不是可完全信任的,因為我們的用戶可能使用了六種方法中的第二種方法重置了瀏覽器的編碼,幸運的是如果Web頁中的不是所有的信息都是英文字符的話,用戶還是不會無聊地執行這種非法操作,除非他真的想得到亂碼。
感謝各位的閱讀!關于“J2EE Web組件中中文及相關問題的示例分析”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。