字符集转换解决方案
问题的提出:
关于字符串的字符集转换,目前应用系统中主要在对数据库操作的时候。
1. 向数据提交操作请求
会对每一个String类型的变量做一次GBKToUnicode的操作,实际上此操作最终会触发unicodeToGBK操作,而在unicodeToGBK中会调用isGBKString方法用来判定此字符串是否是GBK编码,采用的方式是循环比较字符串数组中的每一个char对象值。
2. 从数据库返回数据信息
会对每一个String类型做一次unicodeToGBK的操作,同样会调用isGBKString方法。
由于上述操作导致应用服务器的性能产生很大的负载,因此需要及时改进。
已经解决的问题:
对于从数据库返回数据信息而做的unicodeToGBK操作,我们主要是在schema的getString时调用,及exesql中的getdatavalue中调用。Schema中的调用我们通过一个静态变量SysConst.CHANGECHARSET来控制是否执行(目前默认情况下是不执行),而exesql中的调用是强制执行的。
经过民生的近期测试,我们发现可以去掉exesql中的unicodeToGBK操作,而保证数据在返回到前台的时候没有乱码。
尚未解决的问题:
对于向数据提交操作请求而做的GBKToUnicode的操作,实际上此操作也依赖于SysConst.CHANGECHARSET变量
● 如果此变量为true
则执行new Bytes("GBK"), "ISO8859_1");
● 如果此变量为false
则执行new Bytes("ISO8859_1"), "GBK");
现在系统中SysConst.CHANGECHARSET默认设置为false,而不论此变量为何值,系统都会执行isGBKString这个操作。weblogic管理页面
问题:如果我们去除这一操作,会导致提交到后台数据库中的中文全部变成??的形式,在查询的时候,也无法使用中文作为查询条件。
以前的存储方式:
以前的应用是通过unicodeToGBK进行转换,提交给数据库的时候,字符集的编码采用的是GBK。之所以当初要在后台统一字符集处理,是因为无法有效保证前台提交过来的信息编码格式。
问题分析:
产生上述情况的原因是Jsp/Servlet 不能接收form提交的汉字,也不能解析通过get方式传递的汉字。
运行于Java 应用服务器的 JSP/Servlet 为 Browser 提供 HTML 内容,其过程如下图所示:
其中有字符编码转换的地方有:
● JSP 编译。Java 应用服务器将根据 JVM 的 ding 值读取 JSP 源文件,编译生成 JAVA 源文件,再根据 ding 值写回文件系统。如果当前系统语言支持 GBK,那么这时候不会出现 encoding 问题。如果是英文的系统,如 LANG 是 en_US 的 Linux, AIX 或 Solaris,则要将 JVM 的 ding 值置成 GBK 。系统语言如果是 GB2312,则根据需要,确定要不要设置 ding,将 ding 设为 GBK 可以解决潜在的 GBK 字符乱码问题
● Java 需要被编译为 .class 才能在 JVM 中执行,这个过程存在与a.同样的 ding
问题。从这里开始 servlet 和 jsp 的运行就类似了,只不过 Servlet 的编译不是自动进行的。对于JSP程序, 对产生的JAVA 中间文件的编译是自动进行的(在程序中直接调用ls.javac.Main类). 因此如果在这一步出现问题的话, 也要检查encoding和OS的语言环境,或者将内嵌在JSP JAVA Code 中的静态汉字转为 Unicode, 要么静态文本输出不要放在 JAVA code 中。对于Servlet, javac 编译时手工指定-encoding 参数就可以了。
● Servlet 需要将 HTML 页面内容转换为 browser 可接受的 encoding 内容发送出去。依赖于各 JAVA App Server 的实现方式,有的将查询 Browser 的 accept-charset 和 accept-language 参数或以其它猜的方式确定 encoding 值,有的则不管。因此采用固定encoding 也许是最好的解决方法。对于中文网页,可在 JSP 或 Servlet 中设置 contentType="text/html; charset=GB2312";如果页面中有GBK字符,则设置为contentType="text/html; charset=GBK",由于IE 和 Netscape对GBK的支持程度不一样,作这种设置时需要测试一下。因为16位 JAVA char在网络传送时高8位会被丢弃,也为了确保Servlet页面中的汉字(包括内嵌的和servlet运行过程中得到的)是期望的内码,可以用 PrintWriter Writer() 取代 ServletOutputStream OutputStream(). PrinterWriter 将根据contentType中指定的charset作转换 (ContentType需在此之前指定!);
也可以用OutputStreamWriter封装 ServletOutputStream 类并用write(String)输出汉字字符串。对于 JSP,JAVA Application Server 应当能够确保在这个阶段将嵌入的汉字正确传送出去。
● 这是解释 URL 字符 encoding 问题。如果通过 get/post 方式从 browser 返回的参数值中包含汉字信息, servlet 将无法得到正确的值。SUN的 J2SDK 中,HttpUtils.parseName 在解析参数时根本没有考虑 browser 的语言设置,而是将得到的值按 byte 方式解析。这是网上讨论得最多的 encoding 问题。因为这是设计缺陷,只能以 bin 方式重新解析得到的字符串;或者以 hack HttpUtils 类的方式解决。参考文章 2 均有介绍,不过最好将其中的中文 encoding GB2312、 CP1381 都改为 GBK,否则遇到 GBK 汉字时,还是会有问题。 Servlet API 2.3 提供一个新的函数 HttpServeletRequest.setCharacterEncoding 用于在调用 Parameter(“param_name”) 前指定应用程序希望的 encoding,这将有助于彻底解决这个问题。
提出的解决方法:
通过在中间件上设置、或者在servelt上设置,避免应用程序执行字符集转换操作。
方法一:
数据提交的方式有两种,一种是get的方式,一种是post的方式。经测试,Java中接收到前台传入的信息的时候,中文字符就已经转换为??,原因未明。可能是Tomcat在接收到请求后,并没有能够根据request中的信息提前正确的编码方式。
解决:可以添加一个设置字符集的Filter,来保证Servlet能够正确按照指定的字符集解析。同时配置l文件如下:
<filter>
<filter-name>Set Character Encoding</filter-name>
<display-name>Set Character Encoding</display-name>
<filter-class>filters.SetCharacterEncodingFilter</filter-class> --实现类
<init-param>
<param-name>encoding</param-name>
<param-value>GBK</param-value> --字符集设置
</init-param>
</filter>
<filter-mapping>
<filter-name>Set Character Encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
这是一种比较常用的规范提交数据字符集的方式。
试验结果:
在tomcat、websphere、weblogic上分别测试应用的情况。
● Tomcat下
使用filter后,采用form的提交能够被有效的转换为gbk模式到数据库中,并且在查询返回后,没有出现乱码。但是在用get的方式传递变量的时候出现乱码,使得无法进行中文信息查询,解决的方法是在tomcat的l文件中的<Connector >对象中添加URIEncoding="GBK"属性。
● Websphere下
使用filter后,post、get两种方式都能够正常的解析gbk编码
● Weblogic下
使用filter后,post、get两种方式都能够正常的解析gbk编码。不过在应用中出现比较多的乱码,解决的方案是在应用的web-inf中添加l文件,其中设置如下信息
<jsp-descriptor>
<jsp-param>
<param-name>encoding</param-name>
<param-value>GBK</param-value> --好像不同的平台设置不太一样
</jsp-param>
<jsp-param>
<param-name>compilerSupportsEncoding</param-name>
<param-value>true</param-value>
</jsp-param>
</jsp-descriptor>
注:测试是基于oracle数据库,字符集ZHS16GBK。同时在tomcat上也进行了db2的测试,字符集是UTF-8。
测试环境:
● Window中文平台:tomcat5.0,websphere5.1,weblogic8.1
● Window英文平台:websphere5.1,weblogic8.1
● Unix平台:weblogic
● 数据库:oracle数据库,字符集ZHS16GBK
测试结果:以上平台下都没有问题,能够保证数据已GBK的模式存入数据库中,并查询出来。
测试疑问:websphere、weblogic下,使用get方式来提交信息的时候,会根据客户端的字符集设置产生问题。(如果客户端的地域是中国,则查询是能够正常的提交GBK编码给后台,如果前台的地域不是中国,则提交给后台的编码为地域所设的国家编码模式)
方法二:
通过配置xml文件来实现filter的方法。
针对不同的中间件产品,各自都有一些比较特殊的xml配置信息,因此如果能够通过xml文件的配置来达到filter的效果,那么就能够更好的提高应用平台的性能。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论