Java中的中文编解码问题一直以来令开发者比较头疼,这在Web开发中表现尤为突出。网上的解决方案琳琅满目,但一般是针对于一个特定问题的。我自己在开发过程中也是多次遇到过这种问题,经过冷静分析和查阅参考资料问题也都得以解决(或许解决方案不是最佳的)。但是每一次的解决并没有为下一次问题的出现提供特别好的联想效果。今天特地在这里将Java开发中的中文编解码问题做一下总结。
首先,先来说一下可能遇到中文编解码问题的场景。主要就是在 IO操作的环境中出现这种编解码问题(这么描述也不知道是不是合适)。比如说,从文件中读取数据来展示,从数据库中读取数据来展示,从第三方接口(WebService接口、JS接口、Http接口等)获取数据来展示…
Java处理字符的基本原理又是什么呢?我大体说一下,自己理解的也没有多么深入。各位Java开发者应该都清楚,Java使用Unicode编码来存储字符数据,具体使用的是UTF-16,UTF-16采用的是定长的双字节编码。Java在处理字符时采取三步走:
1、 按照某种编码从文件中读取字符数据
2、 将读取的数据以Unicode(UTF-16)的编码方式存储在内存中
3、 按照某种编码将数据写入目的地
本篇文章主要分为3个章节来介绍:
1、 Java Application 中的中文编解码
2、 Java web中的中文编解码分析
3、 JavaScript中的中文编解码分析
Java Application 中的中文编解码
开发环境是eclipse,文件编码都设置为了UTF-8。
我们直接在代码中硬编码,如下:
String str = “中国”;
System.out.println(str);
这个时候,控制台输出的结果是正确的,不会出现乱码。但如果采用这种方式:
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
str = br.readLine();
System.out.println(str);
从eclipse的控制台中输入中文,再回显在控制台中,便会出现乱码。下面对这两种现象分析如下:
按照Java处理字符的三步走,因为eclipse中已经设置了文件编码是UTF-8,只要eclipse不出错,那么就可以肯定这个java源文件是UTF-8格式。
然后,利用eclipse来编译,编译后数据会议Unicode的格式存入字节码文件中。
最后,eclipse调用java命令输出,由于控制台的编码格式也是UTF-8,故而第一种方式不会出现乱码。
但是,如果不是硬编码而是从控制台输入中文,因为键盘的输入流的默认格式为系统默认编码,对中文操作系统而言就是GBK。这样便导致了GBK转UTF-8过程中出现了乱码。
Java web****中的中文编解码分析
Java Web开发过程中进场会遇到中文乱码的问题,比如:前台参数传输之服务端后乱码,服务端响应到达浏览器后乱码,等等。
首先看一下javaWeb开发中出现的各种编码:
1、 Jsp文件自身的编码
2、 Tomcat读取jsp文件时采用的编码
3、 Tomcat返回响应时采用的编码
4、 浏览器显示html时采用的编码
Jsp文件中会出现下面所示的编码指定方式:
<%@ page language=_“java”_ contentType=_“text/html; charset=UTF-8″_ pageEncoding=_“UTF-8″_%>
pageEncoding指的是改jsp文件自身采用的编码格式,这个编码要跟jsp文件的实际编码格式保持一致。contentType中的charset用来指定Tomcat返回响应时采用的编码,也是post方式提交参数的编码方式。Meta标签中的charset是在contentType未指定编码时采用的默认编码格式。
这里最常见的乱码出现在request.getParameter()过程中。这里分为GET方式和POST方式来分别分析。
1、 GET方式
首先,认识一下URL
URL到底是以什么格式来编码呢?这要分为两种情形。
情形一:URL是在浏览器地址栏中输入的,该URL将会采用UTF-8来编码,注意是URL并不包括后面的Query String。实际上,这个Query String是采用系统默认编码GBK来编码的。
情形二:URL是通过页面中链接等类似方式产生的,这个Query String将会采用源页面的编码方式来编码。
Tomcat在接收到这样的URL后,默认采用ISO-8859-1来解码URL,包括Query String,这个编码可以通过设置Tomcat配置文件中的URIEncoding属性来改变。需要注意的是,这个编码参数只适用于GET方式提交的参数。
2、 POST方式
POST表单参数是通过http的body传递到服务器的。前面已经说过,表单项参数是采用contentType中的charset指定的编码格式进行编码的。服务器端也是用contentType中的charset指定的编码进行解码操作,所以一般不会出现乱码问题。这个编码我们可以通过request.setCharacterEncoding()来进行设置,该设置只对POST参数有效。注意,这个函数必须在第一次调用request.getParameter()之前使用。
GET和POST两种方式的不同表现使得处理起来比较麻烦。好在还存在一种解决方案,那就是设置Tomcat的参数useBodyEncodingForURI=true(注意,并不是对整个URI都采用BodyEncoding,只是应用于Query String而已)。这样,Tomcat便会用request.setCharacterEncoding()指定的编码来解析GET参数了。
JavaScript****中的中文编解码分析
使用URL进行参数传递时,可能会含有中文或者特殊字符,这样就会导致乱码问题。JavaScript对文字进行编码涉及3个函数:escape、encodeURI、encodeURIComponent,对应3个解码函数:unescape、decodeURI、decodeURIComponent。
escape:采用ISO Latin字符集对指定的字符串进行编码。所有的空格、标点、特殊字符以及其他非ASCII字符都被转化为%xx格式的字符编码。
不编码字符(69个):*、+、-、.、/、@、_、0-9、a-z、A-Z
encodeURI:把URI字符串采用UTF-8格式编码。
不编码字符(82个):!、#、$、&、’、(、)、,、:、;、=、?、~、*、+、-、.、/、@、_、0-9、a-z、A-Z
进行URL跳转时可以整体使用encodeURI,例如:
Location.href=encodeURI(“http://localhost:8080/query?floor=5楼&version=2”);
encodeURIComponent:与encodeURI类似,只是该方法将对更多的字符进行编码。
不编码字符(71个):!、’、(、)、~、*、-、.、_、0-9、a-z、A-Z
传递参数时需要使用encodeURIComponent,这样组合的URL才不会被#等特殊字符截断。
JavaScript编码后的参数,服务器端可以用URLDecoder.decode来解码。但是需要注意的是,Tomcat会自动先对URL做一次解码,但这次解码并非是使用URLDecoder.decode。针对这种情况一种方案就是在JavaScript中对参数进行两次encodeURIComponent编码。