首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网站开发 > XML SOAP >

Xml ResourceBundle简略实现

2012-07-24 
Xml ResourceBundle简单实现ResourceBundle主要是用于和本地语言环境相关的一些资源绑定。特别是String资源

Xml ResourceBundle简单实现

ResourceBundle主要是用于和本地语言环境相关的一些资源绑定。特别是String资源。

从国际化的设计角度看,一般在代码里不编写和语言环境相关的东西。比如在代码里编写和语言环境相关的错误提示或信息。

以下面枚举为例:

public enum WeekdayEnum {    Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday;}

?如果期望在不同的weekday的心情,不同语言环境输出不同的信息,如中文环境希望这样输出:

Monday:星期一郁闷  Tuesday:星期二忐忑 Wednesday:星期三难熬  Thursday:星期四期待  Friday星期五激动  Saturday:星期六高兴  Sunday:星期天担忧  

这时我们需要定义资源文件,为不同的语言环境制定不同的资源文件,同时支持占位符,可以通过动态传入字符串替换占位符。

?

JDK自带的ResourceBundle支持properties文件作为资源文件绑定。而我们有的时候希望更习惯于xml的文件定义。这时可以基于JDK ResourceBundl扩展,实现基于XML的ResourceBundl资源绑定。

我们公司里面的二方库有一套xml resourcebundle的实现,但是该实现需要依赖一些外部的jar包,如xml解析等等。

?

有时候,这种基础功能基于原生实现更方便,不要去依赖其他的二方库,所以实现了一套完全基于JDK的实现。


1.定义资源文件 WeekDayEnum.xml

?

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"><properties><entry key="Monday">星期一郁闷</entry><entry key="Tuesday">星期二忐忑</entry><entry key="Wednesday">星期三难熬</entry><entry key="Thursday">星期四期待</entry><entry key="Friday">星期五激动</entry><entry key="Saturday">星期六高兴</entry><entry key="Sunday">星期天担忧</entry></properties> 

?

2.编写代码实现

2.1.XmlResourceFactory

?

public class XmlResourceBundleFactory {    private static XMLResourceBundleControl DEFAULT_CONTROL = new XMLResourceBundleControl(null,true);    private final static String             POINT_REGEX     = "\\.";    /**     * 通过默认的XMLResourceBundleControl获取资源Bundle     *      * <pre>     * 默认的XMLResourceBundleControl实现,就在classpath的跟目录下查找资源文件。     * </pre>     *      * @param fileName     * @return     */    public static ResourceBundle getBundle(String fileName) {        return ResourceBundle.getBundle(fileName, DEFAULT_CONTROL);    }    /**     * 通过指定path的XMLResourceBundleControl获取资源Bundle     *      * <pre>     * 指定path的XMLResourceBundleControl实现,会在指定的classpath目录下查找资源文件。     * </pre>     *      * @param fileName     * @param classpath     * @return     */    public static ResourceBundle getBundle(String classpath, String fileName) {        XMLResourceBundleControl xmlResourceBundleControl = new XMLResourceBundleControl(classpath,true);        return ResourceBundle.getBundle(fileName, xmlResourceBundleControl);    }    public static class XMLResourceBundleControl extends ResourceBundle.Control {        private String  resourcePath;    // 資源的classpath路径        private boolean seprateDotPrefix; // 用于标识是否把包含点的baseName前缀过滤掉。        XMLResourceBundleControl(String resourcePath, boolean seprateDotPrefix){            this.resourcePath = resourcePath;            this.seprateDotPrefix = seprateDotPrefix;        }        public List<String> getFormats(String baseName) {            return Collections.singletonList("xml");        }        public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader,                                        boolean reload) throws IllegalAccessException, InstantiationException,                                                       IOException {            if ((baseName == null) || (locale == null) || (format == null) || (loader == null)) {                throw new NullPointerException();            }            ResourceBundle bundle = null;            if (!format.equals("xml")) {                return null;            }            if (seprateDotPrefix) {                if (baseName.indexOf(".") > 0) {                    String array[] = baseName.split(POINT_REGEX);                    baseName = array[array.length - 1];                }            }            String bundleName = toBundleName(baseName, locale);            String resourceName = toResourceName(bundleName, format);            String resourceFullName = resourceName;            if (resourcePath != null && !"".equals(resourcePath.trim())) {// baseName可能包含包命前綴,把包命前綴去除                resourceFullName = resourcePath + "/" + resourceName;            }            URL url = loader.getResource(resourceFullName);            if (url == null) {                return null;            }            URLConnection connection = url.openConnection();            if (connection == null) {                return null;            }            if (reload) {                connection.setUseCaches(false);            }            InputStream stream = connection.getInputStream();            if (stream == null) {                return null;            }            BufferedInputStream bis = new BufferedInputStream(stream);            bundle = new XMLResourceBundle(bis);            bis.close();            return bundle;        }    }    static class XMLResourceBundle extends ResourceBundle {        private Properties props;        XMLResourceBundle(InputStream stream) throws IOException{            props = new Properties();            props.loadFromXML(stream);        }        protected Object handleGetObject(String key) {            return props.getProperty(key);        }        public Enumeration<String> getKeys() {            Set<String> handleKeys = props.stringPropertyNames();            return Collections.enumeration(handleKeys);        }    }}

?2.2 CodeMessageHolder

public class CodeMessageHolder {    private Class<?>       type;    private String         resourcePath;    private ResourceBundle resourceBundle;    /**     * 从指定路径加载resource     *      * @param type     * @param classpath     */    private CodeMessageHolder(Class<?> type, String classpath){        this.type = type;        this.resourcePath = classpath;        loadBundleBySpecialPath();    }    /**     * 从默认路径加载resource     *      * @param type     */    private CodeMessageHolder(Class<?> type){        this.type = type;        loadBundleByDefault();    }    protected static CodeMessageHolder newDefaultMessageHolder(Class<?> type) {        return new CodeMessageHolder(type);    }        protected static CodeMessageHolder newSpecialPathMessageHolder(Class<?> type,String classpath) {        return new CodeMessageHolder(type,classpath);    }    private void loadBundleByDefault() {        resourceBundle = XmlResourceBundleFactory.getBundle(type.getName());    }    private void loadBundleBySpecialPath() {        resourceBundle = XmlResourceBundleFactory.getBundle(resourcePath, type.getName());    }    public String getMessage(Enum<?> e) {        if (resourceBundle == null) {            return null;        }        return resourceBundle.getString(e.name());    }    public String getMessage(String key) {        if (resourceBundle == null) {            return null;        }        return resourceBundle.getString(key);    }    public String getMessage(Enum<?> e, String... param) {        String s = getMessage(e);        if (s == null) {            return null;        }        return MessageFormat.format(s, (Object[]) param);    }    public String getMessage(String key, String... param) {        String s = getMessage(key);        if (s == null) {            return null;        }        return MessageFormat.format(s, (Object[]) param);    }}
?

?

3.编写枚举测试类,测试绑定

public enum WeekdayEnum {    Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday;    private static CodeMessageHolder messageHolder = CodeMessageHolder.newDefaultMessageHolder(WeekdayEnum.class);    public String getMessage() {        return messageHolder.getMessage(this);    }    public String getMessage(String... params) {        return messageHolder.getMessage(this, params);    }    public static void main(String[] args) {        for (WeekdayEnum w : WeekdayEnum.values()) {            System.out.println(w.getMessage());        }    }}
?

?

?

关于resourcebundle内部实现,JDK是基于cache来做的,不需要每次都去装载资源文件。内部实现看源码即可明白,这里不过多解释。

?

附件附上源码实现,刚好看到这个且有兴趣的,欢迎一起交流或提供建议。

?

?

1 楼 san_yun 2012-04-21   上次你提到可增量的倒排序索引来解决标签问题,什么时候分享下这方面的心得吧? 2 楼 singleant 2012-04-24   san_yun 写道上次你提到可增量的倒排序索引来解决标签问题,什么时候分享下这方面的心得吧?
我只是觉得技术上可行呀 具体场景上我也没用过 3 楼 laiweiweihi 2012-05-06   楼主,可以用绝对路径代替 ClassPath 么?资源文件非要放在 ClassPath 下么? 4 楼 san_yun 2012-05-06   javaeye 太恶心了,这也要通知我。。。。。 5 楼 singleant 2012-05-07   laiweiweihi 写道楼主,可以用绝对路径代替 ClassPath 么?资源文件非要放在 ClassPath 下么?
这个用绝对路径不是太好吧?classpath自包含比较好。
绝对路径可以做,不过就意味着和环境绑定在一起了,这个绝对路径就需要一个可配置的入口。

热点排行