spring(11)------spring国际化支持

来源:互联网 发布:恋爱的酸臭味 知乎 编辑:程序博客网 时间:2024/05/29 08:37

一,关于spring国际化的简介

在java编程中,对于信息的处理一般有两种方式:

(1)将信息存在数据库里,用的时候从数据库里取。(惯用手法数据字典就是)

(2)将信息存放在java常量类中,通过java类调用属性值。

这两种方式对于处理不需要国际化的网站,系统是能实现的,但是,如果需要国际化,

这两种方式就实现国际化非常困难。

而spring对于国际的实现提供了良好的支持,Application通过继承

org.springframework.context.MessageResource接口,通过getMessage()方法获取信息资源,

从而实现国际化的目的。

二,getMessage()三种形式

(1)getMessage(String code, Object[] args, String defaultMessage, Locale locale);

这个是获取信息的基本方法,如果找不到指定信息,也就是args传入后没有找到,

就用defaultMessage这个信息作为默认信息。

(2)getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException;

跟上一个方法同的是没有指定默认值,如果根据传入参数找不到指定信息,就会抛异常NoSuchMessageException。

(3)getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException;

通过MessageSourceResolvable获取传入信息的信号,传入参数跟上面两个方法类型不一样,一般不常用。

MessageSource源码中getMessage重载了3个方法:

/* * Copyright 2002-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.springframework.context;import java.util.Locale;/** * Strategy interface for resolving messages, with support for the parameterization * and internationalization of such messages. * * <p>Spring provides two out-of-the-box implementations for production: * <ul> * <li>{@link org.springframework.context.support.ResourceBundleMessageSource}, * built on top of the standard {@link java.util.ResourceBundle} * <li>{@link org.springframework.context.support.ReloadableResourceBundleMessageSource}, * being able to reload message definitions without restarting the VM * </ul> * * @author Rod Johnson * @author Juergen Hoeller * @see org.springframework.context.support.ResourceBundleMessageSource * @see org.springframework.context.support.ReloadableResourceBundleMessageSource */public interface MessageSource {/** * Try to resolve the message. Return default message if no message was found. * @param code the code to lookup up, such as 'calculator.noRateSet'. Users of * this class are encouraged to base message names on the relevant fully * qualified class name, thus avoiding conflict and ensuring maximum clarity. * @param args array of arguments that will be filled in for params within * the message (params look like "{0}", "{1,date}", "{2,time}" within a message), * or {@code null} if none. * @param defaultMessage String to return if the lookup fails * @param locale the Locale in which to do the lookup * @return the resolved message if the lookup was successful; * otherwise the default message passed as a parameter * @see java.text.MessageFormat */String getMessage(String code, Object[] args, String defaultMessage, Locale locale);/** * Try to resolve the message. Treat as an error if the message can't be found. * @param code the code to lookup up, such as 'calculator.noRateSet' * @param args Array of arguments that will be filled in for params within * the message (params look like "{0}", "{1,date}", "{2,time}" within a message), * or {@code null} if none. * @param locale the Locale in which to do the lookup * @return the resolved message * @throws NoSuchMessageException if the message wasn't found * @see java.text.MessageFormat */String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException;/** * Try to resolve the message using all the attributes contained within the * {@code MessageSourceResolvable} argument that was passed in. * <p>NOTE: We must throw a {@code NoSuchMessageException} on this method * since at the time of calling this method we aren't able to determine if the * {@code defaultMessage} property of the resolvable is null or not. * @param resolvable value object storing attributes required to properly resolve a message * @param locale the Locale in which to do the lookup * @return the resolved message * @throws NoSuchMessageException if the message wasn't found * @see java.text.MessageFormat */String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException;}

三,spring关于国际化的实现思路

当ApplicationContext被加载的时候,会自动从spring配置文件XML中去查找id为messageSource的bean。

spring约定国际化支持的bean为messageSource,通过org.springframework.context.support.ResourceBundleMessageSource

绑定国际化信息的资源文件,获取国际化信息。

四,简单体验下spring国际化实例,然后再根据实例分析国际化的实现思想

项目结构:

messages_en_CN.properties文件内容:HelloWorld=问候:{0},问候时间:{1}

注意:该文件放在src下



HelloWorld类:

package com.lanhuigu.spring.action;public class HelloWorld{private String msg;//通过set方法注入属性值public void setMsg(String msg) {this.msg = msg;}public String getMsg() {return msg;}}
spring配置文件:

<?xml version="1.0" encoding="UTF-8"?><!--  - Application context definition for JPetStore's business layer.  - Contains bean references to the transaction manager and to the DAOs in  - dataAccessContext-local/jta.xml (see web.xml's "contextConfigLocation").  --><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"><!-- 负责国际化支持 --><bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"><!-- property有两个属性名,basename,basenames               顾名思义,第一个放一个value,第二个放一个或多个value --><property name="basename"><!-- 国际化支持的定义在文件名为message的文件中,     也就是这个地方设置什么,src下对应的配置文件为     messages_en_CN.properties或 messages.class,名字是别的也一个含义--><value>messages_en_CN</value></property><!-- <property name="basenames"><list><value>messages_en_CN</value><value>messages_en_US</value></list></property> --></bean><!-- 定义一个id为sayHello的bean,通过spring配置文件变换实现类,实现不同的功能,无需修改别的程序 --><bean id="sayHello" class="com.lanhuigu.spring.action.HelloWorld" >    <!-- 将变量msg值依赖注入 -->    <property name="msg">    <value>测试</value>    </property>   </bean></beans>
测试程序:

package com.lanhuigu.spring.test;import java.util.Calendar;import java.util.Locale;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import com.lanhuigu.spring.action.HelloWorld;public class TestHelloWorld {@Testpublic void testMyHelloWorld(){//1 读取spring初始化的配置文件ApplicationContext acxt = new ClassPathXmlApplicationContext("/applicationContext.xml");//2 根据bean获取ISayHello实现类对象HelloWorld helloAC = (HelloWorld) acxt.getBean("sayHello");//3 调用接口方法System.out.println(helloAC.getMsg());//4.国际化测试//A.对应messages.properties中的两个参数{0},{1}Object[] objs = new Object[]{"HelloWorld",Calendar.getInstance().getTime()};//B.根据messages.properties中的HelloWorld获取配置,再传入objs数据参数,最后加上国家获取当前时间String mytest = acxt.getMessage("HelloWorld", objs, Locale.CHINA);System.out.println(mytest);}}
运行结果:



输出结果出现乱码的问题,先不管乱码是怎么回事,先根据代码分析国际化原理。

(1)spring配置文件中,国际化bean的id为messageSource(这个是spring约定的),

bean的来源为org.springframework.context.support.ResourceBundleMessageSource,设定bean中的property

属性basename或basenames两者是有区别的,可以看spring配置文件中的注释,property下value的值就是src

配置文件的名字。例如,在spring中<value>messages_en_CN</value>,即为src国际化信息的配置文件为

messages_en_CN.properties。

(2)messages_en_CN.properties资源文件中的配置为:HelloWorld=问候:{0},问候时间:{1}

=(等号)前的HelloWorld为acxt.getMessage("HelloWorld", objs, Locale.CHINA)相当于key值,

根据HelloWorld获取信息资源配置文件中的(value)‘问候:{0},问候时间:{1}’,然后objs将传入对应的参数,

根据后面的语言组装返回对应的字符串:é?????:HelloWorld,é????????é??:16-4-9 下午7:18(乱码下面解决)


从上面可以看出,国际化就是通过ResourceBundleMessageSource接口获取资源文件,

传入对应参数,组装成对应字符串,也就是把从数据库或java常量类获取信息的形式转换

为从资源库获取信息,如果我们放入不同的资源配置文件,获取的就是不同语言的信息,

从而实现国际化,每次需要什么语言就放什么语言的配置文件。

五,解决中文乱码的问题

乱码问题解决办法如下:

(1)转码方式解决,吃力不讨好,不去管它

(2)扩展ResourceBundleMessageSource接口,解决乱码问题。

在上面util代码下,新建ResourceBundleMessageSourceExtend类,继承于ResourceBundleMessageSource,

ResourceBundleMessageSourceExtend.java内容如下:

package com.lanhuigu.spring.util;import java.io.UnsupportedEncodingException;  import java.text.MessageFormat;  import java.util.Locale;  import java.util.Map;  import java.util.concurrent.ConcurrentHashMap;    import org.springframework.context.support.ResourceBundleMessageSource; public class ResourceBundleMessageSourceExtend extends  ResourceBundleMessageSource {  //属性文件使用UTF-8编码(你的属性文件messages.properties使用什么进行编码,ENCODING设置成对应的格式)private static final String ENCODING = "UTF-8";  private static final String NULL = "null";  /** cache the encoding key value * */  Map<String, String> encodingCache = new ConcurrentHashMap<String, String>(      20);  /** * resolve no argus */  protected String resolveCodeWithoutArguments(String code, Locale locale) {  String message = super.resolveCodeWithoutArguments(code, locale);  return decodeString(message, ENCODING);  }  /** * resolve args * @see resolveCode(String code, Locale locale) */  protected MessageFormat createMessageFormat(String msg, Locale locale) {  if (logger.isDebugEnabled()) {      logger.debug("Creating MessageFormat for pattern [" + msg              + "] and locale '" + locale + "'");  }  msg = decodeString(msg, ENCODING);  return new MessageFormat((msg != null ? msg : ""), locale);  }  /** * 转码  * @param msg * @param encode * @return */  private String decodeString(String message, String encode) {  String encodMessage = encodingCache.get(message);  if (encodMessage == null) {      try {          encodMessage = new String(message.getBytes("ISO8859-1"), encode);          if (message != null) {              encodingCache.put(message, encodMessage);          } else {              encodingCache.put(message, NULL);              // log the code is not exist in properties          }      } catch (UnsupportedEncodingException e) {          e.printStackTrace();      }  }  return encodMessage;  }  }
修改spring配置文件为如下:

<?xml version="1.0" encoding="UTF-8"?><!--  - Application context definition for JPetStore's business layer.  - Contains bean references to the transaction manager and to the DAOs in  - dataAccessContext-local/jta.xml (see web.xml's "contextConfigLocation").  --><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"><!-- 负责国际化支持 --><bean id="messageSource" class="com.lanhuigu.spring.util.ResourceBundleMessageSourceExtend"><property name="basename"><value>messages_en_CN</value></property><!-- <property name="basenames"><list><value>messages_en_CN</value><value>messages_en_US</value></list></property> --></bean><bean id="sayHello" class="com.lanhuigu.spring.action.HelloWorld" >    <!-- 将变量msg值依赖注入 -->    <property name="msg">    <value>测试</value>    </property>  </bean></beans>

其他不变,运行结果如下:

乱码好了,这个地方需要注意的就是messages_en_CN.properties编码形式是什么,

扩展接口中得对应了,在propertiest配置文件上右键properties看看编码是啥,然后

设置private static final String ENCODING = "UTF-8";为对应的编码形式,才能避免乱码问题。

比如为UTF-8的形式,所以ENCODING设置成UTF-8,这样做即能支持UTF-8的编码。



0 0