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

http://hi.baidu.com/studyaspnet/item/ecd636f4c87d9009d89e729c

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=%D5%C5%C8%FD

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

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

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

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

所以这样也不难理解为什么所谓“浏览器地址栏是不支持中文”,不能直接用中文而要用“UTF-8”来通过“8859_1”来打包了,原因就是“%D5%C5%C8%FD”这串类似于密码般的字符串本身就是西文字符,用“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>


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值