<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    tbwshc

    解決jsp參數傳遞亂碼的問題

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

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

     

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

     

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

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

     

         表單的提交方式:

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

    Requesttest.jsp代碼 
    <%@ page language="java" contentType="text/html; charset=UTF-8" 
        pageEncoding="UTF-8"%>  
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">  
    <html>  
    <head>  
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
    <title>Insert title here</title>  
    </head>  
    <body>  
    <%-- post方式提交表單 --%>  
    <form action="http://localhost:8888/EncodingTest/requestresult.jsp" method="post">  
        UserName:<input type="text" name="username"/>  
        Password:<input type="password" name="password"/>  
        <input type="submit" value="Submit">  
    </form>  
    </body>  
    </html> 
    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <%-- post方式提交表單 --%> <form action="http://localhost:8888/EncodingTestb/requestresult.jsp" method="post"> UserName:<input type="text" name="username"/> Password:<input type="password" name="password"/> <input type="submit" value="Submit"> </form> </body> </html>
          在上面的請求頁面的username輸入框里輸入的是“世界杯”三個漢字,password輸入框中輸入"123"后按下Submit按鈕提交請求。截獲到的請求報文如下:

    Post方式的請求報文代碼 
    POST /EncodingTest/requestresult.jsp HTTP/1.1 
    Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*  
    Referer: http://localhost:8080/TomcatJndiTest/requesttest.jsp  
    Accept-Language: zh-cn  
    User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; CIBA; aff-kingsoft-ciba; .NET CLR 2.0.50727)  
    Content-Type: application/x-www-form-urlencoded  
    Accept-Encoding: gzip, deflate  
    Host: localhost:8888 
    Content-Length: 49 
    Connection: Keep-Alive  
    Cache-Control: no-cache  
     
    username=%E4%B8%96%E7%95%8C%E6%9D%AF&password=123 
    POST /EncodingTest/requestresult.jsp HTTP/1.1 Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */* Referer: http://localhost:8080/TomcatJndiTest/requesttest.jsp Accept-Language: zh-cn User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; CIBA; aff-kingsoft-ciba; .NET CLR 2.0.50727) Content-Type: application/x-www-form-urlencoded Accept-Encoding: gzip, deflate Host: localhost:8888 Content-Length: 49 Connection: Keep-Alive Cache-Control: no-cache username=%E4%B8%96%E7%95%8C%E6%9D%AF&password=123
          以上報文內容,可以看出post方式的請求報文是有專門的數據部的。,

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

    Get方式的請求報文代碼 
    GET /EncodingTest/requestresult.jsp?username=%E4%B8%96%E7%95%8C%E6%9D%AF&password=123 HTTP/1.1 
    Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*  
    Referer: http://localhost:8080/TomcatJndiTest/requesttest.jsp  
    Accept-Language: zh-cn  
    User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; CIBA; aff-kingsoft-ciba; .NET CLR 2.0.50727)  
    Accept-Encoding: gzip, deflate  
    Host: localhost:8888 
    Connection: Keep-Alive 
    GET /EncodingTest/requestresult.jsp?username=%E4%B8%96%E7%95%8C%E6%9D%AF&password=123 HTTP/1.1 Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */* Referer: http://localhost:8080/TomcatJndiTest/requesttest.jsp Accept-Language: zh-cn User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; CIBA; aff-kingsoft-ciba; .NET CLR 2.0.50727) Accept-Encoding: gzip, deflate Host: localhost:8888 Connection: Keep-Alive
         以上報文內容,可以看出get方式的請求報文沒有專門的數據部,數據是直接跟在url的后面。

     

           請求報文中對漢字的處理:

           從上面兩種報文可以看出頁面上輸入的“世界杯”三個漢字被替換成了"%E4%B8%96%E7%95%8C%E6%9D%AF”這樣一個字符串,然后發給服務器的。看到這,可能會有兩個問題:問題一、這個字符串是什么?問題二、為什么要做這樣的替換?

     

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

     

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

     

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

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

     

    方案一代碼 
    <%String str = new String(request.getParameter("username").getBytes("ISO-8859-1"),"utf-8"); %>  
    Username:<%=str %> 
    <%String str = new String(request.getParameter("username").getBytes("ISO-8859-1"),"utf-8"); %> Username:<%=str %>
          既然request.getParameter("username")默認情況下返回的字符串是用"ISO-8859-1"解出來的,那就先把這個不可辨認的字符串再用"ISO-8859-1"來打散,也就是:request.getParameter("username").getBytes("ISO-8859-1")。最后再用跟你的頁面的charset一致的字符集來重組這個字符串:new String(request.getParameter("username").getBytes("ISO-8859-1"),"utf-8")。這樣就能見到它的廬山真面目了。

     

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

      

    方案二代碼 
    <%request.setCharacterEncoding("UTF-8"); %> 
    <%request.setCharacterEncoding("UTF-8"); %>
          方案二是在頁面的最開始或者是在該頁面中使用的第一個request.getParameter("")方法之前加上上述一段代碼,它的作用是用作為參數傳入的編碼集去覆蓋request對象中的默認的"ISO-8859-1"編碼集。這樣request.getParameter("")方法就會用新的編碼集去解碼,因為"UTF-8"支持中文,所以作為參數傳過來的“世界杯”三個漢字就能正確的接收到了。但關于request.setCharacterEncoding("")方法,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方式提交的話,那你還是乖乖的選用方案一吧!

     

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

    Encodingfilter代碼 
    public class EncodingFilter implements Filter {  
          
        private String charset;  
        @Override  
        public void destroy() {  
            // TODO Auto-generated method stub  
        }  
     
        @Override  
        public void doFilter(ServletRequest request, ServletResponse response,  
                FilterChain chain) throws IOException, ServletException {  
            //用init方法取得的charset覆蓋被攔截下來的request對象的charset  
            request.setCharacterEncoding(this.charset);  
            //將請求移交給下一下過濾器,如果還有的情況下。  
            chain.doFilter(request, response);  
        }  
     
        @Override  
        public void init(FilterConfig config) throws ServletException {  
            //從web.xml中的filter的配制信息中取得字符集  
            this.charset = config.getInitParameter("charset");  
        }  

    public class EncodingFilter implements Filter { private String charset; @Override public void destroy() { // TODO Auto-generated method stub } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { //用init方法取得的charset覆蓋被攔截下來的request對象的charset request.setCharacterEncoding(this.charset); //將請求移交給下一下過濾器,如果還有的情況下。 chain.doFilter(request, response); } @Override public void init(FilterConfig config) throws ServletException { //從web.xml中的filter的配制信息中取得字符集 this.charset = config.getInitParameter("charset"); } }
            要想這個過濾器生效,還得到web.xml里加入下面的配制信息。

    Web.xml代碼 
    <filter>  
       <filter-name>EncodingFilter</filter-name>  
       <filter-class>cn.eric.encodingtest.filter.EncodingFilter</filter-class>  
       <init-param>  
           <param-name>charset</param-name>  
           <param-value>UTF-8</param-value>  
       </init-param>  
    </filter>  
    <filter-mapping>  
       <filter-name>EncodingFilter</filter-name>  
       <url-pattern>/*</url-pattern>  
    </filter-mapping> 
    <filter> <filter-name>EncodingFilter</filter-name> <filter-class>cn.eric.encodingtest.filter.EncodingFilter</filter-class> <init-param> <param-name>charset</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>EncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
     

            2、直接使用URL后接參數的形式(超級鏈接)。

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

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

             跟form提交有些不同的是:當你點擊這個超級鏈接后在瀏覽器的地址欄里看到的是http://localhost:8080/TomcatJndiTest/jstlresult.jsp?content=世界杯,而不是http://localhost:8080/TomcatJndiTest/jstlresult.jsp?content=%E4%B8%96%E7%95%8C%E6%9D%AF

    這里瀏覽器并沒有幫我們把這個轉化工作搞定,所以這里要自己動手,豐衣足食了。做法如下:

            <a href="./jstlresult.jsp?content=<%=java.net.URLEncoder.encode("世界杯","utf-8") %>">Go South Africa

            這樣的話在第二個頁面就能使用<%String str = new String(request.getParameter("content").getBytes("ISO-8859-1"),"utf-8"); %>的方法來正確的得到這個參數值了。

     

            總結一下:

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

            2、get提交的方式:<%String str = new String(request.getParameter("content").getBytes("ISO-8859-1"),"utf-8"); %>這樣的字符串重組的方法。

            3、超級鏈接方式:先將鏈接url中的漢字用java.net.URLEncoder.encode("paramValue","charset")方法處理一下,下面的做法參照2。

    posted on 2012-06-18 13:28 chen11-1 閱讀(6956) 評論(3)  編輯  收藏

    Feedback

    # re: 解決jsp參數傳遞亂碼的問題[未登錄] 2012-09-07 14:43 a

    果然有人  回復  更多評論   

    # re: 解決jsp參數傳遞亂碼的問題 2014-04-28 09:49 visitor

    非常不錯,感謝分享  回復  更多評論   

    # re: 解決jsp參數傳遞亂碼的問題 2014-12-23 14:06 額外

    問問  回復  更多評論   


    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 亚洲综合一区二区精品导航| 亚洲人成网站影音先锋播放| 国产日韩AV免费无码一区二区三区 | 亚洲a∨无码精品色午夜| 亚洲国产成人精品女人久久久 | 精品在线观看免费| 亚洲国产AV一区二区三区四区| 国产精品视_精品国产免费| 久久精品成人免费国产片小草| 亚洲欧洲日产国产最新| 国产精品久免费的黄网站| 久久精品免费观看| 亚洲一卡2卡三卡4卡无卡下载| 亚洲乱码中文字幕手机在线| 中文字幕视频免费| 免费人成视频在线播放| 亚洲福利视频网址| 亚洲午夜无码AV毛片久久| 99久久免费国产精品特黄| 久久国产乱子伦精品免费午夜 | 亚洲人成无码网站在线观看| 色久悠悠婷婷综合在线亚洲| 日韩精品无码区免费专区 | www成人免费视频| 亚洲最大成人网色香蕉| 国产亚洲精品福利在线无卡一 | 亚洲精品综合久久| 在线观看成人免费| 亚洲欧洲AV无码专区| 亚洲国产精品一区二区第一页| 免费看无码自慰一区二区| 久草视频在线免费看| 羞羞视频免费网站日本| 亚洲大成色www永久网址| 亚洲精品福利视频| 国产AV无码专区亚洲AV漫画| 免费黄色网址入口| 在线观看日本免费a∨视频| 99re免费在线视频| 99热在线日韩精品免费| 免费精品国产自产拍在线观看 |