• 简约之美jodd--props属性使用


      Prop是一个超级properties;包含了很多jdk缺失的东西:utf-8支持,宏,分区,profiles,全配置等等。

    属性存储在一个或者多个*.props文件,而且它是开放的,支持多种类型的资源。更重要的是,它和java properties是兼容的。

      Props的目标不是提供一个最大限度地配置解决方案,而是提供一个比java properties更好的选择。因此如果在应用中使用到properties,考虑使用Props来替代。

     基本规则

    下面是介绍props文件格式的一组基本规则。其中的一些规则如下示例:

    props example

    utf8编码

    默认情况下,props文件是utf8编码,也可以使用别的任意编码格式。不管使用哪种编码格式,props加载java properites时仍然使用ISO 8859-1.

    去除空白字符

    分区名称和属性名称的开头结尾的空白字符将被去除掉,而属性值也会去除开头和结尾的空白字符。

    赋值

    可以使用"="或者":"进行赋值。

    值连接

    使用"+="连接同名属性的值(以逗号分隔)。

    注解

    从";"或者"#"开头到行的结尾来注解。

    转义符

    使用""作为转义符,对字符进行转义(例如 "#"代表了字符"#","\"代表"")。

    多行的值(Multi-line values)

    如果""作为行的连接符,表明下一行仍然是属性的值。

    特殊字符

    \uXXXX将被编译为字符,同样 , ,f也会编译为字符。

    多行值(Multiline values)

    使用三引号作为一种方便的形式来定义多行的值。

    注:三引号的语法是一对连续的单引号或者双引号(通常都是成对的用)。

    三引号让程序员从引号和特殊字符串的泥潭里面解脱出来,自始至终保持一小块字符串的格式是所谓的WYSIWYG(所见即所得)格式的。

    基本用法

    Props的使用非常简单。概况的说,Props管理着属性。

        Props p = new Props();
        p.load(new File("example.props"));
        ...
        String story = p.getValue("story");

    Props加载属性的方法有多种形式:文件、输入流、字符串、属性Properties。然后通过Props的etValue方法来调用属性值,这个方法通常返回一个字符串的值。

    分区

      分区和INI文件的分区非常相似。在Props中,分区仅表示前缀相同的一组键,这组键直到分区结尾或者文件结尾。

      分区名称已[开头,以]结尾。属于该分区的属性在分区的头部之后。分区名称将作为前缀加到分区属性中。分区以空的[]结尾或者新的分区开始或者到文件尾部。

    示例如下:

    [users.data]
    weight = 49.5
    height = 87.7
    age = 63
    []
    comment=this is base property

    下面的和上述示例等同:

    users.data.weight = 49.5
    users.data.height = 87.7
    users.data.age = 63
    comment=this is base property

    因此,分区可以缩短文件,从而使文件更可读。

    Profiles

    通常情况下,一个应用有不同的环境,因此要求不同组别的属性。例如web应用的测试环境、发布环境。一种组织这些属性的方法是定义不同的profile,在这些profile里同样的键有不同的值。

    Props支持属性的Profile。Profile定义在键名内:profile名称以<>包装。一个可以可以有一个或者多个profile定义。同样,profile可以定义在键名的任意地方,甚至在单词的中间;然而,最好还是把它放到键名的尾部。

    没有profile的属性是基于属性的,若检索特定profile的属性失败,将会检查基本的属性。

    profile可以看着相同属性组的一个“不同的视图”或者“快照”。示例:

    db.port=3086
    
    db.url<develop>=localhost
    db.username<develop>=root
    
    db.url<deploy>=192.168.1.101
    db.username<deploy>=app2499

    在上面的示例中,定义了3个键,两个键拥有两个不同的profile(develop/deploy)且没有基本的值。

    上文提到,分区是一个键的前缀定义,并且profile可以定义在键名的任意地方,因而分区名称也可以包含profile定义,上述的示例可以改造如下:

    db.port=3086
    
    [db<develop>]
    url=localhost
    username=root
    
    [db<deploy>]
    url=192.168.1.101
    username=app2499

    当检索上述值时,可以指定活跃的profile:

        String url = props.getValue("db.url", "develop");
        String user = props.getValue("db.username", "develop");

    注意:一个profile可以同时定义多次。profile的顺序非常重要!当键定义到多个活跃的profile时,将返回第一个的值(第一个匹配的profile的值)。

    你也可以仅仅检索基本属性(忽略profile)--使用getBaseValue()方法。基本属性不属于任何profile。

    默认的活跃profile

    通常,在一个应用的生命周期中,只有一组profile是活跃的。不需要每次在调用getValues()时都传递此活跃的profile。Props支持在外部定义这个所谓的活跃profile,这个定义在加载属性的props文件中。

    在使用getValue(String)检索属性时,活跃的profile就是默认的profile。活跃profile以@profiles的特殊属性键定义。例如:

    key1=hello
    key1<one>=Hi!
    
    @profiles=one

    则下面的java代码:

    String value = props.getValue("key1");

    将会返回值“Hi!”,因为活跃profile是"one".

    活跃profile也可以通过java代码设置,方法是:setActiveProfiles().

    内部profile

      有这样一种场景:两个或者多个profile共享大部分配置,而只有很少一部分属性是不同的。为避免在每个profile中重复定义所有的属性,可以使用内部profile定义哪些不同的属性。Props首先检索内部profile的键,然后检索基本属性,示例如下:

    key1<one>=Hi!
    key2<one>=...
    ....
    key100<one>=...
    
    key1<one.two>=Hola!

    上述示例定义了两个profiles,第一个名称为"one",包含了100个键值对。第二个profile是一个名称为one.two的内部profile。它包含一个属性(key1)---但上层profile所有属性都是可用的!当使用java代码调用上述属性:props.getValue("key1", "one.two")时将会怎样呢?

    Props将会

      在内部名为one.two的profile中检索属性

      如果没有找到,Props检查上一层的profile:one。

      如果还检索不到,没有更上一层的profile了,Props检索基本属性。

    内部profile可用有很多层。

    Props最大的优点是支持宏。宏是一些键值的引用,别的键可用使用该值。宏以{}包装。示例如下:

    key1=Something ${foo}
    ...
    foo=nice

    key1的值是“Something nice”。宏可用引用任意存在的属性键,不管它们定义在哪里。

    同样也支持嵌套的宏,示例如下:

    key1=**${key${key3}}**
    key3=2
    key2=foo

    key1的值是"**foo**".

    宏和profile

    宏通常使用当前活跃或者提供的profile来解析。若当前的profile改变了,宏的值通常也会改变。

    这种行为由标志位useActiveProfilesWhenResolvingMacros来控制。例子如下:

    root=/app
    root<foo>=/foo
    data.path=${root}/data

    data.path的值在profile设置为active时是多少?因为foo是活跃的,root的值变为/foo,因此data.path的值为/foo/data.

    若我们关闭所有的profile而只使用基本属性,data.path的值时/app/data.

    也可以显示的设置宏的profile:

    root=/app
    root<foo>=/foo
    data.path=${root<foo>}/data

    上述例子中,宏root将一直使用foo profile而不管当前选定的profile,因而data.path的值将一直是"/foo/data".

    多行值

    多行的值可以通过三引号定义。中间的都看做值:

    email.body='''
        Hello $n,
    
        welcome!
    '''

    注意:多行的值的空白将不会对剪短!因此上述示例中的值将包含5行。

    遍历和键的顺序

    Props中的键是有顺序的!因此可以根据属性文件中键的顺序遍历所有的键。不用如下代码:

    foo.1=value1
    foo.2=value2
    ...

    你可以遍历props如下:

     Props props = ....
     Iterator<PropsEntry> it = p.iterator();

    遍历的顺序和props定义的顺序一致。

    更进一步,可以通过增加profile来过滤检索或者/和分区遍历。你可以这样写:

        Iterator<PropsEntry> it = p.entries()
                .section("one.two")
                .profile("prof1", "prof2")
                .iterator();

    上述代码仅仅遍历给定分区和给定profile的属性。

    由于引入了profile,可以将一个键定义在属性文件的多个地方。例如,你可以为两个不同的profile定义一个特定的值。在这种情况下,将不能确定键的正确顺序:是第一个检索到的键还是它所在位置获取的值?你可以通过使用skipDuplicatesByValue和skipDuplicatesByPosition()来控制。

    复制操作符

    假定你有一定数量的属性,即默认情况下,和不同种类的数目一样,示例如下:

    com.jodd.action1=value1
    com.jodd.action2=value2
    ...
    org.jodd.action1=value1
    org.jodd.action2=value2
    ...
    net.jodd.... # etc

    Props支持你使用复制操作符(<=)来最小化重复的属性,上述属性可以写成如下形式:

    [actions]
    action1=value1
    action2=value2
    ...
    
    []
    org.jodd <= actions
    
    [com]
    jodd <= actions
    
    [net.jodd]
    <= actions

    上述示例显示了使用复制操作的三种不同方法,没有使用分区,使用部分分区和完全使用分区。使用这三种方法的哪一种都可以,你可以任意选择一种。

    注意:复制的值设置为宏,因此上述所有复制的属性也等同于:

    org.jodd.action1=${actions.action1}
    com.jodd.action1=${actions.action1}
    ....

    配置

     使用几种配置设置可以很好的对Props进行调优:

      新行转义值

        当行结尾符(EOL)需要转义时,指定一个新的字符串。默认值是空的字符串,故多行的值和单行的值连接起来。如果新行转义值被设置为,例如" "时,多行的值将以多行的形式保存。

      截左侧值

        如果需要从左边剪断的话,设置此值。

      截右侧值

        如果需要从右边剪断的话,设置此值。

       新行忽略前面的空白值

        若值分割为多行(以转义EOL)时需要忽略主要的空白值时定义此值。默认值时true,因此下面的多行属性:

    key1=line1
         line2
    line3

    将被读成line1line2line3(连接成的)

      跳过空的属性

        跳过空的属性的标志位。

      连接重复的属性

        一旦设置,重复的属性键将不会覆盖旧的键,而是连接并且通过逗号分隔。

      多行值

        默认启用,利用一种更便利的方式来书写多行的值,以三引号(和python一样)来书写。三引号内的所有字符认作一个值,因此新行不需要转义。

    源码如下:

    /**
         * Value that will be inserted when escaping the new line.
         */
        protected String escapeNewLineValue = StringPool.EMPTY;
    
        /**
         * Trims left the value.
         */
        protected boolean valueTrimLeft = true;
    
        /**
         * Trims right the value.
         */
        protected boolean valueTrimRight = true;
    
        /**
         * Defines if starting whitespaces when value is split in the new line
         * should be ignored or not.
         */
        protected boolean ignorePrefixWhitespacesOnNewLine = true;
    
        /**
         * Defines if multi-line values may be written using triple-quotes
         * as in python.
         */
        protected boolean multilineValues = true;
    
        /**
         * Don't include empty properties.
         */
        protected boolean skipEmptyProps = true;

    参考文献:

    http://jodd.org/doc/props.html

  • 相关阅读:
    iframe页面调用父窗口JS函数
    href超级链接里加上javascript代码的,还有target问题
    IE上的兼容性调整问题烦死啦
    如何在java web工程下建立存储property文件的文件夹,让Java程序直接读取
    当是class com.cosl.po.Pc$$EnhancerByCGLIB$$38c58f03时,反射属性都他妈不好用了
    好奇怪啊,如果邮箱JSON格式的字符串不是在一行上,那么转为JSON将转换不成功,估计是数据格式有问题吧
    flexpaper上传带中文名字的文档,在页面显示若出现404错误时,请在server.xml文件中进行编码utf-8
    loger4j时间一长,就不向数据库里写日志啦,然而重新启动工程后就可以再次向数据库写日志,好奇怪
    直接在filter过滤器代码里加org.apache.struts2.ServletActionContext.getRequest()会出现空指针情况
    ssh框架从页面传中文发生乱码时怎么解决,就是添加一个字符编码拦截器。用springframework自带的便可
  • 原文地址:https://www.cnblogs.com/davidwang456/p/4575195.html
Copyright © 2020-2023  润新知