广告广告
  加入我的最爱 设为首页 风格修改
首页 首尾
 手机版   订阅   地图  繁体 
您是第 3203 个阅读者
 
发表文章 发表投票 回覆文章
  可列印版   加为IE收藏   收藏主题   上一主题 | 下一主题   
t0306894 手机
个人文章 个人相簿 个人日记 个人地图
特殊贡献奖
头衔:
版主
分享: 转寄此文章 Facebook Plurk Twitter 复制连结到剪贴簿 转换为繁体 转换为简体 载入图片
推文 x0
[JScript][教学] [转贴]解析Java的中文问题
尽管关于Java中文问题的讨论已经相当多了,但由于Java的相关技术标准繁多,面向Java的Web伺服器、应用伺服器以及JDBC资料库驱动等都没有官方的标准,所以Java应用在处理中文时所存在的问题不仅没有消失而且随着所选用的伺服器、驱动程式以及运行环境等因素的不同而变化。本专题中,我们整理了Java中文问题的分析文章及其解决方法,希望能帮您解开Java的中文之谜。


Java的中文问题
关于Java中文问题的几条分析原则
虽然对于Java中文处理问题的讨论已不乏其数,但我们如何从众多现象中找出问题所在,并进行分析和解决呢?本文将主要从如何预测、发现和检查问题的角度给出建议...

JSP/Servlet 中的汉字编码问题
网上就 JSP/Servlet 中 DBCS 字元编码问题有许多优秀的文章和讨论,本文对它们作一些整理,并结合 IBM WebSphere Application Server 3.5(WAS)的解决方法作一些说明,希望它不是多余的...

深入剖析JSP和Servlet对中文的处理
在Java程式中都曾遇到输入的中文不能正确显示的问题,本文就针对这种“中文问题”,给出了一种解决方法...




看过本次专题,希望您会找到对Java的中文问题的处理办法。当然,我们也希望您能就次发表您的看法。如果您也更好的解决办法、实战经验或者对Java的中文问题有更深入的理解,欢迎您参与交流,也欢迎您投稿,续写本次专题。

关于Java中文问题的几条分析原则
作者:周竞涛 王明微 本文选自:IBM DW中国

尽管对于Java中文处理问题的讨论已不乏其数,但由于Java技术涉及内容广(J2EE包含了十几种相关技术),技术供应商繁多,面向Java的Web 伺服器、应用伺服器以及JDBC资料库驱动等都没有官方的标准,所以Java应用在处理中文过程中出了存在固有的问题外也存在随着选用的伺服器,驱动程式的不同而带来的Java中文问题的多变性,增加了问题的复杂度。那么,我们如何在这么纷繁的现象中找到问题的症结呢?
Java中文问题的一般解决办法


事实上,Java的中文问题都是由于Java应用所采用的缺省编码格式与目标或者应用所要读入字元的编码格式不同而造成的(具体参见文献1)。对于如何解决Java的中文问题,通常有四种方法:

1) 选择JDK的中文本地化版本。尽管Java2 JDK的中文本地化版本(http://java.sun.com/products/jdk/1.2/chinesejdk.html)并不是一个官方的版本,Sun公司也没有承诺会对该本地化版本进行升级,但其仍不失为一个Java中文问题的解决方案。

2)选择合适的编译参数。对于Java的国际版本来讲,我们也可以在编译Java应用的时候通过指定确定的编码机制来实现其编译结果对中文的支援。例如,对于需要支援繁体中文和简体中文应用可以通过javac -encoding big5 sourcefile.java 和javac -encoding gb2312 sourcefile.java来编译根源程式。

3) 通过编程的方式实现字元编码的转换代码。通过编程的方式来解决Java的中文问题,已经成为了一种较为普遍的做法。下面就是一种最常见的字元编码转换函数,其将字元的编码格式转换为中文Windows系统的GBK编码形式。


public static String toChinese(String strvalue)
{
try{
if(strvalue==null)
return null;
else
{
strvalue = new String(strvalue.getBytes("ISO8859_1"), "GBK");
return strvalue;
}
}catch(Exception e){
return null;
}
}


4) 定义字元输出集。对于JSP应用,我们可以通过


<%@ page contentType="text/html; charset=GBK" %>

<%@ page contentType="text/html; charset=GB2312" %>


来定义JSP页面的字元输出集。当然,我们也可以通过HTML的标记


<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=gb2312">


来定义字元的输出集。
存在的问题


根据方法实现的方式,我们可以将以上四种方法分为两类,一类是通过利用某些标准或者规则来实现的方法,上面的1)、2)、4)都属于此类;一类是通过针对性的编程来实现的方法,上面所提的方法3)就属于此类。

由于方法1),2),4)是具有规范性的一类方法,所以方法比较简单,解决方案也不具备较大的针对性,较为通用,例如我们可以采用方法2)的编译方式通过编译Java原始档案来实现内码的预置,而无需考虑源码到底有哪些部分出现了Java的中文处理问题,诸如输出乱码等等。

但是,正由于这些方法不具备针对性,解决问题的方法过于统一,所以在某些情况下,它们并不能彻底地解决Java的中文问题。举一个非常常见的例子。在通常情况下,用户的Java应用往往需要与其他Java应用介面进行交互,例如通过某种版本的JDBC访问资料库。由于JDBC的驱动所支援的编码随着提供商乃至版本的不同而不同,所以如果在资料库的输入输出过程中出现中文不能正确处理问题时,我们需要在资料的输入和输出过程做两次正好相反的编码转换,这对于方法1),2),4)来说,往往是无法解决的。当然,对于方法2,我们也可以通过采用一些技巧使来满足上面的情况,一个最有效的办法就是尽量将Java应用的各个部分元件化。例如我们可以通过将资料库的读入和输出代码分解在不同的原始档案上来实现分别编译,从而满足不同的字元编码要求。但是通常的程式设计都不太可能满足这种要求,因为这种程式的划分结果很可能是不合理的。例如,我们将资料库的读出和写入方法封装到一个类中是比较合适的一种设计,但如果将该类的这两个方法分别实现在两个档里则变得非常不合理。因此对于1),2),4)方法来说,虽然实现比较简单,但却具有一些无法克服的缺点。这也是那些实现起来相对复杂的编程方法得以流行的原因。

相对于方法1),2),4)来说,方法3)具有更好的针对性和灵活性。程式可以根据不同的情况做出灵活的处理,在任何需要的地方进行字元的编码转换,但是该方法的特点也对软体的开发人员提出了更高要求--必须能够准确的捕捉到有可能发生中文处理问题的地方,并做出正确的判断和处理。
分析的原则


总的说来,所有解决Java中文处理的方法都不是很复杂。相反的是,由于Java技术特别是J2EE技术涉及的内容繁多,各种Web伺服器、应用伺服器以及JDBC资料库驱动等参差不齐,所以如何正确而及时的发现应用的中文处理问题则变得相对复杂的多。那么我们如何来发现这些问题呢?

通常,Java处理中文时所产生的问题都是由于用户的Java应用所采用的缺省编码格式与目标或者应用所要读入字元的编码格式不同而造成的,而引起这些不同的一个主要原因就是用户的Java应用与其他应用进行了编码格式不匹配的资料交换(包括直接或间接的资料登录、输出)。所以,为了及时发现问题,我们可以由这一点入手,根据以下的原则对应用进行分析:

注意字元变数情况。由于变数的字元编码形式较为隐蔽,多次变数间数值的改变和运算可能会引起字元集的改变;在变数与页面所提交资料的各种操作中,较容易发生不同编码格式字元进行运算的情况。

注意任何形式的字元读入与输出。之所以要提到任何形式,是因为Java应用大多数都是作为网路应用开发的,所以与其他语言的应用相比,Java应用需要面对网路世界各种各样的字元资料交换形式。例如各种表单的资料提交,URL形式的资料读入,经过加密运算的字元资料交换,网页控制项选择结果的输入,控制项内容的的显示(如List控制项)等等。

小心使用第三方的元件和应用。由于第三方元件和应用的实现是非透明的,所以一般情况下,我们很难判断这些元件或驱动的缺省编码格式是什么,也无法对其进行控制。因此,在使用它们所提供的介面函数进行资料交换的时候要特别注意,如果确实出现中文无法正确处理情况,应首先检查我们自己的代码并调整相关代码以适应这些介面,因为这些元件或者应用基本上不会提供调整编码机制的介面。必要时,我们可能需要采用其他可替换的元件或者应用。

注意被请求物件所含有的资料登录与输出。这是非常隐蔽的一类情况,当我们的应用以物件的方式(例如序列化的物件)进行交互时,如果这个物件内部含有字元资料的处理过程,或者含有某些资料的输入、输出,甚至是抛出一段用中文注解的异常,都可能出现中文无法正确显示等问题。由于这些行为往往被封装在物件中,所以我们在编写程式时,很容易忽略这种可能情况。并且这种情况带有一定的不可预见性,例如我们可能不清楚这个物件会在什么时候抛出什么样的异常,所以这时我们就需要做一定的测试工作。

注意资料库的资料访问过程。Java通过JDBC与资料库建立连接。对于JDBC驱动程式来说,由于目前大部分的JDBC驱动程式并不是针对中文系统而设计的(中文资料大都采用ISO-8859-1编码方式),所以一般情况下在资料读写过程中往往都需要字元编码的转化。但是我们仍建议用户在使用这些 JDBC驱动时,仔细阅读它的说明。如果确实无法弄清JDBC字元资料的编码到底是什么,我们的建议是做一些必要的测试。例如下面是一组在简体中文 Win2000平台下,采用Weblogic 6.0所提供的JDBC驱动从MS SQL Server2000中正确读入中文字元的代码(例子中进行了字元运算):


...
Class.forName("weblogic.jdbc.mssqlserver4.Driver").newInstance();
conn = myDriver.connect("jdbc:weblogic:mssqlserver4", props);
conn.setCatalog("labmanager");
Statement st = conn.createStatement();
//execute a query
String testStr;
String testTempStr = new String() ;
testStr = new String(testTempStr.getBytes("ISO-8859-1"));//编码转化
DatabaseMetaData DBMetaData =conn.getMetaData();
ResultSet rs = DBMetaData.getTables(null, null,null,new
String[]{"TABLE"} );
while (rs.next()){
for(int j=1; j<=rs.getMetaData().getColumnCount(); j++){
testStr = testStr +String(rs.getObject(j).toString().getBytes("ISO-8859-1"));
}
}


然而,需要注意的是,不同的JDBC驱动对相同的资料库的支援并不同,而同一类JDBC驱动对不同的资料库的支援也不相同,也就是说我们的字元转化代码在 JDBC驱动改变甚至是版本变化情况下都有可能无法正确工作。例如对于上面的例子,在同样的环境下改用i-net 的Una 2000 Driver Version 2.03 for MS SQL Server时,是无法正确处理中文的。原因很简单,这个JDBC驱动本身支援的就是GBK的编码机制,所以根本就不需要做任何的编码转化。

6)必要的测试。由于Java中文问题的产生随着Web伺服器,流览器,运行环境和开发工具的不同都可能发生变化,所以为了更好的避免问题的发生,我们必须作一些针对性的测试。另外,在我们确实无法通过分析来确定Java的中文处理问题是否可能发生的情况下或者无法知道问题的发生是由于哪个环节(是Web伺服器,流览器还是JDBC资料驱动等等)引起的时候,测试工作则变得非常重要。并且我们可能需要较为全面的测试,例如对Web伺服器,流览器和JDBC资料驱动等都要做测试,这样有利于我们找出那些隐藏在多个环节协调过程中所产生的问题。
结论


事实上,Java中文处理之所以存在问题,其根本原因是由于被操作的中文字元(变数)的编码格式与目标的编码格式不同造成的,所有这些问题其实都是发生在字元的读入、输出过程中的,只要我们把握住这一环节,就可以更好的发现、分析、处理和预防Java的中文问题了。

参考资料

段明辉。Java 编程技术中汉字问题的分析及解决。http://www- 900.ibm.com/developerWorks/cn/java/java_chinese/index.shtml,该文分析了Java编程过程中中文问题产生的原因,并提出了解决方法。

作者简介

周竞涛,西北工业大学CAD/CAM国家专业实验室博士研究生,致力于将哲学、数学结合到技术研究中,主要研究方向:中间件、XML技术、EII,Semantic Web Services。

王明微,陕西西安,西北工业大学CAD/CAM国家专业实验室硕士研究生,研究方向:逆向工程、模式识别。

『引自 IBM DW中国』

JSP/Servlet 中的汉字编码问题
作者:张建芳 本文选自:IBM DeveloperWorks 中国网站

网上就 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 中文字元集

其实解决 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-2000(GBK2K) 在 GBK 的基础上进一步扩展了汉字,增加了藏、蒙等少数民族的字形。GBK2K 从根本上解决了字位元元不够,字形不足的问题。它有几个特点:

●它并没有确定所有的字形,只是规定了编码范围,留待以后扩充。

●编码是变长的,其二位元元组部分与 GBK 相容;四位元元组部分是扩充的字形、字位元元,其编码范围是首位元组 0x81-0xfe、二位元组0x30-0x39、三位元组 0x81-0xfe、四位元组0x30-0x39。

●它的推广是分阶段的,首先要求实现的是能够完全映射到 Unicode 3.0 标准的所有字形。

●它是国家标准,是强制性的。

现在还没有任何一个作业系统或软体实现了 GBK2K 的支援,这是现阶段和将来汉化的工作内容。

3.JSP/Servlet 汉字编码问题及在 WAS 中的解决办法

3.1 常见的 encoding 问题的现象

网上常出现的 JSP/Servlet encoding 问题一般都表现在 browser 或应用程式端,如:

●流览器中看到的 Jsp/Servlet 页面中的汉字怎么都成了 ’?’ ?

●流览器中看到的 Servlet 页面中的汉字怎么都成了乱码?

●JAVA 应用程式介面中的汉字怎么都成了方块?

●Jsp/Servlet 页面无法显示 GBK 汉字。

●Jsp/Servlet 不能接收 form 提交的汉字。

●JSP/Servlet 资料库读写无法获得正确的内容。

隐藏在这些问题后面的是各种错误的字元转换和处理(除第3个外,是因为 Java font 设置错误引起的)。解决类似的字元 encoding 问题,需要了解 Jsp/Servlet 的运行过程,检查可能出现问题的各个点。

3.2 JSP/Servlet web 编程时的 encoding 问题

运行于Java 应用伺服器的 JSP/Servlet 为 Browser 提供 HTML 内容,其过程如下图所示:

其中有字元编码转换的地方有:

a.JSP 编译。Java 应用伺服器将根据 JVM 的 file.encoding 值读取 JSP 原始档案,并转换为内部字元编码进行 JSP 编译,生成 JAVA 原始档案,根据 file.encoding 值写回档系统。如果当前系统语言支援 GBK,那么这时候不会出现 encoding 问题。如果是英文的系统,如 LANG 是 en_US 的 Linux, AIX 或 Solaris,则要将 JVM 的 file.encoding 值置成 GBK 。系统语言如果是 GB2312,则根据需要,确定要不要设置 file.encoding,将 file.encoding 设为 GBK 可以解决潜在的 GBK 字元乱码问题。

b.Java 需要被编译为 .class 才能在 JVM 中执行,这个过程存在与a.同样的 file.encoding 问题。从这里开始 servlet 和 jsp 的运行就类似了,只不过 Servlet 的编译不是自动进行的。

c.Servlet 需要将 HTML 页面内容转换为 browser 可接受的 encoding 内容发送出去。依赖于各 JAVA App Server 的实现方式,有的将查询 Browser 的 accept-charset 和 accept-language 参数或以其他猜的方式确定 encoding 值,有的则不管。因此 constant-encoding 也许是最好的解决方法。对于中文网页,可在 JSP 或 Servlet 中设置 contentType="text/html; charset=GB2312";如果页面中有GBK字元,则设置为contentType="text/html; charset=GBK",由于IE 和 Netscape对GBK的支持程度不一样,作这种设置时需要测试一下。

因为16位元 JAVA char在网路传送时高8位元会被丢弃,也为了确保Servlet页面中的汉字(包括内嵌的和servlet运行过程中得到的)是期望的内码,可以用 PrintWriter out=res.getWriter() 取代 ServletOutputStream out=res.getOutputStream(), PrinterWriter 将根据contentType中指定的charset作转换(ContentType需在此之前指定!);也可以用OutputStreamWriter 封装 ServletOutputStream 类并用write(String)输出中文字元串。

对于 JSP,JAVA Application Server 应当能够确保在这个阶段将嵌入的汉字正确传送出去。

d.这是 URL 字元 encoding 问题。如果通过 get/post 方式从 browser 返回的值中包含汉字资讯, servlet 将无法得到正确的值。SUN的 J2SDK 中,HttpUtils.parseName 在解析参数时根本没有考虑 browser 的语言设置,而是将得到的值按 byte 方式解析。这是网上讨论得最多的 encoding 问题。因为这是设计缺陷,只能以 bin 方式重新解析得到的字串;或者以 hack HttpUtils 类的方式解决。参考文章 2、3 均有介绍,不过最好将其中的中文 encoding GB2312、 CP1381 都改为 GBK,否则遇到 GBK 汉字时,还是会有问题。

Servlet API 2.3 提供一个新的函数 HttpServeletRequest.setCharacterEncoding 用于在调用 request.getParameter(“param_name”) 前指定应用程式希望的 encoding,这将有助于彻底解决这个问题。

WebSphere Application Server 对标准的 Servlet API 2.x 作了扩展,提供较好的多语言支援。上述c,d情况,WAS 都要查询 Browser 的语言设置,在缺省状况下zh、zh-cn 等均被映射为 JAVA encoding CP1381(注意:CP1381 只是等同于 GB2312 的一个 codepage,没有 GBK 支持)。这样做我想是因为无法确认 Browser 运行的作业系统是支援GB2312, 还是 GBK,所以取其小。但是实际的应用系统还是要求页面中出现 GBK 汉字,最着名的是朱总理名字中的“?”(rong2 ,0xe946,\u9555),所以有时还是需要将 Encoding/Charset 指定为 GBK。当然 WAS 中变更缺省的 encoding 没有上面说的那么麻烦,针对 a,b,参考文章 5 ),在 Application Server 的命令行参数中指定 -Dfile.encoding=GBK 即可; 针对 d,在 Application Server 的命令行参数中指定-Ddefault.client.encoding=GBK。如果指定了-Ddefault.client.encoding= GBK,那么c情况下可以不再指定charset。

3.3 资料库读写时的 encoding 问题

JSP/Servlet 编程中经常出现 encoding 问题的另一个地方是读写资料库中的资料。

流行的关联资料库系统都支援资料库 encoding,也就是说在创建资料库时可以指定它自己的字元集设置,资料库的资料以指定的编码形式存储。当应用程式访问资料时,在入口和出口处都会有 encoding 转换。对于中文资料,应当保证资料的完整性。GB2312,GBK,UTF-8 等都是可选的资料库 encoding;如果选择 ISO8859-1(8-bit SBCS),那么应用程式在写资料之前须将 16Bit 的一个汉字或 Unicode 拆分成两个 8-bit 的字元,读数据之后则需将两个位元组合并起来,同时还有判别其中的 SBCS 字元。没有充分利用资料库 encoding 的作用,反而增加了编程的复杂度,ISO8859-1不是推荐的资料库 encoding。JSP/Servlet编程时,可以先用资料库管理系统提供的功能检查其中的中文资料是否正确。

然后应当注意的是读出来的资料的 encoding,JAVA 程式中一般得到的是 Unicode。写数据时则相反。

3.4 定位问题时常用的技巧

定位中文encoding问题通常采用最笨的也是最有效的办法——在你认为有嫌疑的程式处理后列印字串的内码。通过列印字串的内码,你可以发现什么时候中文字元被转换成Unicode,什么时候Unicode被转回中文内码,什么时候一个中文字成了两个 Unicode 字元,什么时候中文字串被转成了一串问号,什么时候中文字串的高位被截掉了……

取用合适的样本字串也有助于区分问题的类型。如:”aa啊aa?aa” 等中英相间、GB、GBK特征字元均有的字串。一般来说,英文字元无论怎么转换或处理,都不会失真(如果遇到了,可以尝试着增加连续的英文字母长度)。

其实 JSP/Servlet 的中文encoding 并没有想像的那么复杂,虽然定位和解决问题没有定规,各种运行环境也各不尽然,但后面的原理是一样的。了解字元集的知识是解决字元问题的基础。不过,随着中文字元集的变化,不仅仅是 java 编程,中文资讯处理中的问题还是会存在一段时间的。



介绍大家一个透过facebook来玩的网页游戏 : 海盗王
献花 x0 回到顶端 [楼 主] From:台湾中华电信 | Posted:2005-02-14 14:39 |

首页  发表文章 发表投票 回覆文章
Powered by PHPWind v1.3.6
Copyright © 2003-04 PHPWind
Processed in 0.011427 second(s),query:15 Gzip disabled
本站由 瀛睿律师事务所 担任常年法律顾问 | 免责声明 | 本网站已依台湾网站内容分级规定处理 | 连络我们 | 访客留言