`
linxueqin
  • 浏览: 273 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
最近访客 更多访客>>
社区版块
存档分类
最新评论

验证模块从原理到实践

阅读更多

        以下内容带大家一起设计一个验证功能模块,既然要做一个这样的模块,我们就把有关的概念做一下设计。

 

验证器

package cc.soft.validate;

import cc.soft.validate.ValidateException;

public interface Validator {

    void validate(Object obj) throws ValidateException;
}

 

验证异常类

 

package cc.soft.validate;

@SuppressWarnings("serial")
public class ValidateException extends Exception {

    public ValidateException() {
        // TODO Auto-generated constructor stub
    }

    public ValidateException(String message) {
        super(message);
        // TODO Auto-generated constructor stub
    }

    public ValidateException(Throwable cause) {
        super(cause);
        // TODO Auto-generated constructor stub
    }

    public ValidateException(String message, Throwable cause) {
        super(message, cause);
        // TODO Auto-generated constructor stub
    }

    public ValidateException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
        // TODO Auto-generated constructor stub
    }

}

 

 

验证结果

package cc.soft.validate;

public class Violation {

    private String path;

    private String message;

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    @Override
    public String toString() {
        return "Violation [path=" + path + ", message=" + message + "]";
    }

}

 

    验证规则

package cc.soft.validate;

public interface ValidateRule extends ValidateNode {

}

 

    验证节点

package cc.soft.validate;

import java.util.List;

public interface ValidateNode {

    List<ValidateNode> getChildren();

    void setChildren(List<ValidateNode> children);

    Validator[] getValidators();

    void setValidators(Validator[] validators);
}

 

    验证上下文

package cc.soft.validate;

import java.util.List;

public interface ValidateContext {

    List<Violation> validate(Object target, ValidateRule rule) throws Exception;

}

 

    以上的其它模型概念都比较好理解,这里说一下ValidateNode是如何抽象出来的,假如有两个类型如下

 

 

package cc.soft.validate;

public class Book {

    /**
     * 书名
     */
    private String name;

    /**
     * 作者
     */
    private Person author;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Person getAuthor() {
        return author;
    }

    public void setAuthor(Person author) {
        this.author = author;
    }

}

 

 

 

package cc.soft.validate;

public class Person {

	/**
	 * 姓名
	 */
	private String name;

	/**
	 * 别名
	 */
	private String[] alisNames;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String[] getAlisNames() {
		return alisNames;
	}

	public void setAlisNames(String[] alisNames) {
		this.alisNames = alisNames;
	}

}

 

 

    现有一个Book实例 book,  book.getName() 可以用来描述书本名这个值,book.getOwner().getName() 可以用来描述书本作者的名字的值, book.getOwner().getAlisNames()[0] 可以用来描述书本作者的第一个别名,另外我们也可以使用另外一种, 

根值(RootBean) + 路径(Path)的方式。想必用过Xpath的朋友都很熟悉了。

 

书本名=book + /name

作者名=book + /onwer/name

第一个别名值 = book + /owner/alisNames/1  (为什么不写成 /owner/alisNames[0], 咱就别纠结这了…… 嘿嘿,别忘了我们的目标是来讨论ValidateNode是怎么来的)

 

我们把路径用/切分, 是不是就切成了一节一节的, 这么一节一节的就是我们的那个ValidateNode了。藕断丝连,那么Node就是一个链式结构(先别怼我看到的Node结构不是一个链式结构),每一个Node都有0或1个上级Node, 但因为有的Node是共用的,自然就把他设计成树结构比较好点吧,这样一来,从叶子往根看,还是一条链。好了 ValidateNode#getChildren(); 这个事情算说明白了。

 

再看 ValidateNode#getValidators()是怎么回事。从Validator这个类角度来看,他的功能就是验证一个给定的Object值,如果不符合规则,就抛出一个ValidateException,至于规则嘛,就是模块的扩展点了,这个就符合了Validator接口的设计。 从要验证的Object值角度来看,一个值有1个或多个Validator。所以ValidateNode#getValidators()就说通了。

 

 

ValidateRule 呢,咱就认为是一个树根的 ValidateNode就行了。 

 

这么一下来可以这么描述

 

/name [{验证器1},{验证器2}……]

/onwer/name [{验证器4},{验证器4}……]

/owner/alisNames/* [{验证器5},{验证器6}……]

 

再回头看看我们的路径描述 如 /owner/alisNames/1 切断了之后, 应该有两种类型的Node, 一种是有名称的,一种是代表集合的。因此设计如下两个类型

 

 

package cc.soft.validate.core;

public class SimpleValidateNode extends AbstractValidateNode {

    private String name;

    public SimpleValidateNode(String name) {
        super();
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

 

package cc.soft.validate.core;

public class ArrayValidateNode extends AbstractValidateNode {

}

 

 

    好了,概念模型大概梳理已经完成,接下来就是实现这套模型了。实现的过程没什么好解释的,有兴趣的可以把代码下载来参考

    在这里引入一个题外话,只有核心没有外围的东西,不好用。 我们知道一杆Q的核心 Q樘+Z弹+Z针, 但你见过一把Q只包含这三样的么, 都是为了各种需求,加上D夹呀,准镜呀 才是一个实用的Q。回到话题,规则如何定义?

 

在 bean上用Annotation来定义?

用 path=[验证器集合描述] 的kv方式?

还是其它的方式,外围不可轻视,决定着你的产品的易用性

 

以下是使用json来定义的规则,*代表的是多值字段 &代表的是子属性类型的规则定义

{
	"name": [
		{
			"type": "required",
			"message": "书名必填"
		},
		{
			"type": "length",
			"minLength": "3",
			"message": "书名长度不小于3"
		}
	],
	"author": [
		{
			"type": "required",
			"message": "书名作者必填"
		}
	],
	"author&": {
		"name": [
			{
				"type": "required",
				"message": "姓名必填"
			}
		],
		"alisNames": [
			{
				"type": "required",
				"message": "别名必填"
			}
		],
		"alisNames*": [
			{
				"type": "required",
				"message": "值必填"
			},
			{
				"type": "length",
				"minLength": "3",
				"message": "别名长度不小于3"
			}
		]
	}
}

  

 

好了,第一次写文章,到此为止。

 

 

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics