Java数据库字符国际化

Java数据库字符国际化,第1张

数据库字符国际化是大家提问最多的问题 例如MySQL数据库大家可能在JDBC URL添加useUnicode=true&CharacterEncoding=GBK作为中文支持的基本条件 但这有时破坏了数据的完整性 如果某些人粗心大意 就会导致数据编码错误 产生乱码 因此 我们需要一些手段在程序内部进行编码处理 人们一般通过在应用上使用 String(bytes:byte[] enc:String)/String getBytes(enc:String)进行字符串编解码 这样做虽然易懂 但是如果遇到大字段表格 手动编码时费时费力 我的方法 通过研究JDK类库 可以感觉到多层处理机制在数据处理上的优越性 我们完全有可能在数据库上建立一个中间层用于字符的国际化处理 我就是这么做的 仔细研究一下JDBC *** 作数据库出现字符编码问题的根源 很容易发现多数情况是ResultSet的几个String方法在作怪 因此我们就完全可以编写一个ResultSet中间层进行国际化处理 源码如下 public class I nResultSet implements ResultSet{ private String encodingprivate ResultSet rspublic I nResultSet(ResultSet rs String encoding) throws java io UnsupportedEncodingException{ //检查该编码名称是否被系统支持 getBytes(encoding)this rs = rsthis encoding = encoding} … … //以下几个方法是进行String字符串的重编码 public String getString(int index) throws SQLException{ String data = nulltry{ data = new String(rs getBytes(index) encoding)}catch(java io UnsupportedEncodingException uee){} } public String getString(Stirng field) throws SQLException{ String data = nulltry{ data = new String(rs getBytes(field) encoding)}catch(java io UnsupportedEncodingException uee){} } public void updateString(int index String value) throws SQLException{ try{ rs updateBytes(index value getBytes(encoding))}catch(java io UnsupportedEncodingException uee){} } public void updateString(String field String value) throws SQLException{ try{ rs updateBytes(field value getBytes(encoding))}catch(java io UnsupportedEncodingException uee){} } … …}可以看出 所有的String *** 作都使用特定编码的字节数组进行存取 这样通过定义encoding的值实现数据库存取数据编码的一致性 且encoding完全可以通过在配置信息中动态定义 同时 上面的程序又可以解决一些固有的字符串处理问题 例如控制符如\r\n导入到数据库中很有可能被解析为\\r\\n使其不能换行 通过字节数组 *** 作 就可以解决这个问题 这样像文章固有格式就可以完整地保留下来而不需要进行额外转换 *** 作 结论 通过多层处理机制使用中间层对数据库数据进行层层处理可使处理环节之间形成松耦合关系 从而可以进行有效的控制 下面给一个使用动态代理进行字符控制的代码(原创):package yipsilon crocodile databaseimport java sql ResultSetimport java lang reflect InvocationHandlerimport java lang reflect Methodimport java io UnsupportedEncodingException/** * 作者 yipsilon * 如要转载 请通知作者 */public class I nResultSetHandler implements InvocationHandler{ private ResultSet rsprivate String encodingpublic I nResultSetHandler(ResultSet rs String encoding) throws UnsupportedEncodingException{ this rs = rsgetBytes(encoding)this encoding = encoding} public Object invoke(Object proxy Method method Object[] args) throws Throwable{ String methodName = method getName()if(methodName equals( getString )){ Object obj = args[ ]if(obj instanceof Integer){ return decodeString(rs getBytes(((Integer)obj) intValue()) encoding)}else{ return decodeString(rs getBytes((String)obj) encoding)} }else if(methodName equals( updateString )){ Object obj = args[ ]if(obj instanceof Integer){ rs updateBytes(((Integer)obj) intValue() encodeString((String)args[ ] encoding))}else{ rs updateBytes((String)obj encodeString((String)args[ ] encoding))} return null} return method invoke(rs args)} private String decodeString(byte[] bytes String enc){ try{ return new String(bytes enc)} catch(UnsupportedEncodingException uee){ return new String(bytes)} } private byte[] encodeString(String str String enc){ try{ return str getBytes(enc)} catch(UnsupportedEncodingException uee){ return str getBytes()} }}使用时调用: ResultSet rs = //原始的ResultSet结果集String encoding = GBK //字符编码(ResultSet)Proxy newProxyInstance(rs getClass() getClassLoader() rs getClass() getInterfaces() new I nResultSetHandler(rs encoding))lishixinzhi/Article/program/Java/hx/201311/26086

1 Java国际化的思路

Java程序的国际化的思路是将程序中的标签、提示等信息放在资源文件中,程序需要支持哪些国家、语言环境,就对应提供相应的资源文件。资源文件是key-value对,每个资源文件中的key是不变的,但value则随不同国家、语言改变。

Java程序的国际化主要通过如下三个类完成:

Ø java.util.ResourceBundle:用于加载一个国家、语言资源包。

Ø java.util.Locale:用于封装一个特定的国家/区域、语言环境。

Ø java.text.MessageFormat:用于格式化带占位符的字符串。

为了实现程序的国际化,必须先提供程序所需要的资源文件。资源文件的内容是很多key-value对。其中key是程序使用的部分,而value则是程序界面的显示字符串。

资源文件的命名可以有如下三种形式:

Ø baseName _ language _country.properties

Ø baseName _language.properties

Ø baseName.properties

其中baseName是资源文件的基本名,用户可以自由定义。而language和country都不可随意变化,必须是Java所支持的语言和国家。

2 Java支持的语言和国家

事实上,Java不可能支持所有国家和语言,如需要获取Java所支持的语言和国家,可调用Locale类的getAvailableLocale方法获取,该方法返回一个Locale数组,该数组里包含了Java所支持的语言和国家。

下面的程序简单地示范了如何获取Java所支持的国家和语言:

public class LocaleList

{

public static void main(String[] args)

{

//返回Java所支持的全部国家和语言的数组

Locale[] localeList = Locale.getAvailableLocales()

//遍历数组的每个元素,依次获取所支持的国家和语言

for (int i = 0i <localeList.length i++ )

{

//打印出所支持的国家和语言

System.out.println(localeList[i].getDisplayCountry() + "=" + locale

List[i].getCountry()+ " " + localeList[i].getDisplayLanguage()

+ "=" + localeList[i].getLanguage())

}

}

}

通过该程序,我们就可以获得Java程序所支持的国家/语言环境。

3 完成程序国际化

对于如下最简单的程序:

public class RawHello

{

public static void main(String[] args)

{

System.out.println("Hello World")

}

}

这个程序的执行结果也很简单:肯定是打印出简单的“Hello World”字符串,不管在哪里执行都不会有任何改变!为了让该程序支持国际化,则肯定不能让程序直接输出“Hello World”的字符串,这种写法直接输出一个字符串常量,永远不会有任何改变。为了让程序可以输出不同的字符串,此处绝不可使用该字符串常量。

为了让上面输出的字符串常量可以改变,我们将需要输出的各种字符串(不同国家/语言环境对应不同的字符串)定义在资源包中。

我们为上面程序提供如下两个文件:

第一个文件:mess_zh_CN.properties,该文件的内容为:

#资源文件的内容是key-value对。

hello=你好!

第二个文件:mess_en_US.properties,该文件的内容为:

#资源文件的内容是key-value对。

hello=Welcome You!

对于包含非西欧字符的资源文件,Java提供了一个工具来处理该文件:native2ascii,这个工具可以在%JAVA_HOME%/bin路径下找到。使用该工具的语法格式如下:

native2ascii 源资源文件 目的资源文件

如果我们在命令窗口输入如下指令:

#使用native2ascii命令处理mess_zh_CN.properties文件,生成aa.properties文件

native2ascii mess_zh_CN.properties aa.properties

上面的命令将生成一个aa.properties文件,该文件才是我们需要的资源文件,该文件看上去包含很多乱码,其实是非西欧字符的UNICODE编码方式,这完全正常。将该文件重命名为mess_zh_CN.properties即可。

我们看到这两份文件文件名的baseName是相同的:mess。前面已经介绍了资源文件的三种命名方式,其中baseName后面的国家、语言必须是Java所支持的国家、语言组合。

将上面的Java程序修改成如下形式:

public class Hello

{

public static void main(String[] args)

{

//取得系统默认的国家/语言环境

Locale myLocale = Locale.getDefault()

//根据指定国家/语言环境加载资源文件

ResourceBundle bundle = ResourceBundle.getBundle("mess" , myLocale)

//打印从资源文件中取得的消息

System.out.println(bundle.getString("hello"))

}

}

上面程序中的打印语句不再是直接打印“Hello World”字符串,而是打印了从资源包中读取的信息。如果在中文环境下运行该程序,将打印“你好!”;如果我们在“控制面板”将机器的语言环境设置成美国,然后再次运行该程序,将打印“Welcome You!”字符串。

通过上面的简单程序,我们可以体会到Java程序的国际化是多么简单!

从上面程序可以看出:如果我们希望程序完成国际化,只需要将不同国家/语言(Locale)的提示信息分别以不同文件存放。例如简体中文的语言资源文件就是Xxx_zh_CN.properties文件,而美国英语的语言资源文件就是Xxx_en_US.properties文件。

Java程序国际化的关键类是ResourceBundle,它有一个静态方法:getBundle(String baseName , Locale locale)该方法将根据Locale加载资源文件,而Locale封装了一个国家、语言,例如简体中文的环境可以用简体中文的Locale代表,美国英语的环境可以用美国英语的Locale代表。

从上面资源文件的命名中可以看出,不同语言、国家环境的资源文件的baseName是相同的,即baseName为mess的资源文件有很多个,不同国家、语言环境对应不同的资源文件。

例如通过如下代码来加载资源文件:

//根据指定国家/语言环境加载资源文件

ResourceBundle bundle = ResourceBundle.getBundle("mess" , myLocale)

上面代码将会加载baseName为mess的系列资源文件的其中之一,到底加载其中的哪个,则取决于myLocale,对于简体中文的Locale,则加载mess_zh_CN.properties文件。

一旦加载了该文件后,该资源文件的内容就是多个key-value对,程序就根据key来获取指定信息,例如获取key为hello的消息,该消息是“你好!”——这就是Java程序国际化的过程。

如果对于美国英语的Locale,则加载mess_en_US.properties,该文件中的key为hello的消息是“Welcome You!”。

Java程序国际化的关键类是ResourceBundle和Locale,ResourceBundle来根据不同Loacle加载语言资源文件,再根据指定key取得已加载语言资源文件中的字符串即可。


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/yw/7917156.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-11
下一篇2023-04-11

发表评论

登录后才能评论

评论列表(0条)

    保存