APP下载

Tom cat环境下JSP中文乱码问题的解决

2011-08-15

湖南第一师范学院学报 2011年4期
关键词:乱码编码方式表单

彭 立

(湖南第一师范学院信息科学与工程系,湖南 长沙 410205)

Tom cat环境下JSP中文乱码问题的解决

彭 立

(湖南第一师范学院信息科学与工程系,湖南 长沙 410205)

Web服务器Tom cat的中文乱码问题给软件开发人员带来了很大的困惑。为解决这一问题,可通过分析各种编码方式之间的相互转换,发现中文乱码问题的根源,并对各种出错情况进行分析,找出解决问题的办法。

Tomcat;JSP;中文乱码;编码;转换

一、引言

Tomcat作为SUN公司官方推荐的JSP和Servlet容器,因其开源、免费、跨平台、配置简单等特点,得到了广大软件开发人员的喜爱。然而,在中文操作系统上用Tomcat作为Web服务器来开发网站时,会出现中文乱码问题,从而给软件开发人员带来了很大的困惑。有人对这些问题进行过分析,但提出的解决办法并不全面也不完全正确。Tomcat环境下的中文乱码问题涉及范围很广,本文旨在解决其中的一类问题:JSP中文乱码问题。现将Tomcat环境下常见的JSP中文乱码问题列举如下:

问题一:JSP(以下都将JSP文件简称为JSP)本身包含的中文内容在IE(以下都将IE浏览器简称为IE)中显示为乱码。

问题二:表单通过POST方式提交给JSP的中文信息在IE中显示为乱码。

问题三:表单通过GET方式提交给JSP的中文信息在IE中显示为乱码。

为了解决Tomcat环境下JSP中文乱码问题,有必要先了解该环境下使用的编码方式。

二、Tom cat的编码方式

解决其他系统软件的中文乱码问题所获得的经验告诉我们,中文乱码问题往往跟字符的编码方式有关。编码方式是指字符在计算机内的表现形式,也就是机内码。在Tomcat环境下使用的编码方式(即字符集)主要有四种:UNICODE、UFT-8、GB2312-80/GBK和ISO-8859-1。

(一)UN ICODE

UNICODE是Java内部采用的编码方式,也就是说,当Java程序运行时,数据都会转换为UNICODE编码保存在内存中。UNICODE是DBCS(双字节字符集),它和任意国家/区域使用的本地字符集之间存在相互映射的关系,通过这样一种映射关系,它和本地字符集可相互转换。Java虚拟机通过操作系统的Codepage得知系统采用的字符集后,就可以使Java程序中的数据在UNICODE编码和本地字符编码之间相互转换。

(二)UTF-8

UTF-8以8个二进制位为单元对UNICODE进行编码,它是网络数据传输以及Java类文件所采用的编码方式。Tomcat环境下的JSP编译成的Servlet类文件就是以UTF-8编码方式保存的。UTF-8编码的长度不一,通常西文字符为一个字节,而汉字需三个字节。

(三)GB2312-80/GBK

GB2312-80/GBK是汉字的国际码。中文操作系统中汉字的编码方式都为GB2312-80/GBK,而西文字符的编码方式为ISO-8859-1。GB2312-80/GBK是DBCS,其中GB2312-80只能表示简体字,它包含了大部分常用的一、二级汉字和9区的符号;GBK是GB2312-80 的扩展,既可表示简体字也可表示繁体字,它包含了20902个汉字,其编码范围是0X8140~0XFEFE,剔除高字节为0X80的字位,其所有字符都可以一对一映射到UNICODE 2.0。

(四)ISO-8859-1

ISO-8859-1是SBCS(单字节字符集),属于西欧字符集,它是Tomcat默认的编码方式。如无特殊说明,在编译JSP时,Tomcat会把JSP的编码方式默认看成ISO-8859-1;接收表单输入数据时,Tomcat会将数据的编码方式默认看成ISO-8859-1;输出数据到IE时,Tomcat会默认将数据从UNICODE编码转换为ISO-8859-1编码。

三、编码方式的转换

在Java程序运行时,数据以UNICODE编码的形式保存在内存中,Tomcat根据需要,可将其转换为UFT-8编码、GB2312-80编码或ISO-8859-1编码,也可转换回来。Tomcat环境下的JSP从编译到输出,中间要经过多次编码转换;JSP接收表单数据后输出到IE,期间也涉及到多次编码转换。

(一)UN ICODE和UFT-8之间的转换

UNICODE和UFT-8之间的转换通常是网络传输和保存文件的需要。因为UNICODE和UFT-8是一一对应的,这两者之间的转换通常不会造成中文乱码问题。

(二)UN ICODE和GB2312-80之间的转换

GB2312-80中所有的字符编码都可转换为对应的UNICODE编码,例如,汉字“你”的GB2312-80编码为0XC4E3,对应的UNICODE编码为U4F60。但是,一个不在GB2312-80中的字符编码被当作GB2312-80转换为UNICODE时,会被转换为一个特殊编码UFFFD。反过来,并不是所有的UNICODE编码都能转换为GB2312-80编码,只有汉字字符的UNICODE编码才能被转换为对应的GB2312-80编码,例如,汉字“好”的 UNICODE编码为U597D,对应的GB2312-80编码为0XBAC3。不能映射到GB2312-80的UNICODE编码转换为GB2312-80编码时,结果为0X3F,显示出来是“?”。又如,U00D6转换为GB2312-80编码为0X3F。UNICODE编码U00A0~U00FF之间有20个编码在转换为GB2312-80编码后,显示出来都是乱码字符。再如,U00EC转换为GB2312-80编码为0XA8AC,显示出来为乱码字符“ì”。

(三)UN ICODE和ISO-8859-1之间的转换

ISO-8859-1中所有的字符编码都可转换为对应的UNICODE编码,转换方法为:在ISO-8859-1编码的前面加上0X00。例如字符“A”的ISO-8859-1编码为0X41,对应的UNICODE编码为0X0041。一个不在ISO-8859-1中的字符编码被转换为UNICODE编码时,系统并不效验被转换的是否为ISO-8859-1编码,而是直接按转换方法在编码的前面加上0X00。反过来,并不是所有的UNICODE编码都能转换为ISO-8859-1编码。如果UNICODE中某个字符编码能被转换为ISO-8859-1编码,那么它的高字节必为0X00,去掉高字节0X00,保留低字节,便形成了对应的ISO-8859-1编码,例如,字符“B”的UNICODE编码为 U0042,对应的ISO-8859-1编码为0X42。不能映射到ISO-8859-1的UNICODE编码被转换为ISO-8859-1编码时,结果为0X3F,显示出来是“?”,又如汉字“好”的UNICODE编码为U597D,转换为ISO-8859-1编码为0X3F[1]。

四、Tom cat中文乱码问题的原因

在Tomcat环境下,字符通常要经过“编码方式A→UNICODE→编码方式B”这样一个过程,才能最终输出。

现以汉字“的”为例,看看在GB2312-80→UNICODE→ISO-8859-1和 ISO-8859-1→UNICODE→GB2312-80这两种情况下分别会出现什么问题。“的”字的GB2312-80编码为0XB5C4。在第一种情况下,“的”字的编码方式被看作是GB2312-80,转换成的UNICODE编码为U7684,再由UNICODE编码转换成ISO-8859-1编码后,结果是0X3F,显示出来是一个“?”号。在第二种情况下,“的”字的编码方式被看作ISO-8859-1,转换成的UNICODE编码为U00B5U00C4,再由UNICODE编码转化为GB2312-80编码后,结果是0XA6CC0X3F,显示出来是“μ?”这样两个乱码字符。

可以看出以上两种情况都会造成中文乱码问题,错误的编码转换过程是Tomcat中文乱码问题的根源。

五、JSP中文乱码问题的分析和解决

(一)问题一的分析和解决

Tomcat环境下的JSP被IE访问时要经过“编译成Servlet→载入运行→输出到IE”这样三个阶段。现分析一下在每个阶段中编码方式是如何转换的。

1.编译成Servlet

当JSP被IE访问时,Tomcat会采取以下方式来判断JSP采用了哪种编码方式:首先,它会检查JSP中是否有 <%@page pageEncoding=”xx”%> 这行语句(只有JSP2.0才支持这种的语句),如果有,它会把JSP的编码方式看成是xx;否则,它会检查JSP 中 是 否 有 <%@page contentType=”text/html;charset=yy”%>这行语句,如果有,它会把JSP的编码方式看成是yy;如果两者都无,它会把JSP的编码方式默认看成ISO-8859-1。确定了JSP的编码方式后(尽管不一定与实际相符),Tomcat会将JSP从该编码方式转换为UNICODE编码[2],并将UNICODE编码的JSP编译为Servlet类文件,然后将Servlet类文件从UNICODE编码转换为UFT-8编码,并保存在磁盘上。

2.载入运行

JSP编译成的Servlet类文件被载入内存运行时,Tomcat会将Servlet类文件由UFT-8编码转换回UNICODE编码。因为UFT-8编码和UNICODE编码是一一对应的,UFT-8和UNICODE间的相互转换不会导致乱码问题。

3.输出到IE

Servlet将信息输出到IE之前,Tomcat会检查其对应的 JSP中是否有 <%@page contentType=”text/html;charset=xx”%>这行语句。如果有,Tomcat会将输出信息由UNICODE编码转换为xx编码,然后输出到IE,IE的编码方式也会自动被设置为xx;如果JSP中没有以上语句,但有<%@page pageEncoding=”yy”%> 这行语句,Tomcat会将输出信息由UNICODE编码转换为yy编码,然后输出到IE,IE的编码方式也会自动被设置为yy;如果JSP中以上两种语句都没有,Tomcat会将输出信息由UNICODE编码默认转换为ISO-8859-1编码,然后输出到IE,IE的编码方式会被自动设置为ISO-8859-1。

通过以上分析可以看出,Tomcat环境下的JSP被IE访问时要经过“编码方式A→UNICODE→编码方式B”这样一个过程,这一过程中的错误编码转换会导致问题一的出现。问题一通常由以下两种情况造成:

情况一:JSP中没有包含语句 <%@page pageEncoding=”xx”%> 和 <%@page contentType=”text/html;charset=yy”%>。假设JSP中有一汉字“的”(以下都以“的”字为例),现分析为什么“的”字在IE中显示时会变成乱码。在中文操作系统中,JSP以GB2312-80编码保存,因此,JSP文件中“的”字的编码为0XB5C4。因为JSP中没有以上两种语句,在对JSP进行编译时,Tomcat会把JSP的编码方式默认当作ISO-8859-1,从而将0XB5C4转换为UNICODE编码U00B5U00C4。Servlet输出信息到IE时,因JSP源文件中没有以上两种语句,Tomcat会将UNICODE编码U00B5U00C4转换为ISO-8859-1编码0XB5C4,然后输出到IE。因为IE的编码方式会被自动设置为ISO-8859-1,它将编码0XB5C4显示为乱码“μ?”。

情况二:JSP中同时包含有语句 <%@page pageEncoding=”xx”% > 和 <%@page contentType=”text/htm l;charset=yy”%>,但xx和yy之中只有一个为GB2312-80,另一个为ISO-8859-1。如果xx为GB2312-80,yy 为 ISO-8859-1,“的”字在输出时,它的编码会经历0XB5C4→U7684→0X3F这样一个转换过程,最终在IE中显示为一个“?”号。如果xx 为 ISO-8859-1,yy 为 GB2312-80,“的”字在输出时,它的编码会经历0X B5C4→U00b5U00c4→0XA6CC0X3F这样一个转换过程,最终在IE中显示为“μ?”这样两个乱码字符。

解决问题一的方法很简单,只要在JSP中包含语 句 <%@page pageEncoding=”GB2312-80”%> 或<%@page contentType=”text/htm l;charset=GB2312-80”%>即可,这样就可以保证JSP中的中文内容在编译时由GB2312-80编码转换为UNICODE编码,在输出时由UNICODE编码转换回GB2312-80编码。如果要在JSP中同时使用这两种语句,要确保两种语句中的编码方式都为GB2312-80。

(二)问题二、问题三的分析和解决

除了被IE直接访问,JSP还可以被表单调用,从而实现表单输入信息由JSP接收后再输出到IE显示。表单调用JSP时,实质上是调用其编译而成的Servlet。表单输入信息由IE传给Tomcat,再由Tomcat传给运行中的Servlet,最后由Servlet输出到IE进行显示。之前已对Servlet输出信息到IE时出现的编码转换进行过分析,这里不再赘述,接下来只对表单输入信息经Tomcat传递给Servlet时出现的编码转换进行分析。表单调用JSP时,通常采取两种方式:POST方式和GET方式。

1.POST方式

在POST方式下,表单输入数据放在IE请求消息的实体部分传给Tomcat。Servlet中的Request对象通过getParameter方法向Tomcat请求表单输入数据时,Tomcat会检查Request对象的编码方式属性。如果在Request对象调用getParameter方法之前,其编码方式属性已通过request.setCharacterEncoding(“xx”)语句被设置成xx,Tomcat会把输入数据的编码方式看成是xx。如果Servlet中没有这行语句,Tomcat会将输入数据的编码方式默认看成是ISO-8859-1。确定了表单输入数据的编码方式后(尽管不一定与实际相符),Tomcat会将输入数据从该编码方式转换为UNICODE编码,然后传递给Servlet[3]。

可以发现在POST方式下,表单输入数据通过JSP输出到IE时,同样要经历“编码方式A→UNICODE→编码方式B”这样一个过程,这一过程中的错误编码转换会导致问题二的出现。问题二通常由以下两种情况造成(假定在这两种情况中,表单所在的HTML页面的编码方式都为GB2312-80,那么表单中的汉字信息在传给Tomcat时,编码方式都为GB2312-80):

情况一:JSP中既没有语句<%@page pageEncoding=”xx”%> 和 <%@page contentType=”textml;charset=yy”%>,也没有语句request.setCharacterEncoding(“zz”)。因为JSP中没有语句request.setCharacterEncoding(“zz”),Tomcat会将表单输入数据的编码方式看成是ISO-8859-1,并转换成UNICODE编码,因此“的”字的编码会从0XB5C4转换为U00B5U00C4。Servlet输出信息到IE时,因为JSP中没有语句 <%@page pageEncoding=”xx”%> 和<%@page contentType=”textml;charset=yy”%>,Tomcat会将编码U00B5U00C4转换为ISO-8859-1编码0XB5C4,并输出到IE。因为IE的编码方式会被自动设置为ISO-8859-1,编码0XB5C4显示为乱码“μ?”。

情况二:JSP中包含有语句<%@page pageEncoding=”GB2312-80”%> 或 <%@page contentType=”textml;charset=GB2312-80”%>,但没有语句request.setCharacterEncoding(“zz”)。情况二和情况一的不同之处在于:情况二的JSP中包含了语句<%@page pageEncoding=”GB2312-80”%> 或 <%@page content-Type=”textml;charset=GB2312-80”%>,因此”的“字被Servlet输出到IE时,它的编码会从U00B5U00B4转换为GB2312-80编码0XA6CC0X3F,输出到IE显示为“μ?”这样两个乱码字符。

解决问题二有两种方法。

方法一:确保JSP中包含有语句<%@page pageEncoding=”GB2312-80”%> 或 <%@page content-Type=”textm l;charset=GB2312-80”%>,此外,在 Request对象调用getParameter方法之前加上语句request.setCharacterEncoding(“GB2312-80”)。这种方法可确保表单中输入的中文信息通过JSP输出到IE时会经过GB2312-80→UNICODE→GB2312-80这样一个正确的编码转换过程。

方法二:确保JSP中包含有语句<%@page pageEncoding=”GB2312-80”%> 和 <%@page content-Type=”textml;charset=GB2312-80”%>,此外,将 Request对象调用getParameter方法的语句改为String Output=new(request.getParameter(“Input”).getBytes(“ISO8859_1”)),然后输出字符串Output即可。现说明一下这种方法为什么可行。在request.getParameter(“Input”)执行之前,并没有设置Request对象的编码方式,因此表单中汉字的编码方式被当成是ISO-8859-1,然后转换成UNICODE传给Servlet,因而,“的”字的编码从0XB5C4转换为U00B5U00C4。调用了getBytes(“ISO8859_1”)方法后,“的”字的编码又变回了0XB5C4,相当于又变成了GB2312-80编码。通过new方法生成字符串 Output时,该GB2312-80编码会转换成对应的UNICODE编码。在字符串Output被输出时,字符串的内容从UNICODE编码转换成GB2312-80编码输出。通过以上分析发现,该方法可确保表单中输入的中文信息通过JSP输出时会经过ISO-8859-1→UNICODE→ISO-8859-1(GB2312-80)→UNICODE→GB2312-80这样一个正确的编码转换过程。

2.GET方式

在GET方式下,表单输入数据放在IE请求消息的请求行之中传给Tomcat。通过查看Tomcat的源代码可以发现,Tomcat对GET方式下表单输入数据的处理采用了和POST方式不同的方法。当Request对象通过getParameter方法向Tomcat请求表单输入数据时,Tomcat不会检查Request对象的编码方式属性,而是检查配置文件server.xml中port值为 8080的 connector元素的 URIEncoding属性,并将表单输入数据的编码方式看成URIEncoding属性所设置的编码方式。如果server.xml中port值为8080的connector元素没有对URIEncoding属性进行设置,Tomcat会将输入数据的编码方式默认当作ISO-8859-1[4]。

知道了Tomcat在GET方式下对表单输入数据所采用的处理方法,不难为问题三找到解决办法,主要有两种:

方法一:确保JSP中包含有语句<%@page pageEncoding=”GB2312-80”%> 或 <%@page content-Type=”textml;charset=GB2312-80”%>,此外,将配置文件server.xml中port值为8080的connector元素的URIEncoding属性设置为GB2312-80。这种方法可确保表单中输入的中文信息通过JSP输出到IE时会经过GB2312-80→UNICODE→GB2312-80这样一个正确的编码转换过程。

方法二:确保JSP中包含有语句<%@page pageEncoding=”GB2312-80”%> 和 <%@page content-Type=”textml;charset=GB2312-80”%>,此外,将 JSP中Request对象调用getParameter方法的语句改为String Output=new(request.getParameter(“Input”).get-Bytes(“ISO8859_1”)),然后输出字符串Output即可。此方法可行的原因和问题二的方法二相同,此处不再累述。这种方法可确保表单中输入的中文信息通过 JSP输出到 IE时会经过 ISO-8859-1→UNICODE→ISO-8859-1(GB2312-80)→UNICODE→GB2312-80这样一个正确的编码转换过程。

六、结语

Tomcat环境下JSP中文乱码问题的根源是错误的编码转换过程,对各种出错情况进行分析后,不难找出这些问题的解决办法。以上分析对解决Tomcat环境下其他类型的中文乱码问题也具有指导作用。文中的测试都是在Tomcat5.0.28下进行的,所有的解决方法都在该版本下验证通过。

[1]JrneforsO.AshortoverviewofISO/IEC10646andUni code[DB/OL].http://www.nada.kth.se/i18n/ucs/unicodeiso10646-oview.htm l

[2]LindenbergN.DevelopingMultilingualWebApplications UsingJavaServerPagesTechnology[DB/OL].http://java.sun.com/developer/technicalArticles/Intl/MultilingualJSP/index.htm l

[3]孙卫琴,李洪成.Tomcat与JavaWeb开发技术详解[M].北京:电子工业出版社,2004.

[4]Apache Software Foundation.ApacheTomcatConfiguration ReferenceTheHTTPConnector[DB/OL].http://tom cat.apache.org/tomcat-5.5-doc/config/http.htm l

The Solution to Chinese Lousy Code Problemsof JSPon Tom cat

PENG Li

(Departmentof Information Science and Engineering,Hunan FirstNormalUniversity,Changsha,Hunan 410205)

Chinese lousy code problems on Web server Tomcat have been puzzling software developers.To solve thisproblem,one should analyze the conversion between every encoding and find the reason that Chinese lousy code problemsare caused by false encoding-conversion processes.Then a solution to the problem may be found after a furtheranalysisofeach w rong case.

Tomcat;JSP;Chinese lousy code;encoding;conversion

TP311.1

A

1674-831X(2011)04-0128-05

2011-01-09

湖南第一师范学院院级课题(XYS10N09)

彭立(1974—),男,湖南汨罗人,湖南第一师范学院信息科学与工程系讲师。

[责任编辑:胡 伟]

猜你喜欢

乱码编码方式表单
电子表单系统应用分析
对症下药解决多种乱码难题
这些真的不是乱码,是汉字
浅谈网页制作中表单的教学
GCOA算法
可穿戴式多通道传感系统功能需求分析及设计
混合编码方式自适应差分进化算法优化设计宽带天线
炫迈:用神奇乱码勾引你视线
浅谈计算机网络通信中实时差错控制技术
动态表单技术在教学管理中的应用*