教你一招搞定jsp中的中文乱码问题

在jsp中经常遇到中文乱码的问题,主要是因为其中涉及到了很多次的编码转换的问题,其中只要有一步转换出了错误,那么最后的结果就会出现中文的乱码问题。

    分析一下jsp页面到浏览器显示过程中的编码转换。

    首先,是jsp页面的源代码,不管是通过eclipse还是通过一般的文本编辑器,最后会得到一个硬盘上的.jsp的文件。 计算机硬盘上保存的所有文件都是二进制的。 从人眼可以读的字符到硬盘上保存的二进制之间存在一个编码的转换,一般而言,编码起源于ASCII,其使用一个字节的低7位(bit)来代表英文中的字母表和常见的英文字符,起源于美国。 但是,无法表示别国字符,因此,欧洲,希腊等国家在ASCII编码表的基础之上通过使用高一位字节来扩充该编码,形成自己国家特定的编码表,这就是ISO8859编码表,这是一个系列,包括 14 个字符码表,其中西欧的称为ISO8859-1,希腊的是ISO8859-7。

     因为中文字符数量很多,所以在1980年第一个中文字符编码表中采用了2个字节,16位来编码中文字符,称为gb2312编码表,当然后来经过扩充也形成了gbk(1980年)(包括繁体字编码和一些拉丁字符等),再后来经过进一步的扩充得到gb18030(2000年),它在gbk的基础上增加了藏文、蒙文、维吾尔文等主要的少数民族文字编码。这些中文编码表都是向下兼容的,也就是说随着时间的推移逐渐扩充形成原来编码表的超集。 其中,一般情况下使用最多的就是gb2312,它包含了所有常见的汉字和一些其它符号,如果遇到要同时表示繁体字和简体字就需要使用gbk编码了,除非遇到特别生僻的汉字,否则一般很少使用gb18030。同样的在其它国家也形成了自己特定的编码表,所有的这些编码表都只是针对特定国家的字符的编码表,统称为ANSI编码表。 ANSI编码表的含义就是一个国家默认的最常用的字符编码表,例如,对中国ANSI就是gb2312. 所有的这些编码表都是在ASCII的基础上建立起来的,所以,不管使用什么编码表来解码,都不会产生英语字母的乱码,因为这些属于ASCII编码,而且在所有的编码表中都使用了相同的编码来表示。 但是,当使用某种ANSI本地化编码表编码,而使用其它的编码表来解码的时候会出现乱码。

   还有一个问题,在这种格局下,就无法在同一篇文档里面同时保存多国文字了。 为了解决这一的问题,产生了unicode编码。 universal multi-octal coding  cahr set. 它采用了2个字节,18bits试图编码世界上所有的字符。 也就是说,unicode编码出了兼容ASCII以外, 不兼容任何ANSI编码。 由于unicode编码使用固定长度来进行字符编码,对网络传输和存储都不是很有效率,于是产生了utf系统编码,其中最常见的就是utf-8编码,该编码采用一个字节来编码字符,且是变长的,它与unicode编码是兼容的,只是在传输及存储上进行了一些编码上的优化而已。

    那么,现在分析一下jsp编码过程。  首先jsp文件会以一种编码表保存到硬盘上, 为了能保持中文,一般选择gb2312或者gbk,也可以选择utf-8或者unicode. 然后, 当浏览器第一次请求该jsp页面的时候,jsp容器就会编译该jsp文件得到一个servelt的java源文件。在这一步很关键,jsp容器在将jsp编译成java文件的时候,会选择一种编码表来读取硬盘上的jsp文件,举一个简单的比喻, 现在硬盘上存放的jsp文件是一个字节文件,所有需要持久化或者在网络上传输的都只能以字节码的形式进行,所谓字节码就是这些内容都是二进制的bit,且以每8个bit为一个字节来保存。 那么这些一串一串的8bit的字节究竟是什么含义? 这个就必须靠编码表来确定了,简单的说,解码时使用的编码表不同,得到的结果也不同,只有当解码时的编码表与编码时候使用的编码表一致的时候,解码的结果才是正确的,比如,我想保存一个“我在这里”的信息,然后我查寻gb2312编码表,知道二进制“101001001001010100101010”代表中文串“我在这里”, 于是我就把这个二进制串存放到计算机上的硬盘上。下一次, 有个程序要读该硬盘文件的时候, 它得到的就是一个这样的二进制串,那么它想知道是代表什么意思,就必须解码,如果它解码使用的是gb2312编码表,那么它就可以得到正确的意思“我在这里”,如果它使用不兼容的编码表进行解码,很可能在那个编码表中该二进制串代表了其它的字符或者根本就没有对应的字符,那么结果就是那些很奇怪的其它字符或者是问号,这就是所谓的乱码了。

     在这一步中jsp容器默认会采用utf-8来进行解码,而utf-8是基于unicode编码表的,它与所有本地化的中文编码,比如gb2312,gbk等都是不兼容的, 所以,解码的结果就是所有的中文会变成乱码,这样得到的 java文件中的中文就是乱码了。

     要解决这一步的乱码根源,要么将jsp编码改为utf-8,通过设置<%@ page language="java" pageEncoding="utf-8"%>,或者修改jsp容器默认的解码过程使用的编码表成gb2312.

    这样得到的java文件中就能正确显示中文了。

   下面的 步骤就是通用的java文件编码过程了,在该过程中也会涉及到编码问题。

   首先,容器会调用javac命令来讲jsp产生的java源文件编译成.class类文件。 具体的说, 容器会先读入硬盘上的java源文件(二进制),然后采用默认的utf-8进行解码,得到java文件的内容,然后将这些内容转换成unicode编码,unicode编码是java通用的内部编码格式。最后将该unicode编码写入.class文件。

   当客户浏览器调用该class的时候,jvm会载入该class文件至内存中,执行其方法,将执行结果(假设包含中文)以某种编码格式(通过:<%@ page contentType="text/html; charset= GBK" %设置也可以在java代码中通过response.setCharacterEncoding("GBK")来设置)编码后通过response对象发送到浏览器,浏览器在显示的时候会解码,一般浏览器会根据response的header来确定正确的解码格式,如果不正确,也会出现乱码,必须保证浏览器解码格式与response中的编码格式一样,才能正确显示。

 

基本过程就是上面这些,如果出现乱码,按照上述流程检查各个环节的编码和解码,只要保证各部分编码正确,就可以避免中文乱码了。

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

walkingmanc

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值