properties属性文件设计&实践(1) - 多个属性文件

在项目中,一般会在类路径下存在这样的一个属性文件,如:config.properties systemconfig.properties等,通过属性文件可以实现以下目的
1. 统一维护公用的配置性属性
2. 不修改class/jar,改变类的行为

一般还会针对此属性文件提供一个类来读取其属性

 

本文介绍一种在设计公用代码时的属性文件通用设计思路,即多个属性文件
1. 默认属性文件
    在公用代码工程维护,发布时直接打包到jar中,其中的属性会被2、3覆盖
2. 各工程自定义属性文件
    在公用代码工程不维护,使用者提供,其中属性会被3覆盖
3. 不可覆盖的属性文件
    公用代码工程维护,发布时直接打包到jar中

 

具体实现

1.Configuration 属性读取类

2.config.default.properties 默认属性文件

3.config.properties 各工程自定义属性文件

4.config.nooverride.properties 不可覆盖的属性文件

 

1.Configuration 属性读取类

 

package mov.demo;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 属性读取类
 * @author mov
 * @since 0.0.1
 */
public class Configuration {
    private static Logger log = LoggerFactory.getLogger(Configuration.class);

    private static Properties props = new Properties();;

    /** 默认属性文件 */
    private static final String CONFIG_FILE_DEFAULT = "config.default.properties";

    /** 各工程自定义配置 */
    private static final String CONFIG_FILE_USER_DEFINED = "config.properties";

    /** 不可覆盖的属性文件 */
    private static final String CONFIG_FILE_NO_OVERRIDE = "config.nooverride.properties";

    static {
        int successLoadedCount = 0;
        /* 先加载默认配置 */
        if (loadConfig(CONFIG_FILE_DEFAULT)) {
            ++successLoadedCount;
        }

        /* 再加载用户自定义配置,以覆盖默认 */
        if (loadConfig(CONFIG_FILE_USER_DEFINED)) {
            ++successLoadedCount;
        }

        /* 最后加载不可覆盖的配置,以覆盖所有 */
        if (loadConfig(CONFIG_FILE_NO_OVERRIDE)) {
            ++successLoadedCount;
        }

        if (successLoadedCount == 0) {
            log.error("all config file load error");
        }
    }

    /**
     * 获取属性值
     * @param key
     * @return 属性存在时返回对应的值,否则返回""
     */
    public static String getCfgValue(String key) {
        return getCfgValue(key, "");
    }

    /**
     * 获取属性值
     * @param key
     * @param defaultValue
     * @return 属性存在时返回对应的值,否则返回defaultValue
     */
    public static String getCfgValue(String key, String defaultValue) {
        return props.getProperty(key, defaultValue);
    }

    /**
     * 获取属性值
     * @param key
     * @return 属性存在且可以转为int时返回对应的值,否则返回0
     */
    public static int getIntCfgValue(String key) {
        return getIntCfgValue(key, 0);
    }

    /**
     * 获取属性值
     * @param key
     * @param defaultValue
     * @return 属性存在且可以转为int时时返回对应的值,否则返回defaultValue
     */
    public static int getIntCfgValue(String key, int defaultValue) {
        String val = getCfgValue(key);
        if (!isEmpty(val)) {
            try {
                return Integer.parseInt(val);
            } catch (NumberFormatException e) {
                log.warn("error get config. value ‘{}‘ is not a valid int for key ‘{}‘"
                        , val, key);
            }
        }

        return defaultValue;
    }

    /**
     * 获取属性值
     * @param key
     * @return 属性存在时返回对应的值,否则返回false
     */
    public static boolean getBooleanCfgValue(String key) {
        return getBooleanCfgValue(key, false);
    }

    /**
     * 获取属性值
     * @param key
     * @param defaultValue
     * @return 属性存在时返回对应的值,否则返回defaultValue
     */
    public static boolean getBooleanCfgValue(String key, boolean defaultValue) {
        String val = getCfgValue(key);
        if (!isEmpty(val)) {
            return Boolean.parseBoolean(val);
        } else {
            return defaultValue;
        }
    }

    private static boolean loadConfig(String configFile) {
        boolean success = false;
        InputStream inputStream = null;
        try {
            inputStream = Configuration.class.getClassLoader().getResourceAsStream(configFile);

            if (inputStream != null) {
                props.load(inputStream);
                success = true;
            } else {
                log.warn("project config file ‘classpath:{}‘ not found", configFile);
            }
        } catch (Throwable e) {
            log.error("error load config file ‘classpath:{}‘", configFile, e);
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    // do nothing
                }
            }
        }

        return success;
    }

    private static boolean isEmpty(String val) {
        return val == null || val.length() == 0;
    }
}

 

2.config.default.properties 默认属性文件

string.in.default=default
string.in.defaultAndUserdefine=default
string.in.all=default

 

3.config.properties 各工程自定义属性文件

string.in.defaultAndUserdefine=userdefine
string.in.all=userdefine

int.positive=1000
int.negative=-1000
int.overflow=2147483648
int.underflow=-2147483649

boolean.true=TruE
boolean.false=whatever

 

4.config.nooverride.properties 不可覆盖的属性文件

string.in.all=nooverride

 

单元测试

package mov.demo;

import static org.junit.Assert.*;

import org.junit.Test;

public class ConfigurationTest {

    @Test
    public void testGetCfgValueString() {
        assertEquals("", Configuration.getCfgValue("not.exists"));
        assertEquals("default", Configuration.getCfgValue("string.in.default"));
        assertEquals("userdefine", Configuration.getCfgValue("string.in.defaultAndUserdefine"));
        assertEquals("nooverride", Configuration.getCfgValue("string.in.all"));
    }

    @Test
    public void testGetCfgValueStringString() {
        assertEquals(null, Configuration.getCfgValue("not.exists", null));
        assertEquals("default", Configuration.getCfgValue("string.in.default", null));
        assertEquals("userdefine", Configuration.getCfgValue("string.in.defaultAndUserdefine", null));
        assertEquals("nooverride", Configuration.getCfgValue("string.in.all", null));
    }

    @Test
    public void testGetIntCfgValueString() {
        assertEquals(0, Configuration.getIntCfgValue("not.exists"));
        assertEquals(1000, Configuration.getIntCfgValue("int.positive"));
        assertEquals(-1000, Configuration.getIntCfgValue("int.negative"));
        assertEquals(0, Configuration.getIntCfgValue("int.overflow"));
        assertEquals(0, Configuration.getIntCfgValue("int.underflow"));
    }

    @Test
    public void testGetIntCfgValueStringInt() {
        assertEquals(-1, Configuration.getIntCfgValue("not.exists", -1));
        assertEquals(1000, Configuration.getIntCfgValue("int.positive", -1));
        assertEquals(-1000, Configuration.getIntCfgValue("int.negative", -1));
        assertEquals(-1, Configuration.getIntCfgValue("int.overflow", -1));
        assertEquals(-1, Configuration.getIntCfgValue("int.underflow", -1));
    }

    @Test
    public void testGetBooleanCfgValueString() {
        assertFalse(Configuration.getBooleanCfgValue("not.exists"));
        assertTrue(Configuration.getBooleanCfgValue("boolean.true"));
        assertFalse(Configuration.getBooleanCfgValue("boolean.false"));
    }

    @Test
    public void testGetBooleanCfgValueStringBoolean() {
        assertTrue(Configuration.getBooleanCfgValue("not.exists", true));
        assertTrue(Configuration.getBooleanCfgValue("boolean.true", false));
        assertFalse(Configuration.getBooleanCfgValue("boolean.false", true));
    }
}

 

运行单元测试类,结果如下

时间: 2024-08-24 05:18:08

properties属性文件设计&实践(1) - 多个属性文件的相关文章

EntityFramework之领域驱动设计实践

EntityFramework之领域驱动设计实践 - 前言 EntityFramework之领域驱动设计实践 (一):从DataTable到EntityObject EntityFramework之领域驱动设计实践 (二):分层架构 EntityFramework之领域驱动设计实践 (三):案例:一个简易的销售系统 EntityFramework之领域驱动设计实践 (四):存储过程 - 领域驱动的反模式 EntityFramework之领域驱动设计实践 (五):聚合 EntityFramewor

(转)EntityFramework之领域驱动设计实践

EntityFramework之领域驱动设计实践 - 前言 EntityFramework之领域驱动设计实践 (一):从DataTable到EntityObject EntityFramework之领域驱动设计实践 (二):分层架构 EntityFramework之领域驱动设计实践 (三):案例:一个简易的销售系统 EntityFramework之领域驱动设计实践 (四):存储过程 - 领域驱动的反模式 EntityFramework之领域驱动设计实践 (五):聚合 EntityFramewor

JavaScript网站设计实践(七)编写最后一个页面 改进表单

原文:JavaScript网站设计实践(七)编写最后一个页面 改进表单 一.最后一个页面 contact.html.改进表单 在该页面实现的功能: 几乎所有的网站都会有表单填写,对于用户输入和填写的数据,首先我们一般现在前台验证,然后再去后台验证. 在前台最简单的验证:检查必填字段是否填写.填写格式是否符合要求等. 每个表单里面,当获取到输入焦点时,令提示文本消失 现在开始动手来写. 1.实现思路 (1)在这个表单里会验证的是必填字段和邮箱格式是否正确.首先,把判断必填字段和邮箱格式分别写在两个

JavaScript网站设计实践(二)实现导航栏当前所选页面的菜单项高亮显示

一.(一)中的代码还可以修改的地方. 在(一)中,如果是运行在服务器下,如apache等,可以把head和navigation的div抽取出来,放置在另一个html文件里,然后在页面中,include进来.这样,当要对导航栏进行修改时,只需要修改一个文件,而不用修改所有相关的页面文件.不过,我这里没有这样做,没有抽取出来. 二.实现当前页面的标识+不同页面的head头部背景图片的改变 现在在(一)实现的基础之上,来实现导航栏当前所选页面的菜单项高亮显示,让访问者一路了然知道"我正在这里"

《响应式Web设计实践》学习笔记

原书: 响应式Web设计实践 第2章 流动布局 1. 布局选项 传统的固定布局中存在很多问题, 随着屏幕大小的越来越多元化, 固定布局已经不能适用了. 在流动布局中, 度量的单位不再是像素, 而是变成了百分比. 弹性布局与流动布局类似, 但是通常情况下, 弹性布局中会以em来作为单位. 带来一个好处是随着用户增大或减小字体, 适用弹性布局的元素的宽度也会等比例地变化. 但是其也可能出现水平滚动条 混合布局 媒体查询: 媒体查询允许根据设备的信息----诸如屏幕宽度, 方向或者分辨率等属性来使用不

JavaScript网站设计实践(四)编写about.html页面,利用JavaScript和DOM,选择性的显示和隐藏DIV元素

一.现在我们在网站设计(三)的基础上,来编写about.html页面. 这个页面要用到的知识点是利用JavaScript和DOM实现选择性地显示和隐藏某些DIV about.html页面在前面我们为了看导航栏菜单项高亮显示时,已经写了部分内容,只是那时写的代码没有实现div显示和隐藏,现在就在之前编写的基础上,为页面添加显示和隐藏div的效果. 没有写JavaScript之前看到的效果: 实现后的效果图: 这个就是我们现在要做的效果. 1.背景: 我们在about.html页面中写了一个ul列表

JavaScript网站设计实践(六)编写live.html页面 改进表格显示

原文:JavaScript网站设计实践(六)编写live.html页面 改进表格显示 一.编写live.html页面,1.JavaScript实现表格的隔行换色,并且当鼠标移过时当前行高亮显示:2.是输出表格中的abbr标签的内容 实现后的效果图是这样的: 1.实现思路 在输出表格的时候,给出一个判断,如果偶数或是奇数行我们想换色,则添加一个class为odd的值,在这个class里就设置了表格不同颜色tr行. 这里用到了一个判断函数:(下面是两个不同的方法,任选其一) 法一://隔行换色 添加

JavaScript网站设计实践(三)设计有特色的主页,给主页链接添加JavaScript动画脚本

原文:JavaScript网站设计实践(三)设计有特色的主页,给主页链接添加JavaScript动画脚本 一.主页一般都会比较有特色,现在在网站设计(二)实现的基础上,来给主页添加一点动画效果. 1.这里实现的动画效果是:当鼠标悬停在其中某个超链接时,会显示出属于该页面的背景缩略图,让用户知道这个链接的页面大概内容是什么. 效果图: 2.实现这个效果的思路 (1)把主页的几个链接的背景图片缩放到150px*150px,拼成一张750*150的图片,并保存为slideshow.png,存放到ima

JavaScript网站设计实践(五)编写photos.html页面,实现点击缩略图显示大图的效果

原文:JavaScript网站设计实践(五)编写photos.html页面,实现点击缩略图显示大图的效果 一.photos.html页面,点击每一张缩略图,就在占位符的位置那里,显示对应的大图. 看到的页面效果是这样的: 1.实现思路 这个功能在之前的JavaScript美术馆那里已经实现了. 首先在页面中使用ul列表显示出所有的缩略图,然后使用JavaScript,for循环检查出当前点击的是哪一张图片,最后把这张图片给显示出来. 用到三个函数:显示图片函数.创建占位符预装图片.点击显示图片