全部博文(668)
分类:
2008-08-18 10:25:44
本文用例基于JDK 1.4.2和J2EE 1.4,并基于产品WebSphere Application Server(下面简称WAS) 6.0 和Rational Application Developer(下面简称RAD) 6.0开发。用于演示 WAS 6.0的多语言支持特性。
在目前的计算机应用中,英文字符最常用的编码方法是 ASCII,一般以一个字节来表示。但一个字节最多只能区分256个字符。而其他的语言,以汉字为例,汉字成千上万,仅以一个字节无法表示。所以现在都以双字节表示汉字。我们在国内经常碰到的编码方式有 GB2312、GBK、UNICODE、以及国家质量技术监督局在2000年发布并作为一项国家标准正式强制执行的GB18030等。
|
虽然 Java 的基本类已考虑到对非英文的多语言支持(默认 UNICODE 编码),但是如果操作系统的默认编码不是 UNICODE ,要从 Java 源代码到得到正确的结果,就要经过一个较为复杂的过程。该过程为: "Java 源码 -> Java 字节码 -> Java虚拟机 -> 操作系统 -> 显示设备"。在该过程中,我们在每一步都必须正确地处理双字节/汉字的编码,才能够正确显示最终的双字节结果。
1) Java 源码 到 Java 字节码的双字处理
Javac(标准Java 编译器)使用的字符集为操作系统默认的字符集,比如在中文 Windows 操作系统上是 GBK/GB18030 ,而在英文UNIX 操作系统上就是ISO-8859-1。因此开发人员会发现在 英文UNIX 操作系统上编译的类,其中双字节(中文)字符都成了乱码或者问号。解决方案是在编译时添加 encoding 参数,就可以做到与平台无关。语法如下:
javac -encoding GBK |
2) Java 字节码到Java虚拟机再到操作系统的双字处理
JRE (Java 运行环境) 分为国际版和英文版,其中只有国际版才支持非英文字符。JDK(Java 开发工具包) 都肯定支持非英文字符,但并非所有的服务器(或者开发平台)都会安装JDK 。很多操作系统及应用软件都会内嵌 JRE 的国际版本,例如WebSphere Application Server多语言版,为产品及其应用支持非英文字符提供了完全的支持。
3) 操作系统到显示设备的双字节处理
支持非英文字符的最基本条件是操作系统必须支持并能够显示它。如果是纯英文操作系统,如果不搭配特殊的应用软件,肯定不能够显示双字节字符(例如中文)。因此在实际环境中,特别是UNIX操作系统,要特别留意是否安装了多语言支持包。
|
我们接下来探讨在 Java 编程过程中,对非英文字符进行正确的编码转换。假设操作系统已经具备中文的字符集支持。下面以中文为例,示例如何正确处理和显示双字节字符。
1) JSP如何正确显示中文字符
注意下列代码中加重红字显示的部分:
<%@ page language="java" contentType="text/html; charset=GB18030" pageEncoding="GB18030"%> |
该页正确显示如下图:
如果去掉红色字体部分,JSP页面显示将会成乱码,如下图所示:
在这种情况下,如果点击浏览器菜单:查看 ' 编码,会发现页面目前的缺省编码为:"西欧(ISO)" 这时如果选择编码:"简体中文(GB18030)"(如下图所示),页面也能够正确显示汉字,但这种方式显然不能被最终客户端用户所接受,因此编成人员在开发时要尽力避免。
2) 与Servlet交互时如何正确显示中文字符
在页面与Servlet交互时是最容易产生中文字符问题的。因为在HTTP Request 和 HTTP Response在编码时缺省会基于ISO-8859-1,导致传入和传出Servlet的中文参数都编成了乱码或者问号。以上述的JSP作为客户端页面,我们来提交一个既有英文字符和中文字符的参数,提交方式采用HTTP POST方法。如下图所示:
下列代码为接收请求的Servlet的doPost方法:
protected void doPost(HttpServletRequest arg0, HttpServletResponse arg1) throws ServletException, IOException { String name = arg0.getParameter("name"); String a = "您好:"; System.out.println(a + name); PrintWriter out = arg1.getWriter(); out.println(a + name); out.close(); } |
由于代码中对于请求和响应的编码未做任何处理,因此返回给客户端的结果出现了"?",不能正确显示中文字符。如下图:
解决的方法有两种,一种是在WAS/RAD中设置参数进行自动编码,无需改动源码;另一种是通过改动源码编程实现。前者将在本文的第5节进行讨论。后者在J2EE 1.4中很方便实现,即对HttpServletRequest和HttpServletResponse都调用setCharacterEncoding方法。见下列代码中红色加重的字体。在J2EE 1.3中,还仅仅是HttpServletRequest有setCharacterEncoding方法,HttpServletResponse并未提供。
protected void doPost(HttpServletRequest arg0, HttpServletResponse arg1) throws ServletException, IOException { arg0.setCharacterEncoding("GB18030"); String name = arg0.getParameter("name"); String a = "您好:"; System.out.println(a + name); arg1.setCharacterEncoding("GB18030"); PrintWriter out = arg1.getWriter(); out.println(a + name); out.close(); } |
通过在Servlet中对HttpServletRequest和HttpServletResponse都进行了汉字编码,就可以保证传入和传出Servlet的汉字字符都能正确显示,如图:
JSP/Servlet 编程中经常出现编码问题,除了上述讨论的方面,另方面是读写数据库中的数据。
目前业界常用的关系数据库系统都支持数据库多语言编码,也就是说在创建数据库时可以指定它自己的字符集设置,数据库的数据就将以指定的编码形式存储。当应用程序访问数据时,在入口和出口处都会有 encoding 转换。对于中文数据,数据库字符编码的设置应当保证数据的完整性。GB2312、GBK、UTF-8、ISO-8859-1等都是可选的数据库编码。但是如果编码设置成了ISO-8859-1,则应用程序在写数据之前须将 16Bit 的一个汉字或 Unicode 拆分成两个 8-bit 的字符,读数据之后则需将两个字节合并起来,同时还要判别其中的 SBCS 字符。这种情况没有充分利用数据库编码的作用,反而增加了编程的复杂度。因此ISO-8859-1不是推荐的数据库编码。针对上述状况,下列代码示例了如果Java应用是基于GB18030编码,而数据库编码是ISO-8859-1的情况,如何通过Java代码转换字符而不会产生乱码:
1) 从数据库中读入含中文的字符串:
… … PreparedStatement pst = … … ; ResultSet rst = … … ; … … String result = rst.getString(1); //从数据库得到某个字段的字符串结果 result = new String(result.getBytes("GB18030"));//对result的字符集重新进行编码,将其强制转为本地GB18030字符集 … … |
2) 将中文字符串写入数据库:
… … PreparedStatement pst = … … ; … … sql = new String(sql.getBytes(),"GB18030"); //对sql的本地编码按GB18030进行解码,还原为数据库能接受的代码 pst.execute(sql); … … |
|
1) WAS提供对Web部署描述符的扩展功能:在ibm-web-ext.xmi文件中设置autoRequestEncoding和autoResponseEncoding 在 Web 模块上启用 autoRequestEncoding 设置会更改WAS的缺省行为:如果Http Request header上不存在字符集,则WAS检查Http Request的 Accept-Language 头,并使用头中找到的第一种语言进行编码。如果content type头上没有字符集,而且没有 Accept language 头,则WAS使用服务器上设置的字符编码,通过系统属性 default.client.encoding。当上述属性均未设置,则WAS使用 ISO-8859-1。
autoRequestEncoding和autoResponseEncoding参数可以在WSAD/RAD或者Application Server Toolkit (AST)中设置。开发人员可以打开WAR项目的部署描述符文件,如下图所示:
如果在该处进行了设置,就不需要在Servlet中采用编程处理Http Request和Http Response的中文编码问题。
2) 在管理控制台中启用多语言编码支持。
要在管理控制台中使用多语言编码支持,您必须配置应用程序服务器,例如启用 GB18030 编码。在"Java 虚拟机"页面上(应用程序服务器 > server1 > 进程定义 > Java 虚拟机),为通用 JVM 自变量指定 -Dclient.encoding.override=GB18030 (或者-Ddefault.client.encoding=GB18030) ,如下图所示:
李珂嘉,IBM 软件部 WebSphere 专家。 |