现在的位置: 首页 > 综合 > 正文

strut2 学习之验证框架八visitor验证器

2014年07月17日 ⁄ 综合 ⁄ 共 4065字 ⁄ 字号 评论关闭

在上一集中我们讲到了属性验证器,相对比较简单.

在这一集中我们继续讲visitor验证器,该验证器的用处是当action 中的属性不是基本类型和字符串时,如,对象,数组,集合等.


我们先新建一个类Person,就两个属性.

	private int id;
	private String name;


省略了相应的get/set方法

再新建一个Action--PersonAction,继承自ActionSupport.

代码如下:

	private Person person;

	public Person getPerson() {
		return person;
	}

	public void setPerson(Person person) {
		this.person = person;
	}


增加一个Person类型的属性person.

在struts.xml文件中配置action,

		<action name="person" class="action.main.PersonAction">
			<result name="input">/index.jsp</result>
		</action>

再在PersonAction同目录下新建一个PersonAction-validation.xml文件,代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN"
"http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">

<validators>
	 <field name="person">
	 	<field-validator type="visitor">
	 		<param name="context">per</param>
	 		<message>action</message>
	 </field-validator>
</validators>

这里还有一个参数是appendPrefix,这个意思是action中这个验证器的消息将会最终添加到person验证器的消息开头.默认值是true.context这个参数的值可以是任意的,但是要跟下面这个文件的名称一致,如果不指定的话,将会使用action的名称.

然后再在Person同目录下新建一个Person-per-validation.xml文件,代码如下:

<validators>
	<field name="name">
		<field-validator type="fieldexpression">
			<param name="expression">equals("qqq")</param>
			<message>-----${name}person.name${{"aa","aaa","bb","cc"}}</message>
		</field-validator>
	</field>
</validators>

好了,代码就是这样,下面看一下运行效果.

在浏览器中输入http://localhost:8080/a/person.action?person.name=bbbb,可以看到运行结果如下:


可以看到已经将person属性給拦截了,因为是name是"bbbb",所以不满足表达式,"action" 被添加到了最后的消息开头,然后输出了person验证器中的消息.


使用起来还是很简单的.

下面就我的理解我来解释一下context这个字符串的作用,

官方文档上的说法是,ActionValidatorManager将使用这个参数来查找与action相关的ValidatorConfigs(处理validator 配置文件)类.可以用来根据 ActionClass-context-validation.xml这个模式来查找validation.xml文件,默认的值是action的名字,validator拦截器給我们提供了一个方法,

 protected String getValidationContext(ActionProxy proxy) {
        // This method created for WW-3753
        return proxy.getActionName();
 }

注意到了没有,这是protected的,亲,你懂的.

意味着我们可以重写这个方法,根据我们自己的规则去返回这个context給struts2使用.
比如,我们的action有不同的验证文件,你可以根据条件来返回不一样的context字符串,比如,如果sex是男,就返回"nan",是女就返回"nv",你懂的.

下面上一段代码,看一下struts2是如何找验证文件的,

private List<ValidatorConfig> buildValidatorConfigs(Class clazz, String context, boolean checkFile, Set<String> checked) {
        List<ValidatorConfig> validatorConfigs = new ArrayList<ValidatorConfig>();

        if (checked == null) {
            checked = new TreeSet<String>();
        } else if (checked.contains(clazz.getName())) {
            return validatorConfigs;
        }

        if (clazz.isInterface()) {
            Class[] interfaces = clazz.getInterfaces();

            for (Class anInterface : interfaces) {
                validatorConfigs.addAll(buildValidatorConfigs(anInterface, context, checkFile, checked));
            }
        } else {
            if (!clazz.equals(Object.class)) {
                validatorConfigs.addAll(buildValidatorConfigs(clazz.getSuperclass(), context, checkFile, checked));
            }
        }

        // look for validators for implemented interfaces
        Class[] interfaces = clazz.getInterfaces();

        for (Class anInterface1 : interfaces) {
            if (checked.contains(anInterface1.getName())) {
                continue;
            }

            validatorConfigs.addAll(buildClassValidatorConfigs(anInterface1, checkFile));

            if (context != null) {
                validatorConfigs.addAll(buildAliasValidatorConfigs(anInterface1, context, checkFile));
            }

            checked.add(anInterface1.getName());
        }

        validatorConfigs.addAll(buildClassValidatorConfigs(clazz, checkFile));

        if (context != null) {
            validatorConfigs.addAll(buildAliasValidatorConfigs(clazz, context, checkFile));
        }

        checked.add(clazz.getName());

        return validatorConfigs;
    }

这里用到了递归,首先看咱们的Class是不是接口,是的话就得到它继承的接口,然后再递归查找.

然后再看我们的Class是不是Object.class,如果不是,得到父类,然后再递归,直到Class 是Object.class,

从这里也可以看出来的是先从最顶层的接口开始得到validation配置,接口找完之后,再从顶层的Object 开始查找validation配置,接下来就是具体的开始找配置文件了.

buildClassValidatorConfigs逻辑主要在这个方法里面,我们看这行代码
 String fileName = aClass.getName().replace('.', '/') + VALIDATION_CONFIG_SUFFIX;
得到文件名,这样就可以得到PersonAction-validation.xml这个文件的路径了,
上面主要是按类名来得到配置文件,下面就是根据别名了,
如果context不是空的话,就调用buildAliasValidatorConfigs方法,里面有行代码,
String fileName = aClass.getName().replace('.', '/') + "-" + context.replace('/', '-') + VALIDATION_CONFIG_SUFFIX;

看到了吧,如果咱们的context是"nan",那么就可以得到PersonAction-nan-validation.xml文件了.

查找配置文件以及执行验证器,都是在com.opensymphony.xwork2.validator.AnnotationActionValidatorManager这个类里面完成的.

再补充一点,就是我们可以在action中定义validationMethodName和validationDoMethodName这样的方法来进行验证,但是只会被调用一个,比如你的action方法名为save,那么可以定义validationSave这个方法来进行验证操作.

这个方法将会在配置文件验证之后再进行验证.

好了,这次就写到这里了.文笔不好,表达也不清楚,还请见谅,希望能帮到大家.

抱歉!评论已关闭.