• springboot项目实现数据库读取国际化配置


    首先,springboot是支持国际化的,上下文加载的时候会查询messageSource的bean,如果没有就会创建一个名为messageSource放在上下文中

    所以,我们要创建一个messageSource的bean,代码如下:

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

    上面声明了messageResource的Bean,并在服务启动时,将数据库文件加入了缓存,下面我们展示如何获取国际化的对应信息


    @Autowired
    private MyMessageSource myMessageSource;

    myMessageSource.getSourceFromCache("topSerch.content", null)
    myMessageSource.getSourceFromCache中我们从缓存中取值,后面如果是null那么我们就从当前缓存中取
    接下来我们说一下,接口请求中附带语言标识的两种方式
    POST请求:Header中附带Accept-Language,Accept-Language对应的值为数据库存的国际语言缩写值,如:"Accept-Language:zh"
    GET请求:在url后增加lang参数,lang对应的值为数据库存的国际语言缩写值,如:"url?lang=zh"
    

    以上就配置好了从数据库中读取数据国际化文件,但是我为了方便,需要再后台管理增加国际化文件的相关配置,所以有了下面的做法

    先说下想法:我想让后台管理新增一条数据时,自己去填写相应的国际化配置,所以我需要让后台管理做新增操作,但是为了同步新增和代码中使用的模块相同,所以我创建了一张config_i18n_model表,用来存储固定的几个模板,如果代码中有变动,就手动修改

    drop table if exists config_i18n;
    
    /*==============================================================*/
    /* Table: config_i18n                                           */
    /*==============================================================*/
    create table config_i18n
    (
       id                   int not null auto_increment,
       model                varchar(50) comment '模块,类型',
       model_id             int comment '模块id',
       name                 varchar(255) comment '键名',
       text                 varchar(1024) comment '',
       language             varchar(255) comment '对应的语言',
       primary key (id)
    );
    
    alter table config_i18n comment '国际化配置数据库';

    并且,为了使每个模块的配置,对应模块的多条数据,我在config_i18n表中,增加了model_id字段,表示当前国际化数据对应的是model模块的model_id这条记录

    drop table if exists config_i18n;
    
    /*==============================================================*/
    /* Table: config_i18n                                           */
    /*==============================================================*/
    create table config_i18n
    (
       id                   int not null auto_increment,
       model                varchar(50) comment '模块,类型',
       model_id             int comment '模块id',
       name                 varchar(255) comment '键名',
       text                 varchar(1024) comment '',
       language             varchar(255) comment '对应的语言',
       primary key (id)
    );
    
    alter table config_i18n comment '国际化配置数据库';

    最后,在代码的对应模块中,根据数据id取对应模块的国际化值。

    注意:对国际化配置数据库进行增删改时,必须调用以下代码重新加载数据库配置文件,否则不会生效

    myMessageSource.reload()
    
    
    
  • 相关阅读:
    http header Contenttype
    SharePoint 2010 文档库中直接打开文档
    玩转Google开源C++单元测试框架Google Test系列(gtest)(总)
    最近感兴趣的二三事
    最近遭遇的两个VS配置
    环游世界,走遍读过的每一个国家和城镇
    趣题一则:如何快速过桥?
    NASA庆祝地球日:50年地球最精美图片亮相(转载)
    Silverlight,Windows 8应用开发实例教程系列汇总
    Windows 8实例教程系列 数据绑定高级实例
  • 原文地址:https://www.cnblogs.com/fuhui-study-footprint/p/13396818.html
Copyright © 2020-2023  润新知