熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> JSP教程 >> 正文

如何解決JSP參數傳遞亂碼

2013-11-15 11:34:45  來源: JSP教程 

  計算機生於美國英語是他的母語而英語以外的其它語言對他來說都是外語他跟我們一樣不管外語掌握到什麼程度也不會像母語那樣使用得那麼好時常也會出一些“拼寫錯誤”問題

  亂碼的出現根本原因在於編碼和解碼使用了不同的編碼方案比如用GBK編碼的文件用UTF去解碼結果肯定都是火星文所以要解決這個問題中心思想就在於使用統一的編碼方案

  jsp頁面間的參數傳遞有以下幾種方式表單(form)的提交直接使用URL後接參數的形式(超級鏈接)如果兩個jsp頁面在兩個不同的窗口中並且這兩個窗口是父子的關系子窗口中的jsp也可以使用javascript和DOM(windowopenerXXXvalue)來取得父窗口中的jsp的輸入元素的值下面就前兩種方式中出現的亂碼問題做一下剖析

  表單(form)的提交實現參數頁面間的傳遞

  在介紹表單傳遞參數的內容之前先來了解一些預備知識表單的提交方式和請求報文中對漢字的處理

  表單的提交方式

  通常使用的表單的提交方式主要是post和get兩種兩者的區別在於post方式是把數據內容放在請求的數據正文部分沒有長度的限制get方式則是把數據內容直接跟在請求的頭部的URL後面有長度的限制下面是同一個頁面兩種方式的請求報許文

  Requesttestjsp代碼

  

  1. <%@ page language="java" contentType="text/html; charset=UTF"   
  2.     pageEncoding="UTF"%>    
  3. <!DOCTYPE html PUBLIC "//WC//DTD HTML  Transitional//EN" "
  4. <html>    
  5. <head>    
  6. <meta httpequiv="ContentType" content="text/html; charset=UTF">    
  7. <title>Insert title here</title>    
  8. </head>    
  9. <body>    
  10. <% post方式提交表單 %>    
  11. <form action="
  12.     UserName:<input type="text" name="username"/>    
  13.     Password:<input type="password" name="password"/>    
  14.     <input type="submit" value="Submit">    
  15. </form>    
  16. </body>    
  17. </html>   

  

  1. <%@ page language="java" contentType="text/html; charset=UTF" pageEncoding="UTF"%> <!D
  2. OCTYPE html PUBLIC "//WC//DTD HTML  Transitional//EN" "
  3. itle>Insert title here</title> </head> <body> <% post方式提交表單 %> <form action=":<input type="text" nam
  4. e="username"/> Password:<input type="password" name="password"/> <input type="submit" va
  5. lue="Submit"> </form> </body> </html>  

  在上面的請求頁面的username輸入框裡輸入的是“世界杯”三個漢字password輸入框中輸入""後按下Submit按鈕提交請求截獲到的請求報文如下

  Post方式的請求報文代碼

  

  1. POST /EncodingTest/requestresultjsp HTTP/   
  2. Accept: image/gif image/jpeg image/pjpeg image/pjpeg application/xshockwaveflash applicati
  3. on/vndmsexcel application/vndmspowerpoint application/msword */*    
  4. Referer: 
  5. AcceptLanguage: zhcn    
  6. UserAgent: Mozilla/ (compatible; MSIE ; Windows NT ; Trident/; CIBA; affkingsoftci
  7. ba; NET CLR )    
  8. ContentType: application/xwwwformurlencoded    
  9. AcceptEncoding: gzip deflate    
  10. Host: localhost:   
  11. ContentLength:    
  12. Connection: KeepAlive    
  13. CacheControl: nocache    
  14.    
  15. username=%E%B%%E%%C%E%D%AF&password=   
  16. POST /EncodingTest/requestresultjsp HTTP/ Accept: image/gif image/jpeg image/pjpeg image/pjp
  17. eg application/xshockwaveflash application/vndmsexcel application/vndmspowerpoint applicati
  18. on/msword */* Referer: : zhcn Us
  19. erAgent: Mozilla/ (compatible; MSIE ; Windows NT ; Trident/; CIBA; affkingsoftciba; N
  20. ET CLR ) ContentType: application/xwwwformurlencoded AcceptEncoding: gzip deflate H
  21. ost: localhost: ContentLength:  Connection: KeepAlive CacheControl: nocache username=%E
  22. %B%%E%%C%E%D%AF&password=  

  以上報文內容可以看出post方式的請求報文是有專門的數據部的

  下面的同一請求頁面的get提交方式的請求報文

  Get方式的請求報文代碼

  

  1. GET /EncodingTest/requestresultjsp?username=%E%B%%E%%C%E%D%AF&password= H
  2. TTP/   
  3. Accept: image/gif image/jpeg image/pjpeg image/pjpeg application/xshockwaveflash applica
  4. tion/vndmsexcel application/vndmspowerpoint application/msword */*    
  5. Referer: 
  6. AcceptLanguage: zhcn    
  7. UserAgent: Mozilla/ (compatible; MSIE ; Windows NT ; Trident/; CIBA; affkingsoftcib
  8. a; NET CLR )    
  9. AcceptEncoding: gzip deflate    
  10. Host: localhost:   
  11. Connection: KeepAlive   
  12. GET /EncodingTest/requestresultjsp?username=%E%B%%E%%C%E%D%AF&passwo
  13. rd= HTTP/ Accept: image/gif image/jpeg image/pjpeg image/pjpeg application/xshockw
  14. aveflash application/vndmsexcel application/vndmspowerpoint application/msword */* Refer
  15. er: : zhcn UserAgent: Mozi
  16. lla/ (compatible; MSIE ; Windows NT ; Trident/; CIBA; affkingsoftciba; NET CLR 
  17. ) AcceptEncoding: gzip deflate Host: localhost: Connection: KeepAlive  

  以上報文內容可以看出get方式的請求報文沒有專門的數據部數據是直接跟在url的後面

  請求報文中對漢字的處理

  從上面兩種報文可以看出頁面上輸入的“世界杯”三個漢字被替換成了"%E%B%%E%%C%E%D%AF”這樣一個字符串然後發給服務器的看到這可能會有兩個問題問題一這個字符串是什麼?問題二為什麼要做這樣的替換?

  這個字符串是“世界杯”這三個漢字對應的"UTF”編碼"EBECEDAF"在每個字節前追加一個"%"後形成的至於為什麼要做這樣的轉化我的理解是因為請求報文會以"ISO"的編碼方式編碼後通過網絡流的方式傳送到服務器端"ISO"僅支持數字英文字母和一些特殊字符所以像漢字等這樣的字符"ISO"是不認識的所以就必須先給這些"ISO"不支持的字符做個“整形”手術這樣才能正確的將頁面上的信息傳送到服務器端

  這時可能又會有另外一個問題上面的例子中為什麼會選用"UTF"編碼其它的編碼方案可以嗎?答案是可以的在jsp頁面代碼的頭部有這樣一段代碼"<%@ page language="java" contentType="text/html; charset=UTF" pageEncoding="UTF"%>"其中charset的值就是浏覽器在提交請求報文前對請求報文做“整形”手術時用的字符集同是也是浏覽器解釋服務器的響應頁面時的字符集

  在了解了以上內容後開始剖析表單方式傳遞參數的亂碼問題

  以上例為例點擊"Submit"按鈕後浏覽器將做完“整形”手術後的請求報文發送給WEB服務器上的Servlet容器容器在收到這個請求報文後會解析這個請求報文並用這個報文的信息生成一個HttpServletRequest對象然後將這個HttpServletRequest對象傳給這個頁面所要請求的jsp或Servlet(上例中為"requestresultjsp")在這個被請求的jsp或Servlet(上例中為"requestresultjsp")中使用HttpServletRequest對象的getParameter("")方法來取得上一頁面傳來的參數默認情況下這一方法使用的是"ISO"來解碼所以對於英文或數字的參數值自然能正確取得但對於漢字這樣的字符是解不出來的因為那幾個漢字曾經做過“整形”手術已經認不出來了要想再把它們認出來那就得要把手術的主刀醫生找到然後再做一次“還原”手術下面提供的幾個方案可用於不同的情況

  方案一代碼

  

  1. <%String str = new String(requestgetParameter("username")getBytes("ISO")"utf"); %>    
  2. Username:<%=str %>   
  3. <%String str = new String(requestgetParameter("username")getBytes("ISO")"utf"); %> Usern
  4. ame:<%=str %>  

  既然requestgetParameter("username")默認情況下返回的字符串是用"ISO"解出來的那就先把這個不可辨認的字符串再用"ISO"來打散也就是requestgetParameter("username")getBytes("ISO")最後再用跟你的頁面的charset一致的字符集來重組這個字符串new String(requestgetParameter("username")getBytes("ISO")"utf")這樣就能見到它的廬山真面目了

  方案一是一種比較萬能的方法不管是post還是get都適用但可以看出它的缺點是對於每個可能出現漢字的參數都要顯示的做這麼一段處理一個兩個還行要是很多的話那就應該考慮一下是不是可以選用下一種方案

  方案二代碼

  

  1. <%requestsetCharacterEncoding("UTF"); %>   
  2. <%requestsetCharacterEncoding("UTF"); %>  

  方案二是在頁面的最開始或者是在該頁面中使用的第一個requestgetParameter("")方法之前加上上述一段代碼它的作用是用作為參數傳入的編碼集去覆蓋request對象中的默認的"ISO"編碼集這樣requestgetParameter("")方法就會用新的編碼集去解碼因為"UTF"支持中文所以作為參數傳過來的“世界杯”三個漢字就能正確的接收到了但關於requestsetCharacterEncoding("")方法API文檔中有如下的說明

   Overrides the name of the character encoding used in the body of this request This method must be called prior to reading request parameters or reading input using getReader() Otherwise it has no effectb

  所以方案二只對post方式提交的請求有效因為參數都在request的body區而對get方式提交的請求則是無效的這時你會發現同樣的做法但顯示的還是亂碼所以你的請求要是是以get方式提交的話那你還是乖乖的選用方案一吧!

  從上面的敘述可以知道方案二需要在每個頁面的前頭加上<%requestsetCharacterEncoding("UTF"); %>這段代碼這樣做是不是也挺累的所以我們想到了使用過濾器來幫助我們做這件事兒那就清爽簡單多了

  Encodingfilter代碼

  

  1. public class EncodingFilter implements Filter {    
  2.         
  3.     private String charset;    
  4.     @Override    
  5.     public void destroy() {    
  6.         // TODO Autogenerated method stub    
  7.     }    
  8.    
  9.     @Override    
  10.     public void doFilter(ServletRequest request ServletResponse response    
  11.             FilterChain chain) throws IOException ServletException {    
  12.         //用init方法取得的charset覆蓋被攔截下來的request對象的charset    
  13.         requestsetCharacterEncoding(thischarset);    
  14.         //將請求移交給下一下過濾器如果還有的情況下    
  15.         chaindoFilter(request response);    
  16.     }    
  17.    
  18.     @Override    
  19.     public void init(FilterConfig config) throws ServletException {    
  20.         //從webxml中的filter的配制信息中取得字符集    
  21.         thischarset = configgetInitParameter("charset");    
  22.     }    
  23. }   
  24. public class EncodingFilter implements Filter { private String charset; @Override public void destr
  25. oy() { // TODO Autogenerated method stub } @Override public void doFilter(ServletRequest req
  26. uest ServletResponse response FilterChain chain) throws IOException ServletException { //用init方
  27. 法取得的charset覆蓋被攔截下來的request對象的charset requestsetCharacterEncoding(thischarset); //將
  28. 請求移交給下一下過濾器如果還有的情況下 chaindoFilter(request response); } @Override pub
  29. lic void init(FilterConfig config) throws ServletException { //從webxml中的filter的配制信息中取得字
  30. 符集 thischarset = configgetInitParameter("charset"); } }  

  要想這個過濾器生效還得到webxml裡加入下面的配制信息

  Webxml代碼

  

  1. <filter>    
  2.    <filtername>EncodingFilter</filtername>    
  3.    <filterclass>cnericencodingtestfilterEncodingFilter</filterclass>    
  4.    <initparam>    
  5.        <paramname>charset</paramname>    
  6.        <paramvalue>UTF</paramvalue>    
  7.    </initparam>    
  8. </filter>    
  9. <filtermapping>    
  10.    <filtername>EncodingFilter</filtername>    
  11.    <urlpattern>/*</urlpattern>    
  12. </filtermapping>   
  13. <filter> <filtername>EncodingFilter</filtername> <filterclass>cnericencodingtestfilterEncodi
  14. ngFilter</filterclass> <initparam> <paramname>charset</paramname> <paramvalue>UT
  15. F</paramvalue> </initparam> </filter> <filtermapping> <filtername>EncodingFilter</filt
  16. ername> <urlpattern>/*</urlpattern> </filtermapping>  

  直接使用URL後接參數的形式(超級鏈接)

  有些時候可能會遇到通過一個超級鏈接來把參數傳到下一個頁面而剛好這個參數的值有可能會出現中文的情況就像下面這樣

  

  1. <a href="/jstlresultjsp?content=世界杯">Go South Africa 

  跟form提交有些不同的是當你點擊這個超級鏈接後在浏覽器的地址欄裡看到的是世界杯而不是%E%B%%E%%C%E%D%AF

  這裡浏覽器並沒有幫我們把這個轉化工作搞定所以這裡要自己動手豐衣足食了做法如下

  

  1. <a href="/jstlresultjsp?content=<%=javanetURLEncoderencode("世界杯""utf") %>">Go South Africa 

  這樣的話在第二個頁面就能使用

  

  1. <%String str = new String(requestgetParameter("content")getBytes("ISO")"utf"); %> 

  的方法來正確的得到這個參數值了

  總結一下

  post提交的方式使用過濾器將到達頁面前的request對象中的字符編碼設定成跟你頁面統一的編碼

  get提交的方式<%String str = new String(requestgetParameter("content")getBytes("ISO")"utf"); %>這樣的字符串重組的方法

  超級鏈接方式先將鏈接url中的漢字用javanetURLEncoderencode("paramValue""charset")方法處理一下下面的做法參照


From:http://tw.wingwit.com/Article/program/Java/JSP/201311/19243.html
  • 上一篇文章:

  • 下一篇文章:
  • 推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.