【Jsp精品源码栏目提醒】:文章导读:在新的一年中,各位网友都进入紧张的学习或是工作阶段。
网学会员整理了Jsp精品源码-【精品】JSP中文乱码问题解决 - 其它资料的相关内容供大家参考,祝大家在新的一年里工作和学习顺利!
JSP/Servlet 中的汉字编码问题 网上就
JSP/Servlet 中 DBCS 字符编码问题有许多优秀的文章和讨论,本文对它们作 一些整理,并结合 IBM WebSphere Application Server 3.5(WAS)的解决方法作一些 说明,希望它不是多余的。
1. 问题的起源 每个国家(或区域)都规定了计算机信息交换用的字符编码集,如美国的扩展 ASCII码 中国的 GB2312-80,日本的 JIS 等,作为该国家/区域内信息处理的基础,有着统一编码的重要作用。
字符编码集按长度分为 SBCS(单字节字符集) ,DBCS(双字节字符集)两大类。
早期的软件(尤其是操作系统) ,为了解决本地字符信息的计算机处理,出现了各种本地化版本(L10N) ,为了区分,引进了 LANG Codepage 等概念。
但是由于各个本地字符集代码范围重叠,相互间信息交换困难;软件各个本地化版本独立维护成本较高。
因此有必要将本地化工作中的共性抽取出来,作一致处理,将特别的本地化处理内容降低到最少。
这也就是所谓的国际化(I18N) 。
各种语言信息被进一步规范为 Locale 信息。
处理的底层字符集变成了几乎包含了所有字形的 Unicode。
现在大部分具有国际化特征的软件核心字符处理都是以 Unicode 为基础的,在软件运行时根据当时的 Locale/Lang/Codepage 设置确定相应的本地字符编码设置,并依此处理本地字符。
在处理过程中需要实现 Unicode 和本地字符集的相互转换,甚或以 Unicode 为中间的两个不同本地字符集的相互转换。
这种方式在网络环境下被进一步延伸,任何网络两端的字符信息也需要根据字符集的设置转换成可接受的内容。
Java 语言内部是用 Unicode 表示字符的,遵守 Unicode V2.0。
Java 程序无论是从/往文件系统以字符流读/写文件,还是往 URL 连接写 HTML 信息, 或从 URL 连接读取参数值,都会有字符编码的转换。
这样做虽然增加了编程的复杂度,容易引起混淆,但却是符合国际化的思想的。
从理论上来说, 这些根据字符集设置而进行的字符转换不应该产生太多问题。
而事实是由于应用程序的实际运行环境不同,Unicode 和各个本地字符集的补充、完善,以及系统或应用程序实现的不规范,转码时出现的问题时时困扰着程序员和用户。
2. GB2312-80,GBK,GB18030-2000 汉字字符集及 Encoding 其实解决 JAVA 程序中的汉字编码问题的方法往往很简单,但理解其背后的原因,定位问题,还需要了解现有的汉字编码和编码转换。
GB2312-80 是在国内计算机汉字信息技术发展初始阶段制定的,其中包含了大部分常用的一、二级汉字,和 9 区的符号。
该字符集是几乎所有的中文系统和国际化的软件都支持的中文字符集,这也是最基本的中文字符集。
其编码范围是高位 0xa1-0xfe,低位也是0xa1-0xfe;汉字从 0xb0a1 开始,结束于 0xf7fe。
GBK 是 GB2312-80 的扩展,是向上兼容的。
它包含了 20902 个汉字,其编码范围是0x8140-0xfefe,剔除高位 0x80 的字位。
其所有字符都可以一对一映射到 Unicode 2.0,也就是说 JAVA 实际上提供了 GBK 字符集的支持。
这是现阶段 Windows 和其它一些中文操作系统的缺省字符集, 但并不是所有的国际化软件都支持该字符集,感觉是他们并不完全知道 GBK 是怎么回事。
值得注意的是它不是国家标准,而只是规范。
随着 GB18030-2000国标的发布,它将在不久的将来完成它的历史使命。
GB18030-2000GBK2K 在 GBK 的基础上进一步扩展了汉字,增加了藏、蒙等少数民族的字形。
GBK2K 从根本上解决了字位不够,字形不足的问题。
它有几个特点, 它并没有确定所有的字形,只是规定了编码范围,留待以后扩充。
编码是变长的,其二字节部分与 GBK 兼容;四字节部分是扩充的字形、字位, 其编码范围是首字节 0x81-0xfe、二字节 0x30-0x39、三字节 0x81-0xfe、四字节 0x30-0x39。
它的推广是分阶段的, 首先要求实现的是能够完全映射到 Unicode 3.0 标准的所有 字形。
它是国家标准,是强制性的。
现在还没有任何一个操作系统或软件实现了 GBK2K 的支持,这是现阶段和将来汉化的工作内容。
Unicode 的介绍......就免了吧。
JAVA 支持的 encoding 中与中文编程相关的有:有几个在 JDK 文档中未列出ASCII 7-bit 同 ascii7ISO8859-1 8-bit 同 8859_1ISO-8859-1ISO_8859-1latin1...GB2312-80 同 gb2312 gb2312-1980 EUC_CN euccn 1381 Cp1381 1383 Cp1383 ISO2022CN ISO2022CN_GB…GBK 注意大小写同 MS936UTF8 UTF-8GB18030 现在只有 IBM JDK1.3.有支持 同 Cp13921392 JAVA 语言采用 Unicode 处理字符. 但从另一个角度来说,在 java 程序中也可以采用非Unicode 的转码,重要的是保证程序入口和出口的汉字信息不失真。
如完全采用 ISO-8859-1来处理汉字也能达到正确的结果。
网络上流行的许多解决方法,都属于这种类型。
为了不致引起混淆,本文不对这种方法作讨论。
3. 中文转码时、乱码的由来 两个方向转换都有可能得到错误的结果: Unicode--gtByte 如果目标代码集不存在对应的代码,则得到的结果是 0x3f. 如:quotu00d6u00ecu00e9u0046u00bbu00f9quot.getBytesquotGBKquot 的结果是 quotìéFùquot Hex 值是 3fa8aca8a6463fa8b4. 仔细看一下上面的结果, 你会发现u00ec 被转换为 0xa8ac u00e9 被转换为xa8a6... 它的实际有效位变长了! 这是因为 GB2312 符号区中的一些符号被映射到一些公 共的符号编码,由于这些符号出现在 ISO-8859-1 或其它一些 SBCS 字符集中,故 它们在 Unicode 中编码比较靠前, 有一些其有效位只有 8 位, 和汉字的编码重叠其 实这种映射只是编码的映射,在显示时仔细不是一样的。
Unicode 中的符号是单字 节宽,汉字中的符号是双字节宽 . 在 Unicodeu00a0--u00ff 之间这样的符号有 20 个。
了解这个特征非常重要!由此就不难理解为什么 JAVA 编程中,汉字编码的错 误结果中常常会出现一些乱码其实是符号字符 而不全是字符 就比如上面的 例子。
Byte--gtUnicode 如果 Byte 标识的字符在源代码集不存在, 则得到的结果是 0xfffd. 如: Byte ba byte0x81byte0x40byte0xb0byte0xa1 new Stringbaquotgb2312quot 结果是quot啊quot hex 值是quotufffdu554aquot. 0x8140 是 GBK 字符, GB2312 转换表没有 按 对应的值,取ufffd. 请注意:在显示该 uniCode 时,因为没有对应的本地字符,所 以也适用上一种情况,显示为一个quotquot. 实际编程中,
JSP/Servlet 程序得到错误的汉字信息,往往是这两个过程的叠加,有时甚至是两个过程叠加后反复作用的结果.4.
JSP/Servlet 汉字编码问题及在 WAS 中的解决办法4.1 常见的 encoding 问题的现象 网上常出现的
JSP/Servlet encoding 问题一般都表现在 browser 或应用程序端,如: 浏览器中看到的
Jsp/Servlet 页面中的汉字怎么都成了 ’’ 浏览器中看到的 Servlet 页面中的汉字怎么都成了乱码? JAVA 应用程序界面中的汉字怎么都成了方块?
Jsp/Servlet 页面无法显示 GBK 汉字。
JSP 页面中内嵌在lt...gtlt...gt等 Tag 包含的 JAVA code 中的中文成了乱码, 但页面的其它汉字是对的。
Jsp/Servlet 不能接收 form 提交的汉字。
JSP/Servlet 数据库读写无法获得正确的内容。
隐藏在这些问题后面的是各种错误的字符转换和处理 (除第 3 个外,是因为 Java font 设置错误引起的)。
解决类似的字符 encoding 问题,需要了解
Jsp/Servlet 的运行过程,检查可能出现问题的各个点。
4.2
JSP/Servlet web 编程时的 encoding 问题 运行于 Java 应用服务器的
JSP/Servlet 为 Browser 提供 HTML 内容,其过程如下图所示: a.
JSP 编译 b. JAVA 编译 c. Content-Type
JSP JAVA .class 客户 文件 文件 文件 浏览器 Java 应用程序服务器端 客户浏览器端 d. Parameters 其中有字符编码转换的地方有:
JSP 编译。
Java 应用服务器将根据 JVM 的 file.encoding 值读取
JSP 源文件,编 译生成 JAVA 源文件,再根据 file.encoding 值写回文件系统。
如果当前系统语言 支持 GBK,那么这时候不会出现 encoding 问题。
如果是英文的系统,如 LANG 是 en_US 的 Linux AIX 或 Solaris , 则 要 将 JVM 的 file.encoding 值 置 成 GBK 。
系统语言如果是 GB2312,则根据需要,确定要不要设置 file.encoding, 将 file.encoding 设为 GBK 可以解决潜在的 GBK 字符乱码问题 Java 需 要 被 编 译 为 .class 才 能 在 JVM 中 执 行 , 这 个 过 程 存 在 与 a. 同样 的 file.encoding 问题。
从这里开始 servlet 和
jsp 的运行就类似了, 只不过 Servlet 的 编译不是自动进行的。
对于
JSP 程序 对产生的 JAVA 中间文件的编译是自动进行 的在程序中直接调用 sun.tools.javac.Main 类. 因此如果在这一步出现问题的话 也要检查 encoding 和 OS 的语言环境, 或者将内嵌在
JSP JAVA Code 中的静态汉字 转为 Unicode 要么静态文本输出不要放在 JAVA code 中。
对于 Servlet javac 编 译时手工指定-encoding 参数就可以了。
Servlet 需要将 HTML 页面内容转换为 browser 可接受的 encoding 内容发送出 去 。
依 赖 于 各 JAVA App Server 的 实 现 方 式 , 有 的 将 查 询 Browser 的 accept-charset 和 accept-language 参数或以其它猜的方式确定 encoding 值,有的 则不管。
因此采用固定 encoding 也许是最好的解决方法。
对于中文网页,可在
JSP 或 Servlet 中设置 contentTypequottext/html charsetGB2312quot;如果页面中有 GBK 字符, 则设置为 contentTypequottext/html charsetGBKquot, 由于 IE 和 Netscape 对 GBK 的支持程度不一样,作这种设置时需要测试一下。
因为 16 位 JAVA char 在网络传 送时高 8 位会被丢弃,也为了确保 Servlet 页面中的汉字(包括内嵌的和 servlet 运 行过程中得到的)是期望的内码,可以用 PrintWriter outres.getWriter 取代 ServletOutputStream outres.getOutputStream. PrinterWriter 将根据 contentType 中 指 定 的 charset 作 转 换 ContentType 需 在 此 之 前 指 定 ! 也 可 以 用 OutputStreamWriter 封装 ServletOutputStream 类并用 writeString输出汉字字符串。
对于
JSP,JAVA Application Server 应当能够确保在这个阶段将嵌入的汉字正确传 送出去。
这是解释 URL 字符 encoding 问题。
如果通过 get/post 方式从 browser 返回的参 数 值 中 包 含 汉 字 信 息 , servlet 将 无 法 得 到 正 确 的 值 。
SUN 的 J2SDK 中 , HttpUtils.parseName 在解析参数时根本没有考虑 browser 的语言设置,而是将得 到的值按 byte 方式解析。
这是网上讨论得最多的 encoding 问题。
因为这是设计 缺陷,只能以 bin 方式重新解析得到的字符串;或者以 hack HttpUtils 类的方式 解决。
参考文章 2 均有介绍,不过最好将其中的中文 encoding GB2312、 CP1381 都改为 GBK,否则遇到 GBK 汉字时,还是会有问题。
Servlet API 2.3 提供一个 新 的 函 数 HttpServeletRequest.setCharacterEncoding 用 于 在 调 用 request.getParameter“param_name” 前指定应用程序希望的 encoding,这将有助 于彻底解决这个问题。
4.3 IBM Websphere Application Server 中的解决方法 WebSphere Application Server 对标准的 Servlet API 2.x 作了扩展,提供较好的多语言支持。
运行在中文的操作系统中,可以不作任何设置就可以很好地处理汉字。
下面的说明只是对 WAS 是运行在英文的系统中,或者需要有 GBK 支持时有效。
上述 cd 情况,WAS 都要查询 Browser 的语言设置,在缺省状况下, zh zh-cn 等均被映射为 JAVA encoding CP1381(注意: CP1381 只是等同于 GB2312 的一个 codepage,没有 GBK 支持) 。
这样做我想是因为无法确认 Browser 运行的操作系统是支持 GB2312还是 GBK,所以取其小。
但是实际的应用系统还是要求页面中出现 GBK 汉字,最著名的是朱总理名字中的 “镕quotrong2 ,0xe946,u9555,所以有时还是需要将 Encoding/Charset 指定为 GBK。
当然 WAS 中变更缺省的 encoding 没有上面说的那么麻烦,针对 ab,参考文章 5,在 Application Server 的命令行参数中指定 -Dfile.encodingGBK 即可; 针对 d,在 Application Server 的命令行参数中指定-Ddefault.client.encodingGBK。
如果指定了-Ddefault.client.encodingGBK,那么 c 情况下可以不再指定 charset。
上面列出的问题中还有一个关于 Taglt...gtlt...gt中的 JAVA 代码里包含的静态文本未能正确显示的问题, WAS 中的解决方法是除了设置正确的 file.encoding 还需要以 在相同方法设置-Duser.languagezh -Duser.regionCN。
这与 JAVA locale 的设置有关。
4.4 数据库读写时的 encoding 问题
JSP/Servlet 编程中经常出现 encoding 问题的另一个地方是读写数据库中的数据。
流行的关系数据库系统都支持数据库 encoding,也就是说在创建数据库时可以指定它自己的字符集设置,数据库的数据以指定的编码形式存储。
当应用程序访问数据时,在入口和出口处都会有 encoding 转换。
对于中文数据,数据库字符编码的设置应当保证数据的完整性. GB2312,GBK,UTF-8 等都是可选的数据库 encoding;也可以选择 ISO8859-18-bit,那么应用程序在写数据之前须将 16Bit 的一个汉字或 Unicode 拆分成两个 8-bit的字符,读数据之后则需将两个字节合并起来,同时还要判别其中的 SBCS 字符。
没有充分利用数据库 encoding 的作用,反而增加了编程的复杂度,ISO8859-1 不是推荐的数据库encoding。
JSP/Servlet 编程时,可以先用数据库管理系统提供的管理功能检查其中的中文数据是否正确。
然后应当注意的是读出来的数据的 encoding,JAVA 程序中一般得到的是 Unicode。
写数据时则相反。
4.5 定位问题时常用的技巧 定位中文 encoding 问题通常采用最笨的也是最有效的办法——在你认为有嫌疑的程序处理后打印字符串的内码。
通过打印字符串的内码, 你可以发现什么时候中文字符被转换成Unicode,什么时候 Unicode 被转回中文内码,什么时候一个中文字成了两个 Unicode 字符,什么时候中文字符串被转成了一串问号,什么时候中文字符串的高位被截掉了…… 取用合适的样本字符串也有助于区分问题的类型。
如: ”aa 啊 aa 丂 aa” 等中英相间、GB、GBK 特征字符均有的字符串。
一般来说,英文字符无论怎么转换或处理,都不会失真(如果遇到了,可以尝试着增加连续的英文字母长度) 。
5. 结束语 其实
JSP/Servlet 的中文 encoding 并没有想像的那么复杂,虽然定位和解决问题没有定规,各种运行环境也各不尽然,但后面的原理是一样的。
了解字符集的知识是解决字符问题的基础。
不过,随着中文字符集的变化,不仅仅是 java 编程,中文信息处理中的问题还是会存在一段时间的。
Java 编程技术中汉字问题的分析及解决 段 明 辉 在基于 Java 语言的编程中,我们经常碰到汉字的处理及显示的问题。
一大堆看不懂的乱码 肯定不是我们愿意看到的显示效果,怎样才能够让那些汉字正确显示呢?Java 语言默认的编码 方式是 UNICODE ,而我们中国人通常使用的文件和数据库都是基于 GB2312 或者 BIG5 等方 式编码的,怎样才能够恰当地选择汉字编码方式并正确地处理汉字的编码呢?本文将从汉字编 码的常识入手,结合 Java 编程实例,分析以上两个问题并提出解决它们的方案。
现在 Java 编程语言已经广泛应用于互联网世界,早在 Sun 公司开发 Java 语言的时候,就已经考虑到对非英文字符的支持了。
Sun 公司公布的 Java 运行环境(JRE)本身就分英文版和国际版,但只有国际版才支持非英文字符。
不过在 Java 编程语言的应用中,对中文字符的支持并非如同 Java Soft 的标准规范中所宣称的那样完美,因为中文字符集不只一个,而且不同的操作系统对中文字符的支持也不尽相同, 所以会有许多和汉字编码处理有关的问题在我们进行应用开发中困扰着我们。
有很多关于这些问题的解答,但都比较琐碎,并不能够满足大家迫切解决问题的愿望,关于 Java 中文问题的系统研究并不多,本文从汉字编码常识出发,分析 Java 中文问题,希望对大家解决这个问题有所帮助。
汉字编码的常识 我们知道,英文字符一般是以一个字节来表示的,最常用的编码方法是 ASCII 。
但一个字节最多只能区分 256 个字符,而汉字成千上万,所以现在都以双字节来表示汉字,为了能够与英文字符分开,每个字节的最高位一定为 1,这样双字节最多可以表示 64K 格字符。
我们经常碰到的编码方式有 GB2312、BIG5、UNICODE 等。
关于具体编码方式的详细资料,有兴趣的读者可以查阅相关资料。
我肤一下和我们关系密切的 GB2312 和UNICODE。
GB2312 码,中华人民共和国国家标准汉字信息交换用编码,是一个由中华人民共和国国家标准总局发布的关于简化汉字的编码, 通行于中国大陆地区及新加坡,简称国标码。
两个字节中,第一个字节(高字节)的值为区号值加 32(20H) ,第二个字节(低字节)的值为位号值加 32(20H) ,用这两个值来表示一个汉字的编码。
UNICODE 码是微软提出的解决多国字符问题的多字节等长编码,它对英文字符采取前面加“0”字节的策略实现等长兼容。
如 “A” 的 ASCII 码为 0x41,UNICODE 就为 0x00,0x41。
利用特殊的工具各种编码之间可以互相转换。
Java 中文问题的初步认识 我们基于 Java 编程语言进行应用开发时,不可避免地要处理中文。
Java 编程语言默认的编码方式是 UNICODE,而我们通常使用的数据库及文件都是基于 GB2312 编码的,我们经常碰到这样的情况:浏览基于
JSP 技术的网站看到的是乱码,文件打开后看到的也是乱码,被 Java 修改过的数据库的内容在别的场合应用时无法继续正确地提供信息。
String sEnglish “apple” String sChinese “苹果” String s “苹果 apple ” sEnglish 的长度是 5,sChinese 的长度是 4,而 s 默认的长度是 14。
对于 sEnglish 来说, Java 中的各个类都支持得非常好,肯定能够正确显示。
但对于 sChinese 和 s 来说,虽然 Java Soft 声明 Java 的基本类已经考虑到对多国字符的支持 (默认 UNICODE 编码) ,但是如果操作系统的默认编码不是 UNICODE ,而是国标码等。
从 Java 源代码到得到正确的结果,要经过 “Java 源代码-gt Java 字节码-gt 虚拟机-gt操作系统-gt显示设备”的过程。
在上述过程中的每一步骤, 我们都必须正确地处理汉字的编码, 才能够使最终的显示结果正确。
“ Java 源代码-gt Java 字节码” ,标准的 Java 编译器 javac 使用的字符集是系统默认的字符集,比如在中文 Windows 操作系统上就是 GBK 而在 Linux 操作系统上就是ISO-8859-1,所以大家会发现在 Linux 操作系统上编译的类中源文件中的中文字符都出了问题,解决的办法就是在编译的时候添加 encoding 参数,这样才能够与平台无关。
用法是 javac –encoding GBK。
“ Java 字节码-gt虚拟机-gt操作系统” Java 运行环境 (JRE) 分英文版和国际版, ,但只有国际版才支持非英文字符。
Java 开发工具包 (JDK) 肯定支持多国字符,但并非所有的计算机用户都安装了 JDK 。
很多操作系统及应用软件为了能够更好的支持 Java ,都内嵌了 JRE 的国际版本,为自己支持多国字符提供了方便。
“操作系统-gt显示设备” ,对于汉字来说,操作系统必须支持并能够显示它。
英文操作系统如果不搭配特殊的应用软件的话,是肯定不能够显示中文的。
还有一个问题,就是在 Java 编程过程中,对中文字符进行正确的编码转换。
例如,向网页输出中文字符串的时候,不论你是.