一般都表现在 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 即可; 针对