importcom.mbuyy.servicemobile.mapper.ConfigI18nMapper;importcom.mbuyy.servicemobile.model.ConfigI18n;importcom.mbuyy.servicemobile.util.ValidateUtils;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.context.ResourceLoaderAware;importorg.springframework.context.support.AbstractMessageSource;importorg.springframework.core.io.DefaultResourceLoader;importorg.springframework.core.io.ResourceLoader;importorg.springframework.stereotype.Service;importorg.springframework.web.servlet.support.RequestContextUtils;importjavax.annotation.PostConstruct;importjavax.annotation.Resource;importjavax.servlet.http.HttpServletRequest;importjava.text.MessageFormat;importjava.util.HashMap;importjava.util.List;importjava.util.Locale;importjava.util.Map;importjava.util.concurrent.ConcurrentHashMap;//使用@Compnent("messageSource")注解注入
@Service("messageSource")public class MyMessageSource extends AbstractMessageSource implementsResourceLoaderAware {private final Logger logger = LoggerFactory.getLogger(MyMessageSource.class);
ResourceLoader resourceLoader;//这个是用来缓存数据库中获取到的配置的 数据库配置更改的时候可以调用reload方法重新加载
private static final Map> LOCAL_CACHE = new ConcurrentHashMap<>(256);
@ResourceprivateConfigI18nMapper configI18nMapper;
@AutowiredprivateHttpServletRequest request;/*** 初始化
* Java中该注解的说明:@PostConstruct该注解被用来修饰一个非静态的void()方法。
* 被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次。
* PostConstruct在构造函数之后执行,init()方法之前执行。*/@PostConstructpublic voidinit() {this.reload();
}/*** 重新将数据库中的国际化配置加载*/
public voidreload() {
LOCAL_CACHE.clear();
LOCAL_CACHE.putAll(loadAllMessageResourcesFromDB());
}/*** 从数据库中获取所有国际化配置 这边可以根据自己数据库表结构进行相应的业务实现
* 对应的语言能够取出来对应的值就行了 无需一定要按照这个方法来*/
public Map>loadAllMessageResourcesFromDB() {//获取数据库配置
List list =configI18nMapper.selectAll();if(ValidateUtils.isNotEmpty(list)) {final Map zhCnMessageResources = new HashMap<>(list.size());final Map enUsMessageResources = new HashMap<>(list.size());final Map myMessageResources = new HashMap<>(list.size());for(ConfigI18n item : list) {//根据不同语言,分配到对应语言的值中
if (item.getLanguage().equals("zh")){
zhCnMessageResources.put(item.getModel()+ "." +item.getModelId(), item.getText());
}else if (item.getLanguage().equals("en")){
enUsMessageResources.put(item.getModel()+ "." +item.getModelId(), item.getText());
}else if (item.getLanguage().equals("my")){
myMessageResources.put(item.getModel()+ "." +item.getModelId(), item.getText());
}
}//加入缓存
LOCAL_CACHE.put("zh", zhCnMessageResources);
LOCAL_CACHE.put("en", enUsMessageResources);
LOCAL_CACHE.put("my", myMessageResources);
}return new HashMap<>();
}/*** 从缓存中取出国际化配置对应的数据 或者从父级获取
*
*@paramcode
*@paramlocale 可以为null, 表示从当前HttpServletRequest中获取语言
*@return
*/
publicString getSourceFromCache(String code, Locale locale) {
String language= locale == null ?RequestContextUtils.getLocale(request).getLanguage() : locale.getLanguage();//获取缓存中对应语言的所有数据项
Map props =LOCAL_CACHE.get(language);if (null != props &&props.containsKey(code)) {//如果对应语言中能匹配到数据项,那么直接返回
returnprops.get(code);
}else{//如果对应语言中不能匹配到数据项,从上级获取返回
try{if (null != this.getParentMessageSource()) {return this.getParentMessageSource().getMessage(code, null, locale);
}
}catch(Exception ex) {
logger.error(ex.getMessage(), ex);
}//如果上级也没有找到,那么返回请求键值
returncode;
}
}//下面三个重写的方法是比较重要的
@Overridepublic voidsetResourceLoader(ResourceLoader resourceLoader) {this.resourceLoader = (resourceLoader == null ? newDefaultResourceLoader() : resourceLoader);
}
@OverrideprotectedMessageFormat resolveCode(String code, Locale locale) {
String msg=getSourceFromCache(code, locale);
MessageFormat messageFormat= newMessageFormat(msg, locale);returnmessageFormat;
}
@OverrideprotectedString resolveCodeWithoutArguments(String code, Locale locale) {returngetSourceFromCache(code, locale);
}
}