引言
管对于Java中文处理问题的讨论已不乏其数Q但׃Java技术涉?qing)内容广QJ2EE包含?jin)十几种相关技术)(j)Q技术供应商J多Q面向Java的Web服务器、应用服务器以及(qing)JDBC数据库驱动等都没有官方的标准Q所以Java应用在处理中文过E中Z(jin)存在固有的问题外也存在随着选用的服务器Q驱动程序的不同而带来的Java中文问题的多变性,增加?jin)问题的复杂度。那么,我们如何在这么纷J的现象中找到问题的症结呢?
Java中文问题的一般解军_?/STRONG>
事实上,Java的中文问题都是由于Java应用所采用的缺省编码格式与目标或者应用所要读入字W的~码格式不同而造成的(具体参见文献1Q。对于如何解决Java的中文问题,通常有四U方法:(x)
1Q选择JDK的中文本地化版本。尽Java2 JDK的中文本地化版本Q?A target=_blank>http://java.sun.com/products/jdk/1.2/chinesejdk.htmlQƈ不是一个官方的版本QSun公司也没有承Z(x)对该本地化版本进行升U,但其仍不׃ؓ(f)一个Java中文问题的解x(chng)案?/P>
2Q选择合适的~译参数。对于Java的国际版本来Ԍ我们也可以在~译Java应用的时候通过指定定的编码机制来实现其编译结果对中文的支持。例如,对于需要支持繁体中文和体中文应用可以通过javac -encoding big5 sourcefile.java 和javac -encoding gb2312 sourcefile.java来编译源E序?/P>
3Q通过~程的方式实现字W编码的转换代码。通过~程的方式来解决Java的中文问题,已经成ؓ(f)?jin)一U较为普遍的做法。下面就是一U最常见的字W编码{换函敎ͼ其将字符的编码格式{换ؓ(f)中文Windowspȝ的GBK~码形式?/P>
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;
}
}
4Q定义字W输出集。对于JSP应用Q我们可以通过<%@ page contentType="text/html; charset=GBK" %>?lt;%@ page contentType="text/html; charset=GB2312" %>来定义JSP面的字W输出集。当?dng)我们也可以通过HTML的标?lt;META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=gb2312">来定义字W的输出集?/P>
存在的问?/STRONG>
Ҏ(gu)Ҏ(gu)实现的方式,我们可以以上四U方法分Zc,一cL通过利用某些标准或者规则来实现的方法,上面?)?)?Q都属于此类Q一cL通过针对性的~程来实现的Ҏ(gu)Q上面所提的Ҏ(gu)3Q就属于此类?/P>
׃Ҏ(gu)1)Q?)Q?Q是h规范性的一cL法,所以方法比较简单,解决Ҏ(gu)也不具备较大的针Ҏ(gu),较ؓ(f)通用Q例如我们可以采用方?Q的~译方式通过~译Java源文件来实现内码的预|,而无需考虑源码到底有哪些部分出C(jin)Java的中文处理问题,诸如输出q{等?/P>
但是Q正׃q些Ҏ(gu)不具备针Ҏ(gu),解决问题的方法过于统一Q所以在某些情况下,它们q不能彻底地解决Java的中文问题。D一个非常常见的例子。在通常情况下,用户的Java应用往往需要与其它Java应用接口q行交互Q例如通过某种版本的JDBC讉K数据库。由于JDBC的驱动所支持的编码随着提供商乃至版本的不同而不同,所以如果在数据库的输入输出q程中出C文不能正处理问题时Q我们需要在数据的输入和输出q程做两ơ正好相反的~码转换Q这对于Ҏ(gu)1Q,2Q,4Q来_(d)往往是无法解决的。当?dng)对于?gu)2Q我们也可以通过采用一些技巧来满上面的情况Q一个最有效的办法就是尽量将Java应用的各个部分组件化。例如我们可以通过数据库的读入和输出代码分解在不同的源文件上来实现分别编译,从而满不同的字符~码要求。但是通常的程序设计都不太可能满q种要求Q因U程序的划分l果很可能是不合理的。例如,我们数据库的读出和写入Ҏ(gu)装C个类中是比较合适的一U设计,但如果将该类的这两个Ҏ(gu)分别实现在两个文仉则变得非怸合理。因此对?Q,2Q,4Q方法来_(d)虽然实现比较单,但却h一些无法克服的~点。这也是那些实现h相对复杂的编E方法得以流行的原因?/P>
相对于方?Q,2Q,4Q来_(d)Ҏ(gu)3Q具有更好的针对性和灉|性。程序可以根据不同的情况做出灉|的处理,在Q何需要的地方q行字符的编码{换,但是该方法的特点也对软g的开发h员提Z(jin)更高要求--必须能够准确的捕捉到有可能发生中文处理问题的地方Qƈ做出正确的判断和处理?/P>
分析的原?/STRONG>
ȝ说来Q所有解决Java中文处理的方法都不是很复杂。相反的是,׃Java技术特别是J2EE技术涉?qing)的内容J多Q各UWeb服务器、应用服务器以及(qing)JDBC数据库驱动等参差不齐Q所以如何正而及(qing)时的发现应用的中文处理问题则变得相对复杂的多。那么我们如何来发现q些问题呢?
通常QJava处理中文时所产生的问题都是由于用L(fng)Java应用所采用的缺省编码格式与目标或者应用所要读入字W的~码格式不同而造成的,而引赯些不同的一个主要原因就是用L(fng)Java应用与其它应用进行了(jin)~码格式不匹配的数据交换Q包括直接或间接的数据输入、输出)(j)。所以,Z(jin)?qing)时发现问题Q我们可以由q一点入手,Ҏ(gu)以下的原则对应用q行分析Q?/P>
1. 注意字符变量情况。由于变量的字符~码形式较ؓ(f)隐蔽Q多ơ变量间数值的改变和运可能会(x)引v字符集的改变Q在变量与页面所提交数据的各U操作中Q较Ҏ(gu)发生不同~码格式字符q行q算的情c(din)?
2. 注意M形式的字W读入与输出。之所以要提到M形式Q是因ؓ(f)Java应用大多数都是作为网l应用开发的Q所以与其它语言的应用相比,Java应用需要面对网l世界各U各L(fng)字符数据交换形式。例如各U表单的数据提交QURL形式的数据读入,l过加密q算的字W数据交换,|页控g选择l果的输入,控g内容的的昄Q如List控gQ等{?
3. 心(j)使用W三方的lg和应用。由于第三方lg和应用的实现是非透明的,所以一般情况下Q我们很隑ֈ断这些组件或驱动的缺省编码格式是什么,也无法对其进行控制。因此,在用它们所提供的接口函数进行数据交换的时候要特别注意Q如果确实出C文无法正处理情况,应首先检查我们自q代码q调整相关代码以适应q些接口Q因些组件或者应用基本上不会(x)提供调整~码机制的接口。必要时Q我们可能需要采用其它可替换的组件或者应用?
4. 注意被请求对象所含有的数据输入与输出。这是非帔R蔽的一cL况,当我们的应用以对象的方式Q例如序列化的对象)(j)q行交互Ӟ如果q个对象内部含有字符数据的处理过E,或者含有某些数据的输入、输出,甚至是抛ZD는中文注解的异常,都可能出C文无法正显C等问题。由于这些行为往往被封装在对象中,所以我们在~写E序Ӟ很容易忽略这U可能情c(din)ƈ且这U情况带有一定的不可预见性,例如我们可能不清楚这个对象会(x)在什么时候抛Z么样的异常,所以这时我们就需要做一定的试工作?
5. 注意数据库的数据讉Kq程。Java通过JDBC与数据库建立q接。对于JDBC驱动E序来说Q由于目前大部分的JDBC驱动E序q不是针对中文系l而设计的(中文数据大都采用ISO-8859-1~码方式)Q所以一般情况下在数据读写过E中往往都需要字W编码的转化。但是我们仍用户在用这些JDBC驱动Ӟ仔细阅读它的说明。如果确实无法弄清JDBC字符数据的编码到底是什么,我们的徏议是做一些必要的试。例如下面是一l在体中文Win2000q_下,采用Weblogic 6.0所提供的JDBC驱动从MS SQL Server2000中正读入中文字W的代码Q例子中q行?jin)字W运)(j)Q?
...
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驱动对相同的数据库的支持q不同,而同一cJDBC驱动对不同的数据库的支持也不相同Q也是说我们的字符转化代码在JDBC驱动改变甚至是版本变化情况下都有可能无法正确工作。例如对于上面的例子Q在同样的环境下改用i-net 的Una 2000 Driver Version 2.03 for MS SQL ServerӞ是无法正处理中文的。原因很单,q个JDBC驱动本n支持的就是GBK的编码机Ӟ所以根本就不需要做M的编码{化?
6. 必要的测试。由于Java中文问题的生随着Web服务器,览器,q行环境和开发工L(fng)不同都可能发生变化,所以ؓ(f)?jin)更好的避免问题的发生,我们必须作一些针Ҏ(gu)的试。另外,在我们确实无法通过分析来确定Java的中文处理问题是否可能发生的情况下或者无法知道问题的发生是由于哪个环节(是Web服务器,览器还是JDBC数据驱动{等Q引L(fng)时候,试工作则变得非帔R要。ƈ且我们可能需要较为全面的试Q例如对Web服务器,览器和JDBC数据驱动{都要做试Q这h利于我们扑և那些隐藏在多个环节协调过E中所产生的问题?/P>
l论
事实上,Java中文处理之所以存在问题,其根本原因是׃被操作的中文字符Q变量)(j)的编码格式与目标的编码格式不同造成的,所有这些问题其实都是发生在字符的读入、输?gu)E中的,只要我们把握住这一环节Q就可以更好的发现、分析、处理和预防Java的中文问题(sh)(jin)?/P>