Java开发,表单提交中发生中文乱码的问题

  转载
       Java开发,表单提交中发生中文乱码的问题。

Web开发的中文问题一直困惑大家,尤其是对于初上手者。这次有机会彻底解决研究了一下中文乱码的原因和解决方案,做个总结。

为什么会有中文乱码?

因为在默认情况下,HTTP的包都是以“8859_1”来编码的(没办法,谁叫这些标准都是老美定的)。“8859_1”是西文编码方式,对于英文字母没 有任何问题,但是对于中文就不行了。所以,如果不做任何设定,直接将中文用“8859_1”来编码传递,那结果必然是乱码。

解决思路是什么?

好在老美还是有国际化眼光的,HTTP包的编码方式可以由用户指定。因此,只要事先指定好用相对应的编码方式来对传递内容(比如表单提交的中文等)进行编码,就可以顺利解决乱码的问题。

两个基本概念

在进入具体的解决方法之前,首先要对两个基本概念作一下解释。对于由表单提交的内容,HTTP有两种传递方式,分别是“GET”方式和“POST”方式。

“GET”方式就是将各参数直接通过HTTP的包头(head)来传递,简而言之就是直接通过我们所熟悉的网址(URL)来传递,所以我们经常能看到的在一个网址后面跟着许多复杂的由“?”和“&”构成的字符串,其实这就是需要传递的参数了。

“POST”方式则是将所需传递的参数包在HTTP的正文(body)中来传递。因此通过“POST”方式来进行传递,在浏览器的网址上面什么都看不见。

因此,相比较而言,“POST”隐蔽性较好;而“GET”方式使用起来比较容易,直接写URL就可以了。

综上所述,不难发现,解决中文乱码问题实际上就变为对这两种HTTP传递的编码方式进行适当的设定。当然,从解决问题的难易以及对系统架构的完美性角度着手,又分为以下三个层次:

1)入门方法,在所有的servlet和jsp中堆设定用的代码。

2)中级方法,对web伺服器进行配置。

3)高级方法,编写filter过滤器,对“POST”和“GET”独立过滤处理。

下面就具体描述各解决方法:

1)入门方法,在所有的servlet和jsp中“堆”写设定用的代码。

所谓入门方法,那就是现实十分简单,当然效果也是很好的。只是必须在每个相应的文件中写相同的设定代码,代码的重复性就比较大。

由前面所述,由于“POST”和“GET”方式的不同,因此对应着两种的设定方式也不同。

“POST”的情况下,如果服务器端脚本是一个servlet,那只要在doPost()方法里面插入一句

 

request.setCharacterEncode("GB2312");

需要注意的是,这句设定必须在所有从request对象做提取操作之前执行,如果类似于request.getParameter()的操作在前,那么系统将使用默认的“8859_1”编码方式,而忽略后面的设定代码。

如果服务器端是一个jsp脚本,那只要在该脚本的jsp申明部分做好设定即可:

 

<%@ page language="java" contentType="text/html; charset=gb2312" pageEncoding="gb2312"%>

如果是“GET”方式,也就是想通过URL来传递中文的话,稍微要麻烦些,首先因为浏览器地址栏是不支持中文的,也就是如果直接将中文放置在超级连接里面是无效的。因此需要在发送端对中文内容进行编码,比如:

 

URLEncoder.encoder("http://localhost/submit?name=张三","UTF-8");

“UTF-8”表示用这种编码方式对原字符串进行编码,编码好之后看到的结果是

 

http://localhost/submit?name=����

所以我们经常看到在浏览器里面有众多的类似与“����”这样的字符串,就是表明被UTF-8编码过了。由于UTF-8是跨各种平台的通用编码方式,因此比较常用于各种语言文字的传输载体。

相对应的,在接受方需要进行反向的解码即可,代码如下:

 

new String( request.getParameter("name").getBytes("8859_1"), "gb2312" );

这里可能会有一些疑问,为什么用“8859_1”来解码。事实上,我在第一次尝试的时候也曾使用“UTF-8”来尝试解码,结果出现乱码失败。究其原因, 尽管“张三”被编码成了“����”来传输,但是在传输过程中,“����”仍旧需要由“8859_1”来编码打包成HTTP,因此,在接收端,自然先需 要由“8859_1”来还原到“����”的“UTF-8”格式,然后再由“UTF-8”还原到“GB2312”。

所以这样也不难理解为什么所谓“浏览器地址栏是不支持中文”,不能直接用中文而要用“UTF-8”来通过“8859_1”来打包了,原因就是“����” 这串类似于密码般的字符串本身就是西文字符,用“8859_1”编解码没有任何问题。而中文由于是2byte一个汉字,直接用西文方式来编解码自然就会出 现问题。这也就是为什么称“UTF-8”为“跨各种平台的通用编码方式”了。

背景小资料:

由于“UTF-8”是通用编码方式,因此所有的语言格式均可以转换为“UTF-8”,在日益国际的今天,多语言的系统要求越来越多,因此强烈建议使用“UTF-8”来做为系统统一的编解码方式,从而彻底解决中文乱码的问题。

“UTF-8”为了能做到兼容所有语言的编解码,因此每一个字符均用2个byte来编码。这样就造成了存西文字符时需要多一倍的空间。这也算是为了通用而付出的代价了。

2)中级方法,对web伺服器进行配置

可想而知,相对于“堆”写大量代码,配置一下web伺服器config文件来解决中文乱码问题就显得优雅许多。但是由于各种web伺服器的情况不同,其配置方法也不尽相同。因此,其兼容性是个比较大的问题。

这里列举一下,如何通过修改Tomcat的conf配置文件来解决中文乱码的问题。

找到Tomcat的配置文件server.xml中的Connector这一行,为其添加一个如下的属性

 

URIEncoding = "GB2312"

这样就指定了使用“GB2312”来进行编解码。不过需要注意的是,tomcat4.x以以前的版本由于蒋“POST”和“GET”等同视之,因此这样一 句设定就可以适用于两种方法。而到了tomcat5.x以后,两种方式就分开处理了。因此在tomcat5.x的情况下,只做这个设定,那仅仅对 “POST”方式有效,“GET”方式仍然会得到乱码。

不过好在tomcat5.x考虑到了这个问题,提供了一个附加的参数:

 

useBodyEncodingForURI = "true"

如果做了这样的设定,那5.x就将兼容4.x而“POST”和“GET”等同视之。

3)高级方法,编写filter过滤器,对“POST”和“GET”独立过滤处理。

高级方法,顾名思义,就是可以脱离于任何平台,同时又免去冗余的队旗代码工作的解决方案——编写过滤器,Filter。

首先编写一个过滤器SetCharacterEncodingFilter

 

    

public class SetCharacterEncodingFilter implements Filter {

       

       protected String encoding = null;

       

       protected FilterConfig filterConfig = null;

          

       protected boolean ignore = true;

   // --------------------------------------------------------- Public Methods

   

   public void destroy() {

       this.encoding = null;

       this.filterConfig = null;

   }

  

   public void doFilter(ServletRequest request, ServletResponse response,

                        FilterChain chain)

   throws IOException, ServletException {

      // Conditionally select and set the character encoding to be used

       if (ignore || (request.getCharacterEncoding() == null)) {

           String encoding = selectEncoding(request);

           if(encoding != null){

               HttpServletRequest httpServletRequest = (HttpServletRequest) request;

               if(httpServletRequest.getMethod().toLowerCase().equals("post")){

                   //如果是POST方法

                   request.setCharacterEncoding(encoding);

               }

               else{

                   //如果是GET方法

                   //非常抱歉,我还有没有找到很好的对应get方法的代码

                   //一旦完成了这部分代码,马上添加在这里。

                   //!·#¥%……—*()——+|

               }

           }

           

       }

   // Pass control on to the next filter

       chain.doFilter(request, response);

   }

   

   public void init(FilterConfig filterConfig) throws ServletException {

   this.filterConfig = filterConfig;

       this.encoding = filterConfig.getInitParameter("encoding");

       String value = filterConfig.getInitParameter("ignore");

       if (value == null)

           this.ignore = true;

       else if (value.equalsIgnoreCase("true"))

           this.ignore = true;

       else if (value.equalsIgnoreCase("yes"))

           this.ignore = true;

       else

           this.ignore = false;

   }

   // ------------------------------------------------------ Protected Methods

   

   protected String selectEncoding(ServletRequest request) {

       return (this.encoding);

   }

}

 

编写完过滤器以后,需要对其进行部署,也就是在web.xml中做个配置:

在<display-name>标签之后,添加:

 

  <filter>

       <filter-name>Set Character Encoding</filter-name>

       <filter-class>com.zavax.utility.filters.SetCharacterEncodingFilter</filter-class>

           <init-param>

               <param-name>encoding</param-name>

               <param-value>UTF8</param-value>

           </init-param>

           <init-param>

               <param-name>ignore</param-name>

               <param-value>true</param-value>

           </init-param>

       </filter>

   <filter-mapping>

       <filter-name>Set Character Encoding</filter-name>

       <url-pattern>/*</url-pattern>

   </filter-mapping>

猜你喜欢

转载自940324857.iteye.com/blog/2209353
今日推荐