业务层资源国际化处理

 

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

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

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

 

[java]  view plain copy print ?
  1. @Override  
  2.   public ExecuteResult<User> login(String userName, String password) {  
  3.       ExecuteResult<User> executeResult = new ExecuteResult<User>();  
  4.       User userInfo = userDAO.getUserByName(userName);  
  5.       if(userInfo == null){  
  6.           executeResult.addErrorMessage("不存在的用户名");  
  7.           return executeResult;  
  8.       }  
  9.       if(!userInfo.getPassword().equals(password)){  
  10.           executeResult.addErrorMessage("密码错误");  
  11.           return executeResult;  
  12.       }  
  13.       executeResult.setResult(userInfo);  
  14.       return executeResult;  
  15.   }  

设计实现:

 

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

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

 

[java]  view plain copy print ?
  1. /** 
  2.  * 扩展struts2默认的i18n拦截器,添加设置local到LocaleContextHolder中的功能 
  3.  * @author WangXuzheng 
  4.  * @see com.opensymphony.xwork2.interceptor.I18nInterceptor 
  5.  * @see org.springframework.context.i18n.LocaleContextHolder 
  6.  */  
  7. public class I18nResolverInterceptor extends I18nInterceptor {  
  8.     private static final long serialVersionUID = 5888969294461266478L;  
  9.     @Override  
  10.     protected void saveLocale(ActionInvocation invocation, Locale locale) {  
  11.         super.saveLocale(invocation, locale);  
  12.         LocaleContextHolder.setLocale(locale);  
  13.     }  
  14. }  

2.在struts.xml中替换默认的i18n拦截器

 

 

[html]  view plain copy print ?
  1. <interceptor name="i18n" class="com.haier.openplatform.i18n.interceptor.I18nResolverInterceptor"/>  

3.设计业务层国际化资源解析器接口

 

 

[java]  view plain copy print ?
  1. /** 
  2.  * 国际化资源处理器 
  3.  * @author WangXuzheng 
  4.  * 
  5.  */  
  6. public interface I18nResolver {  
  7.     /** 
  8.      * 设置要进行资源处理的目标类 
  9.      * @param clazz 
  10.      */  
  11.     @SuppressWarnings("rawtypes")  
  12.     public void setClass(Class clazz);  
  13.     /** 
  14.      * 解析国际化资源文件,如果找不到该code,返回默认的消息 
  15.      * @param code i18n资源的key值 
  16.      * @return 如果找到返回具体的消息值,如果不存在返回默认消息 
  17.      * @see java.text.MessageFormat 
  18.      */  
  19.     String getMessage(String code);  
  20.       
  21.     /** 
  22.      * 解析国际化资源文件,如果找不到该code,返回默认的消息 
  23.      * @param code i18n资源的key值 
  24.      * @return 如果找到返回具体的消息值,如果不存在返回默认消息 
  25.      * @see java.text.MessageFormat 
  26.      */  
  27.     String getMessage(String code,String arg);  
  28.     /** 
  29.      * 解析国际化资源文件,如果找不到该code,返回默认的消息 
  30.      * @param code i18n资源的key值 
  31.      * @param args 资源中的变量值 
  32.      * @param defaultMessage 默认消息 
  33.      * @return 如果找到返回具体的消息值,如果不存在返回默认消息 
  34.      * @see java.text.MessageFormat 
  35.      */  
  36.     String getMessage(String code, Object[] args, String defaultMessage);  
  37.     /** 
  38.      * 解析国际化资源文件查找指定code对应的消息,如果不存在,抛出异常 
  39.      * @param code 
  40.      * @param args 
  41.      * @return 
  42.      * @throws MessageNotFoundException 
  43.      * @see java.text.MessageFormat 
  44.      * @throws MessageNotFoundException 
  45.      */  
  46.     String getMessage(String code, Object[] args);  
  47. }  

默认的实现类-这里我们的资源配置文件放在和待处理的类同文件下同名的.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

 

[java]  view plain copy print ?
  1. /** 
  2.  * 默认的资源文件解析器,该类读取<code>org.springframework.context.i18n.LocaleContextHolder</code>中保存的Local信息解析资源文件 
  3.  * @author WangXuzheng 
  4.  * @see org.springframework.context.i18n.LocaleContextHolder 
  5.  */  
  6. public class DefaultI18nResolver extends MessageSourceSupport implements I18nResolver {  
  7.     private static final ConcurrentMap<String, ResourceBundle> BUNDLE_MAP = new ConcurrentHashMap<String, ResourceBundle>();  
  8.     private static final List<String> DEFAULT_RESOURCE_BUNDLES = new CopyOnWriteArrayList<String>();  
  9.     private static final Log LOG = LogFactory.getLog(DefaultI18nResolver.class);  
  10.     @SuppressWarnings("rawtypes")  
  11.     protected Class clazz;  
  12.     /** 
  13.      * 添加全局资源配置信息 
  14.      * 
  15.      * @param resourceBundleName the name of the bundle to add. 
  16.      */  
  17.     public static void addDefaultResourceBundle(String resourceBundleName) {  
  18.         //make sure this doesn't get added more than once  
  19.         synchronized (DEFAULT_RESOURCE_BUNDLES) {  
  20.             DEFAULT_RESOURCE_BUNDLES.remove(resourceBundleName);  
  21.             DEFAULT_RESOURCE_BUNDLES.add(0, resourceBundleName);  
  22.         }  
  23.   
  24.         if (LOG.isDebugEnabled()) {  
  25.             LOG.debug("Added default resource bundle '" + resourceBundleName + "' to default resource bundles = "  
  26.                     + DEFAULT_RESOURCE_BUNDLES);  
  27.         }  
  28.     }  
  29.   
  30.     /** 
  31.      * Creates a key to used for lookup/storing in the bundle misses cache. 
  32.      * 
  33.      * @param aBundleName the name of the bundle (usually it's FQN classname). 
  34.      * @param locale      the locale. 
  35.      * @return the key to use for lookup/storing in the bundle misses cache. 
  36.      */  
  37.     private String createMissesKey(String aBundleName, Locale locale) {  
  38.         return aBundleName + "_" + locale.toString();  
  39.     }  
  40.   
  41.     /** 
  42.      * 从全局资源文件中读取文案信息 
  43.      * 
  44.      * @param aTextName 文案 key 
  45.      * @param locale    the locale the message should be for 
  46.      * @return  
  47.      */  
  48.     private String findDefaultText(String aTextName, Locale locale) {  
  49.         List<String> localList = DEFAULT_RESOURCE_BUNDLES;  
  50.         for (String bundleName : localList) {  
  51.             ResourceBundle bundle = findResourceBundle(bundleName, locale);  
  52.             if (bundle != null) {  
  53.                 try {  
  54.                     return bundle.getString(aTextName);  
  55.                 } catch (MissingResourceException e) {  
  56.                     // ignore and try others  
  57.                 }  
  58.             }  
  59.         }  
  60.         return null;  
  61.     }  
  62.   
  63.     /** 
  64.      * 根据资源名称和locale信息查找资源信息 
  65.      * @param aBundleName the name of the bundle (usually it's FQN classname). 
  66.      * @param locale      the locale. 
  67.      * @return the bundle, <tt>null</tt> if not found. 
  68.      */  
  69.     protected ResourceBundle findResourceBundle(String aBundleName, Locale locale) {  
  70.         String key = createMissesKey(aBundleName, locale);  
  71.         ResourceBundle bundle = BUNDLE_MAP.get(key);  
  72.         if (bundle == null) {  
  73.             bundle = ResourceBundle.getBundle(aBundleName, locale, Thread.currentThread().getContextClassLoader());  
  74.             BUNDLE_MAP.put(key, bundle);  
  75.         }  
  76.         return bundle;  
  77.     }  
  78.   
  79.     private Locale getLocale() {  
  80.         return LocaleContextHolder.getLocale();  
  81.     }  
  82.   
  83.     @Override  
  84.     public String getMessage(String code) {  
  85.         return getMessage(code, new Object[] {});  
  86.     }  
  87.   
  88.     /** 
  89.      * 获取资源消息对应的值,先从指定的bundleName的资源中获取文案,如果找不到,从globalResources中读取 
  90.      * @param bundleName 
  91.      * @param locale 
  92.      * @param key 
  93.      * @param args 
  94.      * @return 
  95.      * @see #findResourceBundle 
  96.      */  
  97.     private String getMessage(String bundleName, Locale locale, String key, Object[] args) {  
  98.         ResourceBundle bundle = findResourceBundle(bundleName, locale);  
  99.         if (bundle == null) {  
  100.             return null;  
  101.         }  
  102.   
  103.         String orginalMessage = null;  
  104.         try {  
  105.             orginalMessage = bundle.getString(key);  
  106.         } catch (MissingResourceException e) {  
  107.             // read text from global resources  
  108.             orginalMessage = findDefaultText(bundleName, locale);  
  109.         }  
  110.         return this.formatMessage(orginalMessage, args, locale);  
  111.     }  
  112.   
  113.     @Override  
  114.     public String getMessage(String code, Object[] args) {  
  115.         return getMessage(resolveBunFile(), getLocale(), code, args);  
  116.     }  
  117.   
  118.     @Override  
  119.     public String getMessage(String code, Object[] args, String defaultMessage) {  
  120.         return StringUtils.defaultIfBlank(getMessage(code, args), defaultMessage);  
  121.     }  
  122.   
  123.     @Override  
  124.     public String getMessage(String code, String arg) {  
  125.         String[] args = new String[] { arg };  
  126.         return getMessage(code, args);  
  127.     }  
  128.   
  129.     protected String resolveBunFile() {  
  130.         String pack = this.clazz.getName();  
  131.         return pack.replaceAll("[.]""/");  
  132.     }  
  133.   
  134.     @SuppressWarnings("rawtypes")  
  135.     public void setClass(Class clazz) {  
  136.         this.clazz = clazz;  
  137.     }  
  138. }  

加一个静态工厂类来获取解析器

 

 

[java]  view plain copy print ?
  1. /** 
  2.  * 资源解析器工厂类 
  3.  * @author WangXuzheng 
  4.  * 
  5.  */  
  6. public final class I18nResolverFactory {  
  7.     @SuppressWarnings("rawtypes")  
  8.     private static final ConcurrentMap<Class, I18nResolver> I18N_RESOVER_MAP = new ConcurrentHashMap<Class, I18nResolver>();  
  9.     private I18nResolverFactory(){  
  10.     }  
  11.       
  12.     @SuppressWarnings("rawtypes")  
  13.     public static I18nResolver getDefaultI18nResolver(Class clazz){  
  14.         I18nResolver resolver = I18N_RESOVER_MAP.get(clazz);  
  15.         if(resolver == null){  
  16.             resolver = new DefaultI18nResolver();  
  17.             resolver.setClass(clazz);  
  18.             I18N_RESOVER_MAP.put(clazz, resolver);  
  19.         }  
  20.         return resolver;  
  21.     }  
  22. }  

4.调用实现-非常类似log4j的调用方式

[java]  view plain copy print ?
  1. public class UserServiceImpl implements UserService {  
  2.     private static final I18nResolver I18N_RESOLVER = I18nResolverFactory.getDefaultI18nResolver(UserServiceImpl.class);  
  3.     private UserDAO userDAO;  
  4.     private RoleDAO roleDAO;  
  5.   
  6. @Override  
  7.     public ExecuteResult<User> login(String userName, String password) {  
  8.         ExecuteResult<User> executeResult = new ExecuteResult<User>();  
  9.         User userInfo = userDAO.getUserByName(userName);  
  10.         if(userInfo == null){  
  11.             executeResult.addErrorMessage( I18N_RESOLVER.getMessage("user.notexisted"));  
  12.             return executeResult;  
  13.         }  
  14.         if(!userInfo.getPassword().equals(password)){  
  15.             executeResult.addErrorMessage(I18N_RESOLVER.getMessage("user.wrongpassword"));  
  16.             return executeResult;  
  17.         }  
  18.         executeResult.setResult(userInfo);  
  19.         return executeResult;  
  20.     }  

更多信息请查看 java进阶网 http://www.javady.com/index.php/category/thread

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值