struts2中使用xml进行validate验证

struts2提供了使用validate框架来实现输入校验,这种方式是基于XML的验证。

文件名为XXXAction-validation.xml

那么校验xml文件格式该如何写呢?

可以使用firefox查看此xml的DTD定义,地址为 http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd

在此列出此DTD的内容

<?xml version="1.0" encoding="UTF-8"?>
<!-- 
XWork Validators DTD. 
Used the following DOCTYPE. 
<!DOCTYPE validators PUBLIC 
"-//OpenSymphony Group//XWork Validator 1.0.2//EN" 
"http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd"> 
-->
<!ELEMENT validators (field|validator)+>
<!ELEMENT field (field-validator+)> 
<!ATTLIST field 
name CDATA #REQUIRED 
>
<!ELEMENT field-validator (param*, message)> 
<!ATTLIST field-validator 
type CDATA #REQUIRED 
short-circuit (true|false) "false" 
>
<!ELEMENT validator (param*, message)> 
<!ATTLIST validator 
type CDATA #REQUIRED 
short-circuit (true|false) "false" 
>
<!ELEMENT param (#PCDATA)> 
<!ATTLIST param 
name CDATA #REQUIRED 
>
<!ELEMENT message (#PCDATA)> 
<!ATTLIST message 
key CDATA #IMPLIED 
>

由此DTD的定义可知,此XML文件的根元素为validators。

在根元素下可以有若干个field或validator子元素,即分别代表着字段校验和非字段校验,它们的区别将在后面介绍。


字段校验

字段校验代表着field,标签有个name属性石必填的,它和表单中的name属性值是一样的。
这里我填入username。

<validators> 
<field name="username"> 
</field> 
</validators>
field下面有个子元素叫field-validator,代表着要用什么方式来进行校验,其有个属性叫 type,也是必填的。

<validators> 
<field name="username"> 
<field-validator type=""> 
</field-validator> 
</field> 
</validators>

type应该填入什么内容呢?

可以查看xwork的源文件,在包 com.opensymphony.xwork2.validator.validators下有个文件default.xml,在这个文件中定义了 type属性值。

<validator name="required" class="com.opensymphony.xwork2.validator.validators.RequiredFieldValidator"/>
<validator name="requiredstring" class="com.opensymphony.xwork2.validator.validators.RequiredStringValidator"/>

还有很多定义好的type值,这里不一一列举

在validator元素中,name属性表示可以定义的type值,class 表示用哪个类来进行校验,这是struts2默认设置好的校验器,我们可以直接使用。

在这个例子中,我们将type设置为requiredstring

<validators> 
<field name="username"> 
<field-validator type="requiredstring"> 
</field-validator> 
</field> 
</validators>

在field-validator下面有两个子元素,param和message
param可以任意个,可有可无,但是message有且只有一个。

param表示传入的参数,message表示出错时显示的信息。也就是说message可以是任意的字符串,但是param却是特定的。

在继续之前还是看看 com.opensymphony.xwork2.validator.validators.RequiredStringValidator这个类的源代码。首先确定已经下载了源代码,并且在MyEclipse中关联了源代码,这是一个好习惯。

在这个类中有一个成员变量

private boolean doTrim = true;

因此,我们在param中要做的就是,将param元素的name属性设置为doTrim,值为true。

<validators> 
<field name="username"> 
<field-validator type="requiredstring"> 
<param name="trim"<true>/param> 
<message<username should not be blank!</message> 
</field-validator> 
</field> 
</validators>
trim表示是否忽略空格,默认是true,因此在此也可以省略掉param元素。

其实在 field-validator元素中还有一个属性short-circuit,其默认值是false,表示的意思是短路,即前面验证失败,后面就不做验证了。

然而这仅仅只是一个校验条件,还是以 username为例,在上次的例子中,还要求username的长度要在6到10之间,因此,继续看default.xml文件

在其中找到这样一个元素 
<validator name="stringlength" class="com.opensymphony.xwork2.validator.validators.StringLengthFieldValidator"/>

从字面上可以看出是限制字符串长度的,因此查看这个实现类

它有3个成员变量:

private boolean doTrim = true; 
private int maxLength = -1; 
private int minLength = -1;

其中最主要的是maxLength和minLength分别代表最大长度和最小长度

因此在这个校验器中内容应该如下:

<field name="username"> 
<field-validator type="stringlength"> 
<param name="minLength">6</param> 
<param name="maxLength">10&lr;/param> 
<message>username should be between ${minLength} and ${maxLength}</message> 
</field-validator> 
</field>

有个问题就是 
<validator name="required" class="com.opensymphony.xwork2.validator.validators.RequiredFieldValidator"/>
<validator name="requiredstring" class="com.opensymphony.xwork2.validator.validators.RequiredStringValidator"/>

required和requiredstring有什么区别吗?

requiredstring是指这个字符串是必须的,而required表示这个字段是必须的,而没有指明这个字段是否必须是字符串。

因此对于字符串,可以使用requiredstring,而对于非字符串类型就必须使用required了。如在这个示例中的age,birthday。注意birthday是Date类型的,不是String。

还是回顾一下register2.jsp的页面内容。

body中的内容为: 
<s:actionerror /> 
<s:form action="register2" theme="simple"> 
…… 
…… 
</s:form> 
但是输入数据提交后,仍然显示的是以前的出错信息,并不是今天所设置的信息。

这就涉及到一些知识点了,因为校验框架产生的错误是fielderror,不会在actionerror中显示。

因此,需要将 theme="simple"去掉,并把那些表格标签页去掉,然后执行时会看到在username上方的错误信息。

还有一个问题就是validate校验框架和Action中validate方法是否冲突。

实际上虽然会使用框架验证,但是也会调用Action的validate方法,通过上面的显示结果应该可以清楚的看到,在表单上面集中的显示了actionerror。

但是如果把Action中的validate方法的出错信息add到field中会有什么效果呢??

修改RegisterAction中validate方法,将 addActionError改为addFieldError。

当没有输入用户名时,会显示如下错误信息:

username should not be blank! 
username invalid

为什么会显示这样的结果呢???

首先肯定的是在validate中增加的fielderror,和xml中不会冲突

即错误信息不会被覆盖,而是两者都有,而且先显示xml中定义的错误信息,然后才是validate中定义的错误信息。实际上是所有的xml执行完毕后,在执行validate。

为什么会产生这样的效果呢???那么你就必须知道fielderror到底是什么!继续查看源代码。

因为RegisterAction是继承的 ActionSupport,addFieldError是继承自ActionSupport,所以先看看ActionSupport中 addFieldError的实现方法。

在 ActionSupport中addFieldError是这么实现的,

public void addActionError(String anErrorMessage) {
validationAware.addActionError(anErrorMessage); 

即通过调用validationAware对象的addActionError,而validationAware是 ValidationAwareSupport的一个实例,在ValidationAwareSupport中定义了fielderror是什么。

private Map>String, List<String>> fieldErrors;
public synchronized void addFieldError(String fieldName, String errorMessage) { 
final Map<String, List<String>> errors = internalGetFieldErrors(); 
List<String> thisFieldErrors = errors.get(fieldName);
if (thisFieldErrors == null) { 
thisFieldErrors = new ArrayList<String>(); 
errors.put(fieldName, thisFieldErrors); 
}
thisFieldErrors.add(errorMessage); 
}

通过源代码,可以看到fieldErrors实际上是一个Map>String, List<String>>。key是String类型的,而value是List<String>

而实际上这个List是通过ArrayList<String>来实现的,也就是说,key是String类型的,而value是ArrayList<String>。

虽然一个key只能对应一个value,但是在这里value并不是一个字符串,而是一个数组。所以错误信息不会被覆盖掉。

在ActionSupport类中存在一个方法getFieldErrors,按照方法名可以猜的出该方法返回的是fieldError这个数组,既然如此那么是否可以通过 getFieldErrors直接添加呢??

List<String> list = new ArrayList<String>(); 
list.add("username should be between 6 and 10"); 
this.getFieldErrors().put("username",list);

虽然编译器没有报错,但是实际上是不行的。查看API文档:

getFieldErrors,其解释如下:

public Map<String,List<String>> getFieldErrors()

Description copied from interface: ValidationAware

Get the field specific errors associated with this action. Error messages should not be added directly here, as implementations are free to return a new Collection or an

Unmodifiable Collection.

注释:

这个方法返回与这个action相关的具体的fielderrors,错误信息不能直接从这里添加,执行结果返回一个新的集合或一个不可修改的集合

这是什么意思呢?看源代码,这个方法同样是在 ValidationAwareSupport中实现的。

public synchronized Map<String, List<String>> getFieldErrors() { 
return new LinkedHashMap<String, List<String>>(internalGetFieldErrors()); 
} 
由此可以看到该方法返回的是一个新的LinkedHashMap,只是一个拷贝,而不是原集合,所以这样直接添加是无法显示出来的。

那么何时使用validate验证框架,什么时候使用action中的 validate方法呢?

一般来说,简单验证可以使用 xml,复杂时用validate

前面讲到了 struts2的数据校验,那么为什么要有服务器校验??拥有了客户端校验不是也行吗??

服务端校验是必须的,即使有客户端校验。因为可以不通过browser访问web服务器!!强健的web应用要有客户端和服务器端的验证。

当然,struts2同样支持客户端验证。

要使用struts2的客户端校验,必须满足一下条件:

1.form的主题(theme)一定不能设置为simple

2.将struts2 form标签中validate属性设置为true

但是看到小时效果后就会发现,struts2生成的也是js代码,但是效果却很差,所以一般来说,使用struts2的服务器端校验,而客户端校验自己写。

struts2标签支持事件,可以像使用html标签一样使用。

同样用validate校验框架也应该可以使用局部校验:

当action中有多个方法时,需要在和action同目录下新建文件 XXXAction-XXX(方法名)-validation.xml

在实例化子类对象时,会先执行父类的全局校验,然后是局部校验,接着是子类的全局校验,然后是子类的局部校验,因此不要提供全局校验。

字段校验和非字段校验的区别

通俗点讲:

字段校验:校验谁,用什么方法

非字段校验:用什么校验,校验谁

非字段校验示例:

<validator type="requiredstring">
<param name="fieldName">username</param> 
<message></message> 
</validator>

其中tyoe="fieldName"是不变的。至于其他细节不在这里详细叙述。

但还是建议使用字段校验器。


下面用一个简单的实例演示下xml验证:

本例子实现简单的登陆输入验证:

在myeclipse10下,创建web project,添加struts2.1支持,引入必要的jar包,其中包含commons-validator-xxxx.jar提供validate支持。

首先创建JavaBean:Student.java,位于com.neuq.student包下:

package com.neuq.student;

public class Student {
	private Integer studentid;
	private String password;
	private Integer age;
	public Integer getStudentid() {
		return studentid;
	}
	public void setStudentid(Integer studentid) {
		this.studentid = studentid;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
}

之后创建Action:CheckAction.java,位于com.neuq.check包下:

package com.neuq.check;

import com.neuq.student.Student;
import com.opensymphony.xwork2.ActionSupport;

public class CheckAction extends ActionSupport{
	private Student student;

	public Student getStudent() {
		return student;
	}

	public void setStudent(Student student) {
		this.student = student;
	}

	public String execute() {
			return "toIndex2";
	}
}

之后,在该包(com.neuq.check)下,添加validate文件CheckAction-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="student.studentid">
        <field-validator type="requiredstring">
            <message>request studentid</message>
        </field-validator>
    </field>
    
    <field name="student.password">
        <field-validator type="requiredstring">
            <message>request password</message>
        </field-validator>
    </field>
    
    <field name="student.age">
        <field-validator type="required">
            <message>request age</message>
        </field-validator>
        <field-validator type="int">
            <param name="min">1</param>
            <param name="max">130</param>
            <message>should between ${min} and ${max}</message>
        </field-validator>
    </field>
</validators>

之后修改struts.xml如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
<package name="default" namespace="/" extends="struts-default">
		<action name="aCheck" class="com.neuq.check.CheckAction">
			<result name="toIndex2">/index2.jsp</result>
			<result name="input">/index.jsp</result>
		</action>
	</package>
</struts>    
最后实现前台jsp设计:

index.jsp:

<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<html>
<body>
	<s:form action="aCheck">
		<s:textfield name="student.studentid" label="studentid"></s:textfield>
		<s:password name="student.password" label="password"></s:password>
		<s:textfield name="student.age" label="age"></s:textfield>
		<s:submit></s:submit>
	</s:form>
</body>
</html>
index2.jsp:

<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<html>
<body>
	Validate Success!
</body>
</html>
在tomcat下部署运行,提交信息,会看到提示信息。

方法二:

在之前的基础上,修改CheckAction-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="student">
        <field-validator type="visitor">
            <param name="context">student</param>
            <param name="appendPrefix">true</param>
            <message key="appendPrefix">user''s </message>
        </field-validator>
    </field>
</validators>
student指定了action中变量的名字,visitor是固定写法,student是JavaBean所在包下validate文件名的中间部分。

在com.neuq.student包下创建Student的验证Student-student-validation.xml,命名方式为“class名+context参数指定的值+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="studentid">
        <field-validator type="requiredstring">
            <message>request studentid</message>
        </field-validator>
    </field>
    
    <field name="password">
        <field-validator type="requiredstring">
            <message>request password</message>
        </field-validator>
    </field>
    
    <field name="age">
        <field-validator type="required">
            <message>request age</message>
        </field-validator>
        <field-validator type="int">
            <param name="min">1</param>
            <param name="max">130</param>
            <message>should between ${min} and ${max}</message>
        </field-validator>
    </field>
</validators>
注意,studentid,password,age不需要加JavaBean前缀。
重新部署运行,成功!
总结:
第一种validation方式,把验证集中action的验证文件中。当验证的内容少或者不同的action验证的内容重复性小的时候适用。
第二种validation方式,把验证集中在bean的验证文件中。当多个action都需要对相同bean的内容进行验证时,比较方便。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值