表單提交參數中文亂碼問題

 

表單提交一般有兩種方式,一種是GET方式,一種時POST方式,兩種方式這裏就不詳細解釋了;而後表單參數的傳遞,也有兩種方式,一種是直接把參數加在URL上,以key=value的方式傳遞,一種是在表單內部添加帶name屬性的標籤,例如input,select標籤等。那麼它們組合在一塊兒,就有4種方式:java

 

URL傳參web

表單標籤傳參ajax

混合傳參spring

GET服務器

Aapp

Bide

Cpost

POSTthis

D編碼

E

F

先說一下使用中會出現的問題。A、C方式中,URL上的參數會被表單的參數沖掉,因此A、C方式不要使用。

在說說這幾種方式的特色,在GET方式中,表單中全部的參數實際上都是被追加到URL上的(這也是get方式的url傳參,url參數被沖掉的緣由),表單最後提交給服務器的就是一個url(url長度通常限制爲255字符)。這種方式產生的亂碼最難纏。

在POST方式中,若是參數位於表單中(等同於ajax提交數據時的data內容),參數是以非url形式提交的,因此這種一般不會出現亂碼,並且也容易解決。若是參數位於url中,那參數的傳遞方式和get方式是同樣的,這時產生亂碼的緣由和get方式是同樣的。

如今咱們把問題抽象出來了,參數傳遞有兩種,一種是經過url傳參,一種是經過data傳參。

亂碼之因此亂碼,是由於編碼和解碼的格式不一致。

說說咱們一般解決亂碼的方法。一般有兩類解決辦法,一類是對參數進行編碼,而後後臺進行解碼,這種方式對於以上幾種傳參都適用,可是由於前臺要編碼,後臺須要解碼,因此增長了代碼複雜性。另外一種方式就是弄個filter(spring自帶一個,就是這貨org.springframework.web.filter.CharacterEncodingFilter,能夠直接把它配在web.xml裏面),對全部請求都setCharactorEncoding()爲UTF-8,這種方式一般都行。之因此說一般都行,是由於這種方式之對經過data方式傳遞的參數有效,對於經過url傳遞的參數無效,這也是爲何get提交方式產生亂碼機率大的緣由。

可是咱們怎麼經過url傳參時的亂碼呢?也許有人會說,不用url傳參不就能夠了,可是在許多狀況下,我不得不使用url傳參,好比一個超連接。

其實只要找到問題所在,解決方案也就好辦了。開始時,個人辦法是寫一個filter,對於經過get方式提交的參數,把全部的參數都進行一下編碼轉換:ISO-8859-1——>UTF-8。這種方式我使用了很長時間,直到有一次,我不得不使用post方式的混合傳參時,才發現url上的參數竟然被認爲是post方式傳遞的,固然也沒有被個人filter攔截,固然也就亂碼了。

不過既然要死磕,就必定要把這問題解決。

思路卻是很清晰,雖然是post方式提交的,可是咱們只須要把其中url方式傳參的參數進行轉碼便可(data傳參只須要設置CharactorEncoding便可,若是轉碼那就轉成亂碼了),但是怎麼知道哪些參數是url傳遞呢?

HttpServletRequest對象有getQueryString()這個方法,這個方法可以得到url傳遞的參數的字符串,固然了,參數也就包含在其中。因此咱們只要把其中的參數名分離出來便可,這些就是咱們須要進行轉碼的,別的不須要解碼。

 

在而後呢,咱們經過request獲取參數時,通常會經過這麼幾個方法:getParameter(),getPrarmeterMap(),getParameterValues()這三個方法。因此咱們只要在這三個方法上「作手腳」便可。另外,若是某些參數是按照傳引用(相對於傳值而言,瞭解c的人,對這個應該比較瞭解。另外雖然Java本質上都是傳值,可是若是對象不是基本類型時,就會有傳引用的效果)傳遞的,咱們還要設置一些標誌位,防止屢次轉碼。

 

思路已經清楚了,下面直接貼本人的成型代碼。

第一個是GetHttpServletRequestWrapper,這個類是「主角」,完成對參數的篩選和轉碼:

 

 

  1. /* 
  2.  * Copyright (c) 2014, ShiXiaoyong. All rights reserved. 
  3.  */  
  4. package com.common.filter;  
  5.   
  6. import java.io.UnsupportedEncodingException;  
  7. import java.util.Enumeration;  
  8. import java.util.HashMap;  
  9. import java.util.Map;  
  10.   
  11. import javax.servlet.http.HttpServletRequest;  
  12. import javax.servlet.http.HttpServletRequestWrapper;  
  13.   
  14. /** 
  15.  * 描述:GetHttpServletRequestWrapper 
  16.  *  
  17.  * <pre> 
  18.  * HISTORY  
  19.  * ****************************************************************  
  20.  *  ID   DATE           PERSON          REASON  
  21.  * 1     2015-3-6       Shixy           Create  
  22.  * 2     2015-3-23      Shixy           增長對post混合傳參方式的支持  
  23.  * **************************************************************** 
  24.  * </pre> 
  25.  *  
  26.  * @author Shixy 
  27.  * @since 1.0 
  28.  */  
  29. public class GetHttpServletRequestWrapper extends HttpServletRequestWrapper {  
  30.   
  31.     private String charset = "UTF-8";  
  32.   
  33.     private static final String ENCODED = "__encoded";  
  34.   
  35.     private Map<String, String> urlParamNames = null;  
  36.   
  37.     /** 
  38.      * @param request 
  39.      */  
  40.     public GetHttpServletRequestWrapper(HttpServletRequest request) {  
  41.         super(request);  
  42.         initUrlParameterNames();  
  43.     }  
  44.   
  45.     /** 
  46.      * 得到被裝飾對象的引用和採用的字符編碼 
  47.      *  
  48.      * @param request 
  49.      * @param charset 
  50.      */  
  51.     public GetHttpServletRequestWrapper(HttpServletRequest request, String charset) {  
  52.         super(request);  
  53.         this.charset = charset;  
  54.         initUrlParameterNames();  
  55.     }  
  56.   
  57.     @Override  
  58.     public Enumeration<String> getParameterNames() {  
  59.         return super.getParameterNames();  
  60.     }  
  61.   
  62.     /** 
  63.      * 實際上就是調用被包裝的請求對象的getParameter方法得到參數,而後再進行編碼轉換 
  64.      */  
  65.     @Override  
  66.     public String getParameter(String name) {  
  67.         String value = super.getParameter(name);  
  68.         // 根據urlParamNames是否包含此值來判斷是否須要對其進行get方式轉碼  
  69.         if (!urlParamNames.containsKey(name)) {  
  70.             return value;  
  71.         }  
  72.         if (null != value) {  
  73.             value = convert(value);  
  74.         }  
  75.         return value;  
  76.     }  
  77.   
  78.     @Override  
  79.     public String[] getParameterValues(String name) {  
  80.         // values也是傳值  
  81.         String[] values = super.getParameterValues(name);  
  82.         if ((!urlParamNames.containsKey(name))) {  
  83.             return values;  
  84.         }  
  85.         for (int i = 0; i < values.length; i++) {  
  86.             values[i] = convert(values[i]);  
  87.         }  
  88.   
  89.         return values;  
  90.     }  
  91.   
  92.     @Override  
  93.     public Map<String, String[]> getParameterMap() {  
  94.         Map<String, String[]> map = super.getParameterMap();  
  95.         // 是否已經轉碼的標識位  
  96.         // 由於map是傳引用的,所以屢次調用時,原值會被轉碼轉碼在轉碼,所以要設置此標誌位,防止屢次轉碼  
  97.         if ("1".equals(this.getAttribute(ENCODED))) {  
  98.             return map;  
  99.         }  
  100.   
  101.         // 對map中全部的url傳參進行編碼  
  102.         // 遍歷map中的參數,轉換器編碼  
  103.         for (String key : urlParamNames.keySet()) {  
  104.             String[] value = map.get(key);  
  105.             if (value != null) {  
  106.                 for (int i = 0; i < value.length; i++) {  
  107.                     value[i] = convert(value[i]);  
  108.                 }  
  109.             }  
  110.         }  
  111.   
  112.         this.setAttribute(ENCODED, "1");  
  113.         return map;  
  114.     }  
  115.   
  116.     /** 
  117.      * 將字符串轉碼 
  118.      * ISO-8859-1爲國際通用url編碼 
  119.      * @param target 
  120.      * @return 
  121.      */  
  122.     private String convert(String target) {  
  123.         try {  
  124.             return new String(target.trim().getBytes("ISO-8859-1"), charset);  
  125.         } catch (UnsupportedEncodingException e) {  
  126.             return target;  
  127.         }  
  128.     }  
  129.       
  130.     /** 
  131.      * 初始化設置url傳值的參數名 
  132.      */  
  133.     private void initUrlParameterNames() {  
  134.         if (null != urlParamNames) {  
  135.             return;  
  136.         }  
  137.         // 獲取全部的url傳參的參數名  
  138.         urlParamNames = new HashMap<String, String>();  
  139.         String st = this.getQueryString();  
  140.         if (null == st || 0 == st.length()) {  
  141.             return;  
  142.         }  
  143.         String[] params = this.getQueryString().split("&");  
  144.         for (String p : params) {  
  145.             if (!p.contains("=")) {  
  146.                 continue;  
  147.             }  
  148.             urlParamNames.put(p.substring(0, p.indexOf("=")), null);  
  149.         }  
  150.     }  
  151.   
  152. }  


 

 

第二個就是一個簡單的filter,用於使用上面的RquestWrapper轉碼咱們的參數:

 

 

  1. /*   
  2.  * Copyright (c) 2014, ShiXiaoyong. All rights reserved.  
  3.  */  
  4. package com.common.filter;  
  5.   
  6. import java.io.IOException;  
  7.   
  8. import javax.servlet.Filter;  
  9. import javax.servlet.FilterChain;  
  10. import javax.servlet.FilterConfig;  
  11. import javax.servlet.ServletException;  
  12. import javax.servlet.ServletRequest;  
  13. import javax.servlet.ServletResponse;  
  14. import javax.servlet.http.HttpServletRequest;  
  15.   
  16. /**  
  17.  * 描述:GetMethodEncodingFilter  
  18.  *     針對GET方式提交的表單,進行編碼轉換 
  19.  * <pre>  
  20.  * HISTORY  
  21.  * ****************************************************************  
  22.  *  ID   DATE           PERSON          REASON  
  23.  *  1    2015-3-6       Shixy           Create  
  24.  * ****************************************************************  
  25.  * </pre>  
  26.  *   
  27.  * @author Shixy  
  28.  * @since 1.0  
  29.  */  
  30. public class GetMethodEncodingFilter implements Filter {  
  31.   
  32.     private String charset = "utf-8";  
  33.       
  34.     @Override  
  35.     public void destroy() {  
  36.     }  
  37.   
  38.     @Override  
  39.     public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {  
  40.           
  41.         HttpServletRequest req = (HttpServletRequest)request;    
  42.   
  43.         req = new GetHttpServletRequestWrapper(req,charset);    
  44.         filterChain.doFilter(req, response);    
  45.     }  
  46.   
  47.     @Override  
  48.     public void init(FilterConfig filterConfig) throws ServletException {  
  49.     }  
  50. }  


 

 

最後把咱們的filter配置在web.xml裏便可,要注意順序,最佳位置是setCharatorEncoding那個filter後面。

 

 

  1. <!-- get method url encode -->  
  2. <filter>  
  3.     <filter-name>getMethodEncodingFilter</filter-name>  
  4.     <filter-class>com.common.filter.GetMethodEncodingFilter</filter-class>  
  5. </filter>  
  6. <filter-mapping>  
  7.     <filter-name>encodingFilter</filter-name>  
  8.     <url-pattern>/*</url-pattern>  
  9. </filter-mapping> 
相關文章
相關標籤/搜索