技术开发 频道

专家讲述J2EE中的多字节字符的处理


多字节字符问题的解决方案

编写能运行于任何服务器、在任何浏览器中都能正常显示的J2EE应用是个挑战,下面是一些针对J2EE应用多字节字符问题的解决方案:
 
通用原则:从不假定客户端(浏览器)和服务器端有任何默认设置。
 
  在编辑阶段,不要假定IDE的默认编码设置是你想要的,要手工设置它们。如果IDE不支持特定语言,就在Java代码中用\uXXXX转义序列,在HTML页面中用&#XXXX转义序列,或用随JDK分发的native2ascii工具将本地文字字符串转换成Unicode转义序列,这样就能避免绝大部分问题。在编码阶段,从不假定服务器默认的编码处理设置是正确的,而用下面的方法显式指定:
 
· 请求:
 
setCharacterEncoding()
 
· 响应:
 
setContentType(),
setLocale(),
<%@ page contentType="text/html; charset=encoding" %>
 
在为多种语言开发应用时,采用UTF-8编码方式或将所有语言的字符都用\uXXXX转义序列表示。
 
· 在编译Java类时,确保当前语言环境变量与编码方式正确匹配。
· 在配置阶段,尽可能地使用标准设置。例如在Servlet 2.4规范中有一个配置每个应用的字符编码方式的标准:
 
<locale-encoding-mapping-list>
    <locale-encoding-mapping>
        <locale>ja</locale>
        <encoding>Shift_JIS</encoding>
    </locale-encoding-mapping>
</locale-encoding-mapping-list>
 
当与外部系统通信时,尽可能地找出这些系统的编码方式,如果编码不同就进行转码。可以用UnicodeFormatter.java作为调试器打印所有的字节:
 
清单4
 
UnicodeFormatter.java
import java.io.*;
public class UnicodeFormatter 
{  
static public
String byteToHex(byte b)
{     
// Returns hex String
representation of byte b     
char hexDigit[] =
{        
'0', '1', '2', '3', '4', '5', '6', '7',        
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'     
};     
char[] array =
{
hexDigit[(b >> 4) & 0x0f],
hexDigit[b & 0x0f] };     
return new String(array);  
}  
static public String charToHex(char c)
{     
// Returns hex String
representation of char c     
byte hi = (byte) (c >>> 8);     
byte lo = (byte) (c & 0xff);     
return byteToHex(hi) + byteToHex(lo);  
}
}
 
总在HTML页面中对编码方式做显式声明,例如content="text/html;charset=gb2312">,不要假定浏览器的默认设置是正确的。
 
· 不要在链接里加入多字节字符,例如查询字符串里不要用用户名,改用用户ID。
· 如果必须在链接里加入多字节字符,那就要对URL进行手工编码,可以在服务器端处理(用Java),也可以在客户端处理(用JavaScript或VBscript)。
 
难题之一:UTF-16
 
  有了前面的知识,现在我们来分析一个真正的难题,这是我负责的一个ISV(独立软件开发商)在项目中遇到的:J2EE中的UTF-16。现行的中文字符标准(GB18030)定义并支持27,484个中文字符。尽管这个数字看起来很大,实际上对中国人来说还不够。目前中文拥有60,000多个字符,每年还在快速增长,这个状况对中国政府在信息化方面的工作会产生严重影响。例如我姐姐的名在标准字符集中就没有,因此银行或邮电系统的计算机就打不出她的名。
 
  我的ISV希望能建立一套完整的、能让所有人满意的中文字符系统。它定义了自己的字码表,有两个现成的字符字码表可供选择:采用GB18030标准,可扩充到1600万个字符;或采用Unicode 3.1标准,可支持1,112,064个字符。GB18030标准定义了编码规则,也叫做GB18030,它用起来很简便,目前已被JDK支持。然而如果采用Unicode 3.1标准,我们就可以从三种编码方式中进行选择:UTF-8、UTF-16或UTF-32。
 
  我的ISV希望用UTF-16编码来处理它对中文字符的Unicode扩展。UTF-16编码最主要的特点就是所有的ASCII字符都被编码为16位的单元,这会在各个阶段引发问题。在几个服务器上做过测试后,ISV发现J2EE应用根本不支持UTF-16编码。果真如此吗?我们一起来分析开发的各个阶段以找出问题所在。
 
编辑阶段
 
  如果在Java、JSP或HTML源文件中有多字节文字字符串,就需要用支持它们的IDE。我用的是NetBeans,只要将文本编码属性设置为UTF-16就能轻松支持UTF-16编码。
 
编译阶段
 
  由于在Java或JSP源文件中带有用UTF-16编码的字符,因此需要编译器的支持。可以用javac -encoding UTF-16命令来编译Java源文件,而在NetBeans里则可通过GUI方便地设置编译器的属性。通过一些简单的代码测试可以发现:如果servlet文件中的字符是用UTF-16编码的,那么运行时就不会有问题。

  运行时动态编译的JSP文件值得我们注意。幸运的是,大多数服务器可以对JSP页面的编码方式进行配置;而不幸的是,在Tomcat和Sun ONE应用服务器上做测试时,我发现用来将JSP文件转换为servlet Java源文件的Jasper不能识别被UTF-16编码过的JSP标签(比如),所有这些标签都被当作文字字符串处理了!我认为问题的根源可能在于Jasper(大多数应用服务器都用它做JSP编译器),因为它以字节为单位来识别JSP的特定记号和标签。
0
相关文章