表单提交参数中文乱码问题

 

表单提交一般有两种方式,一种是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> 
相关文章
相关标签/搜索