【狂人小白】轻量级验证框架 Validation.FO 的入门与使用

Validation.FO 使用指南

框架说明

  1. 这是一个验证框架,并且是一个 独立的验证框架 ,不依赖与其他已有的框架;

  2. 可以*的嵌入到其他框架,比如Spring、Struts等流行框架,但实质来说他是独立的,所以无所谓嵌入到哪里,如果需要在GUI桌面应用中,也是完美的;

  3. 配置简单,可*扩展验证器,实际只要实现IValidator接口,以及在rules.fo.xml中添加相关的配置即可;

  4. 支持Spring接口

  5. 使用过程中,你会感觉好像只用了 IValidateService.validate() 一个方法,这会让人感觉良好

优点

  1. 不与任何对象做绑定,最大限度解耦

  2. 只要规则配置写的合理,规则可以复用到多个对象

  3. 扩展验证器很简单

  4. 以Map存储验证结果,非常简单的导出JSON,只要你愿意

相关文档

如何下载

1
2
3
4
5
<dependency>
    <groupId>cc.fozone.validation</groupId>
    <artifactId>fo-validation</artifactId>
    <version>0.9.1.RELEASE</version>
</dependency>

快速开始

使用Validation.FO的步骤如下:

  1. 配置验证规则 rules.fo.xml

  2. 实例化 IValidateService 对象

  3. 调用 IValidateService.validate 方法

基本的使用方法

源代码地址:Basic Usage

1. 创建POJO对象 User.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package validationfo.basic;
 
import java.sql.Timestamp;
 
/**
 * 用户对象
 * @author Jimmy Song
 *
 */
public class User {
    // 用户名
    private String username;
     
    // 密码
    private String password;
    // 再次输入密码
    private String passwordOne;
     
    // 邮箱
    private String email;
     
    // 开始与结束时间
    private Timestamp starttime;
    private Timestamp endtime;
     
    /**
    * Setter & Getter
    */
    ...
}

2. 配置验证规则 rules.fo.xml

  • <include file=""/>
    导入其他规则文件

  • <group name=""></group>
    验证分组,name应该为全局唯一的

  • <field name=""></field>
    验证的字段,name是被验证对象的属性字段名

  • <rule name="" message=""></rule>
    验证规则,name是验证器名称,message是错误后返回的消息

  • <param name="" value=""></param>
    是验证规则时可能需要传入的参数,name是参数名,value是参数值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?xml version="1.0" encoding="UTF-8"?>
<fozone-validation>
    <!-- include 标签导入其他配置 -->
    <include file="validationinfo/basic/another-rules.fo.xml"/>
      
    <!-- 验证组ID,全局唯一 -->
    <group name="user.validate">
        <!-- 验证字段 -->
        <field name="email">
            <!-- 
                规则列表
            -->
            <rule name="required" message="邮件必须填写"/>
        <rule name="between" message="邮件长度应该3-100之间">
            <param name="min" value="3"/>
            <param name="max" value="100"/>
        </rule>
            <rule name="match" message="邮件格式不正确">
                <param name="regex" value="^[A-Za-z]+[\.\-_A-Za-z0-9]*@[A-Za-z0-9]+[\.\-_A-Za-z0-9]*$"/>
            </rule>
        </field>
 
        ...
 
    </group>
</fozone-validation>

3. 实例化测试 BasicTest.java

主要步骤:

  1. 创建配置读取对象IValidateConfig

  2. 创建验证服务对象IValidateService

  3. 执行验证方法IValidateService.validate(object, groupId)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package validationfo.basic;
 
...
 
/**
 * 最基本的测试
 * @author Jimmy Song
 *
 */
public class BasicTest {
    public static void main(String[] args) {
        /**
         * Validation.FO的配置资源
         */
        // 验证器配置,系统默认配置
        String validatorsXML = "validationfo/basic/validators.fo.xml";
        // 规则配置
        String rulesXML = "validationfo/basic/rules.fo.xml";
         
        /**
         * 实例化配置对象
         */
        IValidateConfig config =new BasicValidateConfig(validatorsXML, rulesXML);
        /**
         * 实例化验证服务层
         */
        IValidateService validateService = new BasicValidateService(config);
         
        // 实例化用户
        User user = createUser();
         
        /**
         * 执行验证
         */
        Map<String,String> map = validateService.validate(user, "user.validate");
        // 输出结果
        if(map == null || map.size() == 0) {
            System.out.println("验证成功");
        else {
            System.out.println("验证失败,结果如下");
            System.out.println(map);
        }
    }
}

4. 结果输出

1
2
3
12:31:41,084  INFO BasicValidateConfig:44 - read validation main file , validationfo/basic/rules.fo.xml
验证失败,结果如下
{email=邮件格式不正确, password=两次密码输入不正确, starttime=开始时间不能大于结束时间, endtime=结束时间不能小于开始时间}

如何在Spring中使用

  1. 在Spring中需要使用 SpringValidateConfg 配置对象

  2. 需要额外配置 SpringValidator Bean对象

  3. Spring DEMO 源代码下载

1. 配置Spring配置 context.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 
    <!-- 基于 Spring 配置读取 -->
    <bean id="springValidateConfig" class="cc.fozone.validation.config.SpringValidateConfig">
        <property name="validators">
            <value>validationfo/spring/validators.fo.xml</value>
        </property>
        <property name="rules">
            <value>validationfo/spring/rules.fo.xml</value>
        </property>
    </bean>
     
    <!-- 配置验证服务 -->
    <bean id="basicValidateService" class="cc.fozone.validation.BasicValidateService">
        <constructor-arg index="0" ref="springValidateConfig"/>
    </bean>
     
    <!-- 配置基于Spring的验证器 -->
    <bean class="cc.fozone.validation.validators.SpringValidator"/>
</beans>

2. 如何通过Spring进行验证,SpringTest.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class SpringTest {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
                "validationfo/spring/context.xml");
 
        // 获取验证服务
        IValidateService service = context.getBean(IValidateService.class);
        // 创建用户对象
        User user = createUser();
 
        // 执行验证
        Map<String, String> map = service.validate(user, "user.validate");
        // 输出结果
        if (map == null || map.size() == 0) {
            System.out.println("验证成功");
        else {
            System.out.println("验证失败,结果如下");
            System.out.println(map);
        }
    }
}

3. 执行结果

1
2
3
4
5
6
13:26:00,150  INFO ClassPathXmlApplicationContext:510 - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@283b4947: startup date [Tue Oct 07 13:26:00 CST 2014]; root of context hierarchy
13:26:00,194  INFO XmlBeanDefinitionReader:315 - Loading XML bean definitions from class path resource [validationfo/spring/context.xml]
13:26:00,373  INFO DefaultListableBeanFactory:598 - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@212b0f8a: defining beans [springValidateConfig,basicValidateService,cc.fozone.validation.validators.SpringValidator#0]; root of factory hierarchy
13:26:00,442  INFO BasicValidateConfig:44 - read validation main file , validationfo/spring/rules.fo.xml
验证失败,结果如下
{email=邮件格式不正确, password=两次密码输入不正确, starttime=开始时间不能大于结束时间, endtime=结束时间不能小于开始时间}

Validator验证器与规则

系统默认的验证器文件 validators.fo.xml

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="UTF-8"?>
<fozone-validators>
    <validator name="required" class="cc.fozone.validation.validators.RequiredValidator"/>
    <validator name="match" class="cc.fozone.validation.validators.MatchValidator"/>
    <validator name="between" class="cc.fozone.validation.validators.BetweenValidator"/>
    <validator name="min" class="cc.fozone.validation.validators.MinValidator"/>
    <validator name="max" class="cc.fozone.validation.validators.MaxValidator"/>
    <validator name="equals" class="cc.fozone.validation.validators.EqualsValidator"/>
    <validator name="timestampLessEqual" class="cc.fozone.validation.validators.TimestampLessEqualValidator"/>
    <validator name="timestampCreaterEqual" class="cc.fozone.validation.validators.TimestampCreaterEqualValidator"/>
    <validator name="spring"  useSpring="true" class="cc.fozone.validation.validators.SpringValidator"/>
</fozone-validators>

默认验证规则

required - 必填字段

消息message: 必填

参数param: 无

案例:

1
2
3
4
5
<group name="user.validate">
    <field name="username">
        <rule name="required" message="姓名必须填写。"/>
    </field>
</group>

match - 正则匹配

消息message: 必填

参数param: 

Name Must Description
regex Yes 正则表达式,如果为空,验证直接返回true

案例:

1
2
3
4
5
6
7
<group name="user.validate">
    <field name="email">
        <rule name="match" message="邮件格式不正确">
            <param name="regex" value="^[A-Za-z]+[\.\-_A-Za-z0-9]*@[A-Za-z0-9]+[\.\-_A-Za-z0-9]*$"/>
        </rule>
    </field>
</group>

between - 判断字符串或数组非空长度是否介于两者之间,min <= length <= max

消息message: 必填

参数param: 

Name Must Description
min Yes 最小长度(包含)
max Yes 最大长度(包含)

案例:

1
2
3
4
5
6
7
8
<group name="user.validate">
    <field name="email">
        <rule name="between" message="邮件长度应该3-100之间">
            <param name="min" value="3"/>
            <param name="max" value="100"/>
        </rule>
    </field>
</group>

min - 判断字符串或数组非空长度是否大于等于最小长度,length >= min

消息message: 必填

参数param: 

Name Must Description
value Yes 最小长度(包含)

案例:

1
2
3
4
5
6
7
<group name="user.validate">
    <field name="password">
        <rule name="min" message="密码至少5个字符">
            <param name="value" value="5"/>
        </rule>
    </field>
</group>

max - 判断字符串或数组非空长度是否小于等于最大长度,length <= max

消息message: 必填

参数param: 

Name Must Description
value Yes 最大长度(包含)

案例:

1
2
3
4
5
6
7
<group name="user.validate">
    <field name="password">
        <rule name="max" message="密码最多20个字符">
            <param name="value" value="20"/>
        </rule>
    </field>
</group>

equals - 判断字段是否与指定的字段值是否相同

消息message: 必填

参数param: 

Name Must Description
target Yes 指定的字段名称,并非确定的值

案例:

POJO对象部分字段

1
2
3
4
public class User {
    private String password;
    private String passwordOne;
}
1
2
3
4
5
6
7
<group name="user.validate">
    <field name="password">
        <rule name="equals" message="两次输入的密码不相同">
            <param name="target" value="passwordOne"/>
        </rule>
    </field>
</group>

注:这里会将password与目标passwordOne字段的值进行equals比较
有些时候你可能需要重写equals方法


timestampLessEqual - 时间戳是否小于等于指定的目标时间字段

消息message: 必填

参数param: 

Name Must Description
target Yes 指定的时间字段名称,并非确定的值

案例:

POJO对象部分字段

1
2
3
4
public class User {
    private Timestamp starttime;
    private Timestamp endtime;
}
1
2
3
4
5
6
7
<group name="user.validate">
    <field name="starttime">
        <rule name="timestampLessEqual" message="开始时间不能大于结束时间">
            <param name="target" value="endtime"/>
        </rule>
    </field>
</group>

注:

  1. 这里会将starttime与目标endtime字段的值进行大小比较

  2. 这里的字段必须是java.sql.Timestamp类型


timestampCreaterEqual - 时间戳是否大于等于指定的目标时间字段

消息message: 必填

参数param: 

Name Must Description
target Yes 指定的时间字段名称,并非确定的值

案例:

POJO对象部分字段

1
2
3
4
public class User {
    private Timestamp starttime;
    private Timestamp endtime;
}
1
2
3
4
5
6
7
<group name="user.validate">
    <field name="endtime">
        <rule name="timestampCreaterEqual" message="结束时间不能小于开始时间">
            <param name="target" value="starttime"/>
        </rule>
    </field>
</group>

注:

  1. 这里会将endtime与目标starttime字段的值进行大小比较

  2. 这里的字段必须是java.sql.Timestamp类型


spring - 通过Spring调用其他对象的指定方法进行判断

DEMO: 点击查看

消息message: 必填

参数param: 

Name Must Description
beanName Yes Spring Context中的Bean标识
methodName Yes Bean对象中的指定执行方法,该方法必须返回 boolean 类型
parameterName No 执行方法中传递的参数,**默认** 传递被验证字段的值,如果使用**this** 表示传递被验证的对象, 其他 表示传递对象指定的字段

案例:

POJO对象部分字段

1
2
3
4
public class User {
    private String username;
    private int usernameLength;
}

验证配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<group name="user.validate">
    <field name="username">
        <rule name="spring" message="该用户已存在">
            <param name="beanName" value="userService"/>
            <param name="methodName" value="exist"/>
        </rule>
    </field>
     
    <field name="usernameLength">
        <!-- 使用 this 关键字 -->
        <rule name="spring" message="用户名长度验证错误">
            <param name="beanName" value="userService"/>
            <param name="methodName" value="length"/>
            <param name="parameter" value="this"/>
        </rule>
         
        <!-- 指定字段 -->
        <rule name="spring" message="用户名长度不能小于5个字符">
            <param name="beanName" value="userService"/>
            <param name="methodName" value="lengthByName"/>
            <param name="parameter" value="username"/>
        </rule>
    </field>
</group>

Spring中的配置

1
2
3
4
<beans>
    <!-- 通过Spring进行验证 -->
    <bean id="userService" class="validationfo.springadvance.UserService"/>
</beans>

通过Spring验证的接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package validationfo.springadvance;
 
public class UserService {
    public boolean exist(String value) {
        return !"superman".equals(value);
    }
     
    public boolean length(User user){
        return user.getUsername().length() == user.getUsernameLength();
    }
     
    public boolean lengthByName(String username){
        return username.length() >= 5;
    }
}

注:

  1. 要启用spring配置,需要参照上述的 如何在Spring使用 进行Spring与Validation.FO的整合配置

  2. 指定的对象方法必须返回 boolean 类型

高级部分:如何自定义验证器 IValidator

  1. 实现 IValidator 接口

  2. 在 validators.fo.xml 验证器配置中添加已实现的验证器

  3. 点击这里查看Demo源代码

一个简单的例子

POJO对象

1
2
3
4
5
6
7
8
9
package validationfo.custom;
 
public class Money {
    private int number;
    private String text;
     
    ...
     
}

CustomValidator实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package validationfo.custom;
/**
 * 构造一个判断 参数 是否能够被 指定的值 整出的验证器
 * 例如:对象值为4 ,验证参数为2,那么 4可以被2整除,表示成功
 
 * @author Jimmy Song
 *
 */
public class CustomValidator implements IValidator {
    private static final Logger logger = Logger.getLogger(CustomValidator.class);
     
    /**
     * 要处理的对象
     * @param context 上下文
     * @param type 对象类型
     * @param value 对象值
     * @param rule 对象参数
     * @return 是否成功
     */
    public boolean execute(Object context, Class type, Object value, Rule rule) {
        // TODO Auto-generated method stub
        /**
         * 这里只是演示一下context的用处
         * 可以通过context以及反射获取对象的属性值
         * 举个例子
         */
        try {
            System.out.println("TEXT = "+PropertyUtils.getProperty(context, "text"));
        catch (Exception e1) {
            // TODO Auto-generated catch block
        }
         
        /**
         * 通过 value 实际验证的值
         */
        if(value == nullreturn true;
         
        /**
         * 通过 type 获取值的类型
         */
        if(!(type == Integer.class || type == int.class)) {
            return false;
        }
        int objectValue = ((Integer)value).intValue();
         
         
        /**
         * 通过 rule 获取规则参数
         */
        String toValue = rule.getParameter("value");
        if(StringUtils.isBlank(toValue)) return false;
         
        int intValue = -1;
        try {
            intValue = Integer.parseInt(toValue);
        catch(NumberFormatException e){
            logger.error("倍数值转换错误!");
            return false;
        }
         
        if(intValue <= 0) {
            logger.warn("倍数值不能小于等于0");
            return false;
        }
         
        return objectValue % intValue == 0;
    }
 
}

配置 validators.fo.xml 中添加自定义验证器

关于validators.fo.xml配置的参数说明

语法 : <validator name="" useSpring="true|false"  class=""  beanId=""/>

参数名 必填 含义
name 验证器名称
useSpring 是否通过 Spring 实例化验证器,这样做可以为验证器注入 ApplicationContext
class 当 useSpring=false 时,按照正常的方式进行实例化;当 useSpring=true 时,且使用了 beanId ,则 class 无效,如果没有使用 beanId ,那么 Spring 通过 class 进行实例化
beanId Spring中的bean id
1
2
3
4
5
<?xml version="1.0" encoding="UTF-8"?>
<fozone-validators>
    ...
    <validator name="custom" class="validationfo.custom.CustomValidator"/>
</fozone-validators>

配置验证规则

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="UTF-8"?>
<fozone-validation>
    <!-- 验证组ID,全局唯一 -->
    <group name="money.validate">
        <!-- 验证字段 -->
        <field name="number">
            <rule name="custom" message="验证失败,不能被指定的数整除">
                <param name="value" value="3"/>
            </rule>
        </field>
    </group>
</fozone-validation>

执行测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package validationfo.custom;
 
public class CustomTest {
    public static void main(String[] args) {
        /**
         * Validation.FO的配置资源
         */
        // 验证器配置,系统默认配置
        String validatorsXML = "validationfo/custom/validators.fo.xml";
        // 规则配置
        String rulesXML = "validationfo/custom/rules.fo.xml";
         
        /**
         * 实例化配置对象
         */
        IValidateConfig config =new BasicValidateConfig(validatorsXML, rulesXML);
        /**
         * 实例化验证服务层
         */
        IValidateService validateService = new BasicValidateService(config);
         
        // 实例化数据
        Money money = new Money();
        money.setNumber(7);
        money.setText("演示Context使用的Text");
         
        /**
         * 执行验证
         */
        Map<String,String> map = validateService.validate(money, "money.validate");
        // 输出结果
        if(map == null || map.size() == 0) {
            System.out.println("验证成功");
        else {
            System.out.println("验证失败,结果如下");
            System.out.println(map);
        }
    }  
}

结果输出

1
2
3
4
16:44:17,178  INFO BasicValidateConfig:44 - read validation main file , validationfo/custom/rules.fo.xml
TEXT = 演示Context使用的Text
验证失败,结果如下
{number=验证失败,不能被指定的数整除}









本文转自 sundunjam 51CTO博客,原文链接:http://blog.51cto.com/sunspot/1561016,如需转载请自行联系原作者
上一篇:C# WinForm开发系列 - ComboBox


下一篇:基于bootstrap 的datatable插件的使用(php版)