业务层资源国际化处理

标签: 业务 资源 国际化 | 发表时间:2012-04-23 09:02 | 作者:CrazyCoder2010
出处:http://blog.csdn.net

用过struts2等mvc框架开发的同学都知道,使用struts2处理国际化的消息非常简单直观,但是mvc框架的定位是在展示层(jsp,action)等,在一个典型的3层结构中,处于最上层的位置,按照分层设计原则,下层组件是不可以调用上层组件的,这样就存在一个问题,我们在业务层中可能也会出现一些需要国际化处理的消息信息,这些信息如何设置呢?

     在这篇文章中,我们将借鉴struts2的国际化处理机制,但是要比struts2简单的多,因为业务层需要国际化处理的消息毕竟是少数,废话不多说,直接上干货

先举个例子-业务层未国际化处理前的代码

  @Override
    public ExecuteResult<User> login(String userName, String password) {
        ExecuteResult<User> executeResult = new ExecuteResult<User>();
        User userInfo = userDAO.getUserByName(userName);
        if(userInfo == null){
            executeResult.addErrorMessage("不存在的用户名");
            return executeResult;
        }
        if(!userInfo.getPassword().equals(password)){
            executeResult.addErrorMessage("密码错误");
            return executeResult;
        }
        executeResult.setResult(userInfo);
        return executeResult;
    }
设计实现:

1.添加国际化消息拦截器

我们的应用是基于struts2的,struts2默认提供了一个i18n拦截器,这里我们扩展了以下该拦截器的功能,将locale信息保存起来

/**
 * 扩展struts2默认的i18n拦截器,添加设置local到LocaleContextHolder中的功能
 * @author WangXuzheng
 * @see com.opensymphony.xwork2.interceptor.I18nInterceptor
 * @see org.springframework.context.i18n.LocaleContextHolder
 */
public class I18nResolverInterceptor extends I18nInterceptor {
	private static final long serialVersionUID = 5888969294461266478L;
	@Override
	protected void saveLocale(ActionInvocation invocation, Locale locale) {
		super.saveLocale(invocation, locale);
		LocaleContextHolder.setLocale(locale);
	}
}
2.在struts.xml中替换默认的i18n拦截器

<interceptor name="i18n" class="com.haier.openplatform.i18n.interceptor.I18nResolverInterceptor"/>
3.设计业务层国际化资源解析器接口

/**
 * 国际化资源处理器
 * @author WangXuzheng
 *
 */
public interface I18nResolver {
	/**
	 * 设置要进行资源处理的目标类
	 * @param clazz
	 */
	@SuppressWarnings("rawtypes")
	public void setClass(Class clazz);
	/**
	 * 解析国际化资源文件,如果找不到该code,返回默认的消息
	 * @param code i18n资源的key值
	 * @return 如果找到返回具体的消息值,如果不存在返回默认消息
	 * @see java.text.MessageFormat
	 */
	String getMessage(String code);
	
	/**
	 * 解析国际化资源文件,如果找不到该code,返回默认的消息
	 * @param code i18n资源的key值
	 * @return 如果找到返回具体的消息值,如果不存在返回默认消息
	 * @see java.text.MessageFormat
	 */
	String getMessage(String code,String arg);
	/**
	 * 解析国际化资源文件,如果找不到该code,返回默认的消息
	 * @param code i18n资源的key值
	 * @param args 资源中的变量值
	 * @param defaultMessage 默认消息
	 * @return 如果找到返回具体的消息值,如果不存在返回默认消息
	 * @see java.text.MessageFormat
	 */
	String getMessage(String code, Object[] args, String defaultMessage);
	/**
	 * 解析国际化资源文件查找指定code对应的消息,如果不存在,抛出异常
	 * @param code
	 * @param args
	 * @return
	 * @throws MessageNotFoundException
	 * @see java.text.MessageFormat
	 * @throws MessageNotFoundException
	 */
	String getMessage(String code, Object[] args);
}
默认的实现类-这里我们的资源配置文件放在和待处理的类同文件下同名的.properties文件中

例如:java类

com.haier.openplatform.showcase.security.service.impl. UserServiceImpl

 对应的资源文件为

com/haier/openplatform/showcase/security/service/impl/UserServiceImpl_zh_CN.properties

com/haier/openplatform/showcase/security/service/impl/UserServiceImpl_en_US.properties

/**
 * 默认的资源文件解析器,该类读取<code>org.springframework.context.i18n.LocaleContextHolder</code>中保存的Local信息解析资源文件
 * @author WangXuzheng
 * @see org.springframework.context.i18n.LocaleContextHolder
 */
public class DefaultI18nResolver extends MessageSourceSupport implements I18nResolver {
	private static final ConcurrentMap<String, ResourceBundle> BUNDLE_MAP = new ConcurrentHashMap<String, ResourceBundle>();
	private static final List<String> DEFAULT_RESOURCE_BUNDLES = new CopyOnWriteArrayList<String>();
	private static final Log LOG = LogFactory.getLog(DefaultI18nResolver.class);
	@SuppressWarnings("rawtypes")
	protected Class clazz;
	/**
	 * 添加全局资源配置信息
	 *
	 * @param resourceBundleName the name of the bundle to add.
	 */
	public static void addDefaultResourceBundle(String resourceBundleName) {
		//make sure this doesn't get added more than once
		synchronized (DEFAULT_RESOURCE_BUNDLES) {
			DEFAULT_RESOURCE_BUNDLES.remove(resourceBundleName);
			DEFAULT_RESOURCE_BUNDLES.add(0, resourceBundleName);
		}

		if (LOG.isDebugEnabled()) {
			LOG.debug("Added default resource bundle '" + resourceBundleName + "' to default resource bundles = "
					+ DEFAULT_RESOURCE_BUNDLES);
		}
	}

	/**
	 * Creates a key to used for lookup/storing in the bundle misses cache.
	 *
	 * @param aBundleName the name of the bundle (usually it's FQN classname).
	 * @param locale      the locale.
	 * @return the key to use for lookup/storing in the bundle misses cache.
	 */
	private String createMissesKey(String aBundleName, Locale locale) {
		return aBundleName + "_" + locale.toString();
	}

	/**
	 * 从全局资源文件中读取文案信息
	 *
	 * @param aTextName 文案 key
	 * @param locale    the locale the message should be for
	 * @return 
	 */
	private String findDefaultText(String aTextName, Locale locale) {
		List<String> localList = DEFAULT_RESOURCE_BUNDLES;
		for (String bundleName : localList) {
			ResourceBundle bundle = findResourceBundle(bundleName, locale);
			if (bundle != null) {
				try {
					return bundle.getString(aTextName);
				} catch (MissingResourceException e) {
					// ignore and try others
				}
			}
		}
		return null;
	}

	/**
	 * 根据资源名称和locale信息查找资源信息
	 * @param aBundleName the name of the bundle (usually it's FQN classname).
	 * @param locale      the locale.
	 * @return the bundle, <tt>null</tt> if not found.
	 */
	protected ResourceBundle findResourceBundle(String aBundleName, Locale locale) {
		String key = createMissesKey(aBundleName, locale);
		ResourceBundle bundle = BUNDLE_MAP.get(key);
		if (bundle == null) {
			bundle = ResourceBundle.getBundle(aBundleName, locale, Thread.currentThread().getContextClassLoader());
			BUNDLE_MAP.put(key, bundle);
		}
		return bundle;
	}

	private Locale getLocale() {
		return LocaleContextHolder.getLocale();
	}

	@Override
	public String getMessage(String code) {
		return getMessage(code, new Object[] {});
	}

	/**
	 * 获取资源消息对应的值,先从指定的bundleName的资源中获取文案,如果找不到,从globalResources中读取
	 * @param bundleName
	 * @param locale
	 * @param key
	 * @param args
	 * @return
	 * @see #findResourceBundle
	 */
	private String getMessage(String bundleName, Locale locale, String key, Object[] args) {
		ResourceBundle bundle = findResourceBundle(bundleName, locale);
		if (bundle == null) {
			return null;
		}

		String orginalMessage = null;
		try {
			orginalMessage = bundle.getString(key);
		} catch (MissingResourceException e) {
			// read text from global resources
			orginalMessage = findDefaultText(bundleName, locale);
		}
		return this.formatMessage(orginalMessage, args, locale);
	}

	@Override
	public String getMessage(String code, Object[] args) {
		return getMessage(resolveBunFile(), getLocale(), code, args);
	}

	@Override
	public String getMessage(String code, Object[] args, String defaultMessage) {
		return StringUtils.defaultIfBlank(getMessage(code, args), defaultMessage);
	}

	@Override
	public String getMessage(String code, String arg) {
		String[] args = new String[] { arg };
		return getMessage(code, args);
	}

	protected String resolveBunFile() {
		String pack = this.clazz.getName();
		return pack.replaceAll("[.]", "/");
	}

	@SuppressWarnings("rawtypes")
	public void setClass(Class clazz) {
		this.clazz = clazz;
	}
}
加一个静态工厂类来获取解析器

/**
 * 资源解析器工厂类
 * @author WangXuzheng
 *
 */
public final class I18nResolverFactory {
	@SuppressWarnings("rawtypes")
	private static final ConcurrentMap<Class, I18nResolver> I18N_RESOVER_MAP = new ConcurrentHashMap<Class, I18nResolver>();
	private I18nResolverFactory(){
	}
	
	@SuppressWarnings("rawtypes")
	public static I18nResolver getDefaultI18nResolver(Class clazz){
		I18nResolver resolver = I18N_RESOVER_MAP.get(clazz);
		if(resolver == null){
			resolver = new DefaultI18nResolver();
			resolver.setClass(clazz);
			I18N_RESOVER_MAP.put(clazz, resolver);
		}
		return resolver;
	}
}
4.调用实现-非常类似log4j的调用方式
public class UserServiceImpl implements UserService {
    private static final I18nResolver I18N_RESOLVER = I18nResolverFactory.getDefaultI18nResolver(UserServiceImpl.class);
    private UserDAO userDAO;
    private RoleDAO roleDAO;

@Override
    public ExecuteResult<User> login(String userName, String password) {
        ExecuteResult<User> executeResult = new ExecuteResult<User>();
        User userInfo = userDAO.getUserByName(userName);
        if(userInfo == null){
            executeResult.addErrorMessage( I18N_RESOLVER.getMessage("user.notexisted"));
            return executeResult;
        }
        if(!userInfo.getPassword().equals(password)){
            executeResult.addErrorMessage(I18N_RESOLVER.getMessage("user.wrongpassword"));
            return executeResult;
        }
        executeResult.setResult(userInfo);
        return executeResult;
    }



作者:CrazyCoder2010 发表于2012-4-23 9:02:45 原文链接
阅读:3 评论:0 查看评论

相关 [业务 资源 国际化] 推荐:

业务层资源国际化处理

- - CSDN博客推荐文章
用过struts2等mvc框架开发的同学都知道,使用struts2处理国际化的消息非常简单直观,但是mvc框架的定位是在展示层(jsp,action)等,在一个典型的3层结构中,处于最上层的位置,按照分层设计原则,下层组件是不可以调用上层组件的,这样就存在一个问题,我们在业务层中可能也会出现一些需要国际化处理的消息信息,这些信息如何设置呢.

Java国际化:BreakIterator

- - 编程语言 - ITeye博客
【译自:http://tutorials.jenkov.com/java-internationalization/breakiterator.html , 不准确别怪我】. java.text.BreakIterator 类用来查找不同语言中的字符、单词和句子的边界. 因为不同的语言有不同的字、单词和句子的边界,所以只是查找空格、逗号、句号、分号和冒号是不够的.

Chrome插件的国际化技巧

- iBeyond - keakon的涂鸦馆
今天在查看Proxy SwitchySharp的源码时,看到了一个国际化的技巧. 觉得很不错,于是给Sync My Tabs插件增加了国际化支持,并在此分享. 其实之前我在做Chrome插件时都有个疑点,翻译JavaScript里的文字用Chrome的i18n API很容易,但是要翻译HTML就麻烦了,毕竟动态生成HTML没有静态的方便.

关于HTML5和CSS3的国际化支持

- Amo - HTML5研究小组
随着html5和CSS3在国内的升温,我们来了解一下关于HTML5和CSS3的国际化支持. HTML5、CSS3在国际化支持,解决跨文化和语言问题上有了更大的进步,很好的体现了人性化的设计理念. 一、Padding-start、padding-end. CSS3的属性padding-start, padding-end,用于解决跨语言书写习惯的padding问题.

struts 国际化及i18n拦截器原理

- - 企业架构 - ITeye博客
1.在struts2中可以使用标签获取国际化资源信息,如果带有占位符使用来提供参数. 2.多种资源文件配置方式:. 1.全局资源文件配置,在struts.xml中struts.custom.i18n.resources设置资源文件名称,如.

中兴华为获软银4G大单 TD-LTE国际化加速

- diaoxsh - cnBeta.COM
9月28日,记者获悉,日本第三大移动运营商软银(Softbank)已于近日和中国设备商中兴、华为达成战略合作,将由二者共同为其建设基于TDD技术的4G网络. 据悉,该网络将实现日本90%的人口覆盖,是目前为止全球范围内最大的TD-LTE建设项目. 此前,最大的TD-LTE建设项目在瑞典,由和记黄埔负责运营,预计于今年11月商用.

Google+资源手册

- 向往自由的风 - FeedzShare
发布时间:2011年08月02日,  已有 2 人推荐. Google在社交网络上的大动作已经足以引起Twitter和Facebook的危机感. 它以迅雷不及掩耳之势在短短16天内就俘获了1000万用户,而Twitter当时达到这个用户数用了780天,Facebook则长达852天. 不过和大部分新兴的在线服务一样,人们可能在注册了一个账户之后就几乎不管它了.

iOS开发资源

- - Starming星光社最新更新
iOS App UI 欣赏、分享精美的App界面设计. iOS代码实例搜索、iOS特效示例、iOS代码例子下载. 以web的形式提供iOS UI设计的素材,你可以在web上拖动一些控件做出简单的ios 应用效果,并且生成一个URL,能分享给其他人. 一款 Photoshop 插件,由 UI Parade 推出的一款针对iOS UI 的设计工具,设计师动动鼠标即可制作精美的 iOS 应用原型.

艾瑞:直播互动类在线少儿英语受热捧,国际化步伐加快

- - IT瘾-iresearch
导语:2016年中国在线少儿英语行业市场规模达到19.7亿元,增幅为45.4%. 而且随着用户规模的不断扩大,在线少儿英语教育的市场规模还将有更大发展,预计到2019年将超过50亿元. 导语:在线少儿英语赛道在最近一年多成为 互联网领域又一个引人注目的板块:2015年11月,vipabc母公司TutorGroup(现更名为iTutorGroup)完成2亿美元的C轮融资;2016年6月,51Talk在美股上市,公开募资4560万美元;紧接着,VIPKID在8月获得1亿美元C轮融资以及科比的 风投背书;年底,哒哒英语也宣布完成数亿元B+轮融资.