关闭

数据库替代国际化资源文件

标签: 数据库stringhashmap语言hibernateobject
242人阅读 评论(0) 收藏 举报

我的开发平台是java,主要方面是web方面。我在用国际化资源文件是感觉其不够灵活,如果我要修改某此内容的话,还要进行一次服务重启。麻烦。所以我就想把国际化资源的文件放到数据库中。通过取key来获取相应的value。

以下步骤:

第一步:创建一个数据表.

CREATE TABLE KEYVALUE  (
   KEY                  VARCHAR(255)                    NOT NULL,
   VALUE                VARCHAR(2000)                   NOT NULL,
   LANGUAGE             VARCHAR(255)                   DEFAULT 'zh_CN' NOT NULL,
   KEYREMARK            VARCHAR(255),
   CONSTRAINT PK_KEYVALUE PRIMARY KEY (KEY, LANGUAGE)
);

COMMENT ON TABLE KEYVALUE IS
'设定一个key_value的国际化资源表';

COMMENT ON COLUMN KEYVALUE.KEY IS
'key值,可以有占位符';

COMMENT ON COLUMN KEYVALUE.VALUE IS
'对应key值的内容值';

COMMENT ON COLUMN KEYVALUE.LANGUAGE IS
'选择语言,默认,zh_CN';

COMMENT ON COLUMN KEYVALUE.KEYREMARK IS
'key值的说明项。';

主键是采用联合主键的形式。一个是key值,另一个是语言,语言默认是"zh_CN"。

这样就避免了同一种语言环境下不会出现两个相同的name.当然KEYREMARK 是为了给自己添加备注用的。

第二步:建一个接口,此接口主要有几个方法,功能请看注释。


/**
 * 操作keyValue类的接口
 *
 * @author <br>
 *         2012-3-22 下午12:37:25<br>
 * @aim
 */
public interface KeyValueDao {

    /**
     * 通过key获取指定的value值 2012-3-22 下午03:08:30 <br>
     *
     * @param key key值
     * @return 对应key的value值
     */
    public String getValue(String key);

    /**
     * 通过key和指定占位符获取值 2012-3-22 下午03:08:44 <br>
     *
     * @param key key值
     * @param obj 占位符填充内容
     * @return 对应的value值
     */
    public String getValueObj(String key, Object[] obj);

    /**
     * 通过key和本地语言获取值 2012-3-22 下午03:09:28 <br>
     *
     * @param key
     *            key值
     * @param language
     *            语言
     * @return 对应的value值
     */
    public String getValue(String key, String language);

    /**
     *
     * 2012-3-22 下午03:09:59 <br>
     *
     * @param key
     *            key值
     * @param obj
     *            占位符填充内容
     * @param language
     *            语言
     * @return 对应的value值
     */
    public String getValueObj(String key, Object[] obj, String language);

}

第三步:

编写一个实现接口的类。因为我是用hibernate来操作数据库的,所以读者可以根据自己的实际情况,

改用JDBC,但只要获取到数据库中对应key和language的value值即可。

同时还可以使用占位符。如下,数据表中的数据。

//  key               value                                                                                                      language  keyremark

//   welcome    你好,欢迎{0},你的员工号是:{1},所在的{$depart}{$name}是{2}    zh_CN    测试占位符

在测试的时候,可以设定3个值。

结果:

  Object obj[] = new Object[] { "用户姓名", "用户ID", "用户部门" };

KeyValueDao kdao = (KeyValueDao) App.getBean("keyValueImpl");//此用调用的是spring容器的实现类。

//如果不用spring的话,可以直接用实现类。如果也没有用到hibernate的话,就自己用jdbc。

String val = kdao.getValueObj("welcome", obj);

你好,欢迎用户姓名,你的员工号是:用户ID,所在的部门姓名是用户部门


其中关键的代码是如何实现占位符替代和自身引用,如{$depart}将取得key值为depart的内容,这个内容不能有占位符


import java.util.HashMap;
import java.util.ListIterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.hibernate.Query;

import landa.Dao.KeyValueDao;
import landa.POJO.KeyValue;
import landa.config.BaseDaoImpl;

/**
 * 实现接口KeyValueDao的方法
 *
 * @author <br>
 *         2012-3-22 下午03:20:21<br>
 * @aim
 */
public class KeyValueImpl implements KeyValueDao {

    private BaseDaoImpl baseDao = null;

    /**
     * 通过bean容器注入依赖的对象 2012-3-22 下午03:55:24 <br>
     *
     * @param bd
     */
    public void setBaseDao(BaseDaoImpl baseDao) { //这是对应spring容器自动注入值。
        this.baseDao = baseDao;
    }

    @Override
    public String getValue(String key) {

        String value = getHaveSecondKeyValue(key, "zh_CN");// 默认语言
        if (value != null) {// 此语言对应的key值已经被访问过了,则直接返回对应的内容。
            return value;
        }
        value = "";// 如果value==null,第一次访问此语言的key值,将value设置为空字符串。
        String sql = "from KeyValue where key=:key and language=:language";
        Query q = baseDao.getSession().createQuery(sql);
        q.setString("key", key);
        q.setString("language", "zh_CN");

        ListIterator<KeyValue> lt = null;
        lt = q.list().listIterator();
        if (lt.hasNext()) {
            value = lt.next().getValue();
        }

//这是主要是在多次调用的时候,不用再访问数据库。

//如果读者不是用hibernate,而是用jdbc的话,这里的value值应该是ResultSet 对象为rs, value=rs.getString("key"),

//相应的sql="select key from keyvalue where language=?"


        setHaveSecondKeyValue(key, "zh_CN", value);// 因为是第一次访问,所以要将此语言和key值放在HashMap中保存。

        return value;
    }

    @Override
    public String getValueObj(String key, Object[] obj) {
        return returnValue(getValue(key), obj, null);
    }

    @Override
    public String getValue(String key, String language) {
        if (language == null) {
            return getValue(key);
        }
        String value = getHaveSecondKeyValue(key, language);// 默认语言
        if (value != null) {// 此语言对应的key值已经被访问过了,则直接返回对应的内容。
            return value;
        }
        value = "";

        String sql = "from KeyValue where key=:key and language=:language";
        Query q = baseDao.getSession().createQuery(sql);
        q.setString("key", key);
        q.setString("language", language);

        ListIterator<KeyValue> lt = null;
        lt = q.list().listIterator();
        if (lt.hasNext()) {
            value = lt.next().getValue();
        }

        setHaveSecondKeyValue(key, language, value);// 因为是第一次访问,所以要将此语言和key值放在HashMap中保存。
        return value;
    }

    @Override
    public String getValueObj(String key, Object[] obj, String language) {
        return returnValue(getValue(key, language), obj, language);
    }

    /**
     * 匹配占位符的正则表达式
     */
    private final static String regexNum = "\\{\\d{1,}\\}";// 匹配{数字}如{1}
    private final static String regexAZ = "\\{\\$[a-z||A-Z]{1,}\\}";// 匹配{$字母}如{$depart}

    // 匹配是否有数字可引用,即综合regexNum和regexAZ
    private final static String regex2 = "\\{[\\d{1,}]{1}\\}|\\{\\$[a-z||A-Z]{1,}\\}";

    /**
     *
     * 算法:<br>
     * 第一步:取得当前{0}占位符的开始下标;即:start = m.start();<br>
     * 第二步:截取带占位符的key对应的内容.如:key.substring(lastStart, start)<br>
     * 表示方法:即上一个占位符的位置和当前占位符之间的内容,即为追回的内容。<br>
     * 示例:this is {0} example about{1} regexp.<br>
     * 则第一次截取的时候lastStart为0,start = m.start(),即=8;则截取的内容为substring(0,8),<br>
     * 用一个StringBuilder变量添加截取的内容,同时添加替换占位符的内容。<br>
     * 第二次截取的时候lastStart = start + m.group().length();<br>
     * lastStart=上一次占位符位置+占位符长度{0},即:lastStart=8+3。<br>
     * 一起这样循环。 <br>
     *
     * 2012-3-26 上午10:38:09 <br>
     *
     * @param valueOfKey键值
     * @param obj
     *            填充占位符的对象
     * @return 对应key的值
     */
    private String returnValue(String valueOfKey, Object[] obj, String language) {

//关键代码。将从数据库中取出对应key值的带占位符的内容进行替代。用到正则验证。

如:你好,欢迎{0},你的员工号是:{1},所在的{$depart}{$name}是{2}

//{0}用obj[0],替代,{$depart}用key值为depart的进行替代。

        Pattern p2 = Pattern.compile(regex2);
        Pattern pNum = Pattern.compile(regexNum);
        Pattern pAZ = Pattern.compile(regexAZ);
        Matcher m2 = p2.matcher(key);

        StringBuilder newval = new StringBuilder();
        String group = "";
        int glen = 0;
        int lastStart = 0;
        int start = 0;
        while (m2.find()) { //循环获取匹配的内容。
            group = m2.group();
            start = m2.start();
            newval.append(valueOfKey.substring(lastStart, start));
            glen = group.length();
            if (pNum.matcher(group).find()) {//匹配{数字}
                // 根据{num}中获取num的值,如:{2},则获取obj中obj[2]元素的值。group.substring(1,
                // glen - 1))是为了获取{num}中的num
                newval.append(obj[Integer.parseInt(group.substring(1, glen - 1))]);
            } else if (pAZ.matcher(group).find()) {//匹配{$字母}
                // 添加引用。即如:{$depart}则获取key=depart的内容。
                // group.substring(2, glen - 1)为了获取{$key}中key的值
                newval.append(getValue(group.substring(2, glen - 1), language));
            }
            lastStart = start + m2.group().length();
        }
        newval.append(valueOfKey.substring(start + glen));
        return newval.toString();
    }

    private static HashMap<Object, String> HashmapObj = new HashMap<Object, String>();

    /**
     * 对所有读取不存在占位符的key值时,先判断是否已经存在key值中一个HashMap中,<br>
     * 如果已经存在,则在HashMap中读取,如果不存在,则从数据库中读取此key值,同时存在HashMap中。<br>
     *
     * 通过这种方式减少对数据库的访问 <br>
     * 2012-3-27 下午05:00:36 <br>
     *
     * @param key
     *            指定的key
     * @param language
     *            语言
     * @param value
     *            对应key的值
     * @return
     */
    private String getHaveSecondKeyValue(String key, String language) {
        // 取得key值,key值的构造高:语言+key,组成
        // 已经存在对应:语言+key,组成的值,则直接返回
        return HashmapObj.get(key + language);
    }

    /**
     * 设置一个新的HashMap对应的:语言+key组成的值。 <br>
     * 2012-3-27 下午05:15:46 <br>
     *
     * @param key
     *            设置的key值之一
     * @param language
     *            语言
     * @param value
     *            对应key的内容
     */
    private void setHaveSecondKeyValue(String key, String language, String value) {
        HashmapObj.put(key + language, value);
    }
}

第四步:结束。

其实setHaveSecondKeyValue和getHaveSecondKeyValue

这两个方法,主要是为了在程序中保存已经取得的key内容进行保存。

这样就不用多次访问数据库了。如有不懂的话,请再看一看看,如果是不知道用hibernate或spring的话,

就主要看一下方法returnValue就可以了,因为这才是最关键的

说明:第一次在CSDN中乱写,如有错误或不足,请多指教!

本想上传代码供下载的,但不懂如何上传,求教!



0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:3350次
    • 积分:71
    • 等级:
    • 排名:千里之外
    • 原创:4篇
    • 转载:0篇
    • 译文:0篇
    • 评论:1条
    文章存档