Strut2验证可以通过一个XML配置文件和注解的方式来实现,当然手工验证(编码验证)也是支持的。同时也可以通过XML和注解共同使用的方式实现联合验证。
Struts2的验证是通过validation和workflow拦截器实现的,它们都属于default interceptor stack。validation拦截器用于验证并组织错误消息。workflow拦截器用于检测是否包含错误消息,假如有,它将返回结果为input所指向的页面,并将错误消息和原先输入的数据一同呈现给客户。
如果您的程序中使用了默认的验证(或者转换器)而没有提供为input的结果,则将出现错误。
//ActionSupport提供validate的方法 public void validate() { if(name == null || name.length() == 0){ //这个应该算是声明式配置 addFieldError("name",getText("error.name.empty")); //错误调用的也是input值 这是硬编码 //addFieldError("name","用户名不存在"); } }
验证方法执行完,控制权返回到工作流拦截器,该方法没有返回值,秘密就在于校验生成的错误消息.工作流拦截器会查看是否有错误消息生成,如果有的话,他会更改请求的工作流,终止请求处理并立即返回到用户的输入表单页面.在页面上会显示错误消息.
ValidationAware接口也定义了判断错误消息是否存在的方法,工作流拦截器会使用它们来决定是否需要重定向工作流到input页面,若有错误发生,拦截器会寻找input结果.
说到底就是在正常基础上多了ValidateAction-validation.xml这个文件。。
让我们一步一步做一个基础验证的示例
1. 步骤一:创建输入表单
create.jsp |
<body> <s:form action="helloValidation"> <s:textfield name="name" label="姓名"></s:textfield> <s:textfield name="age" label="年龄"></s:textfield> <s:textfield name="address" label="籍贯"></s:textfield> <s:submit value="提交"></s:submit> </s:form> </body> |
2. 步骤二:创建动作类
HelloAction.java |
package cn.wzhting;
import com.opensymphony.xwork2.ActionSupport;
public class HelloAction extends ActionSupport {
private static final long serialVersionUID = 117358005790515177L; private String name; private Integer age; private String address; public String getName() { return name; } public void setName(String name) { this.name = name; }
public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; }
} |
3. 步骤三:创建验证器。验证配置文件必须是以下两种形式之一
l <ActionClassName>-validation.xml
l <ActionClassName>-<ActionAliasName>-validation.xml
HelloAction-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="name"> <field-validator type="requiredstring"> <message>请输入姓名</message> </field-validator> </field> <field name="age"> <field-validator type="int"> <param name="min">13</param> <param name="max">19</param> <message>年龄为13~19周岁的才允许填写</message> </field-validator> </field> </validators> |
4. 步骤四:请确认你的struts.xml文件中该动作有input的结果。
struts.xml |
… <action name="helloValidation" class="cn.wzhting.HelloAction"> <result name="success">/createConfirm.jsp</result> <result name="error">/error.jsp</result> <result name="input">/create.jsp</result> </action> … |
假如你没有这样设置,你将会得到“No result defined for action *** and result input”的错误提示。
让我们一步一步做一个客户端验证的示例
l <s:form>标签的validate设置为true;
l 某些主题(themes)不支持客户端验证;
步骤一:创建输入表单
create.jsp |
<head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>Validation - Basic</title> <s:head/> </head> <body> <s:form action="helloValidation.action" validate="true"> <s:textfield name="name" label="姓名"></s:textfield> <s:textfield name="age" label="年龄"></s:textfield> <s:textfield name="address" label="籍贯"></s:textfield> <s:submit value="提交"></s:submit> </s:form> </body> |
注意:
l 虽然使用了<s:head/>标签,此处我们只是利用其默认样式。
l 虽然struts2中的动作带不带action后缀效果一样,但是在此处最好加上action后缀,不然会报错。
步骤二、三、四 同《基础验证 Basic Validation》一节,此处省略。
如果表单提交到的动作不在默认命名空间里,在使用<s:form>时必须指定其namespace属性。例如,helloValidation在命名空间/ns内,可能的struts.xml如下:
struts.xml |
… <package name="p1" extends="struts-default" namespace="/ns"> <action name="helloValidation" class="cn.wzhting.HelloAction"> <result name="success">/createConfirm.jsp</result> <result name="error">/error.jsp</result> <result name="input">/create.jsp</result> </action> </package> … |
输入表单如下:
create.jsp |
<head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>Validation - Basic</title> <s:head/> </head> <body> <s:form action="helloValidation.action" validate="true" namespace="/ns"> <s:textfield name="name" label="姓名"></s:textfield> <s:textfield name="age" label="年龄"></s:textfield> <s:textfield name="address" label="籍贯"></s:textfield> <s:submit value="提交"></s:submit> </s:form> </body> |
看上去应该能正常运行,客户端验证将不能。struts必须准确的知道动作所在的命名空间(不是通过URL),因此正确的写法如下:
create.jsp |
<head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>Validation - Basic</title> <s:head/> </head> <body> <s:form action="/ns/helloValidation.action" validate="true"> <s:textfield name="name" label="姓名"></s:textfield> <s:textfield name="age" label="年龄"></s:textfield> <s:textfield name="address" label="籍贯"></s:textfield> <s:submit value="提交"></s:submit> </s:form> </body> |
编写自定义的验证程序
l 实现特定的接口,常用的是继承已经实现相应接口的类,如com.opensymphony.xwork2.validator.validators.FieldValidatorSupport或com.opensymphony.xwork2.validator.validators.ValidatorSupport
l 注册该验证程序
验证的实现全是靠验证器(validators)完成的,这些验证器必须在ValidatorFactory(利用registerValidator方法)中进行注册。自定义的验证器可以通过一种很简单的方式注册进去,那就是在构建路径中(/WEB-INF/classes)中创建validators.xml文件,在该文件中声明你要注册的验证器。
以下列出了struts2框架中默认的验证器,自定义的验证器的定义语法可以参考以下内容。
com.opensymphony.xwork2.validator.validators.default.xml |
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator Config 1.0//EN" "http://www.opensymphony.com/xwork/xwork-validator-config-1.0.dtd">
<!-- START SNIPPET: validators-default --> <validators> <validator name="required" class="com.opensymphony.xwork2.validator.validators.RequiredFieldValidator"/> <validator name="requiredstring" class="com.opensymphony.xwork2.validator.validators.RequiredStringValidator"/> <validator name="int" class="com.opensymphony.xwork2.validator.validators.IntRangeFieldValidator"/> <validator name="long" class="com.opensymphony.xwork2.validator.validators.LongRangeFieldValidator"/> <validator name="short" class="com.opensymphony.xwork2.validator.validators.ShortRangeFieldValidator"/> <validator name="double" class="com.opensymphony.xwork2.validator.validators.DoubleRangeFieldValidator"/> <validator name="date" class="com.opensymphony.xwork2.validator.validators.DateRangeFieldValidator"/> <validator name="expression" class="com.opensymphony.xwork2.validator.validators.ExpressionValidator"/> <validator name="fieldexpression" class="com.opensymphony.xwork2.validator.validators.FieldExpressionValidator"/> <validator name="email" class="com.opensymphony.xwork2.validator.validators.EmailValidator"/> <validator name="url" class="com.opensymphony.xwork2.validator.validators.URLValidator"/> <validator name="visitor" class="com.opensymphony.xwork2.validator.validators.VisitorFieldValidator"/> <validator name="conversion" class="com.opensymphony.xwork2.validator.validators.ConversionErrorFieldValidator"/> <validator name="stringlength" class="com.opensymphony.xwork2.validator.validators.StringLengthFieldValidator"/> <validator name="regex" class="com.opensymphony.xwork2.validator.validators.RegexFieldValidator"/> <validator name="conditionalvisitor" class="com.opensymphony.xwork2.validator.validators.ConditionalVisitorFieldValidator"/> </validators> <!-- END SNIPPET: validators-default --> |
注意:
在struts2.0.7和之前的版本中,如果加入了自定义的验证器,你必须同时还得拥有一份默认验证器的拷贝,即在类路径中的validators.xml的验证器会覆盖掉默认的验证器。但之后的版本则避免了此问题。
用来检查密码强度的验证程序。规则:至少包含一个数字、一个小写字母和一个大写字母。此外该验证程序还可以接受一个minLength参数,用户可以通过设置该参数来设置一个可接受的口令的最小长度。
1、编写验证器
package wiva.struts2.train.validator; import com.opensymphony.xwork2.validator.ValidationException; import com.opensymphony.xwork2.validator.validators.FieldValidatorSupport; public class StrongPasswordValidator extends FieldValidatorSupport { private int minLength = -1; public int getMinLength() { return minLength; } public void setMinLength(int minLength) { this.minLength = minLength; } public void validate(Object object) throws ValidationException { String feildName = getFieldName(); String value = (String)getFieldValue(feildName, object); if(value == null||value.length()==0){ addFieldError(feildName, object); }else if((minLength>-1)&&(value.length()<minLength)){ addFieldError(feildName, object); }else if(!isPasswordStrong(value)){ addFieldError(feildName, object); } } private static final String GROUP1 = "abcdefghijklmnopqrstuvwxyz"; private static final String GROUP2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; private static final String GROUP3 = "0123456789"; protected boolean isPasswordStrong(String password) { boolean ok1 = false; boolean ok2 = false; boolean ok3 = false; int length = password.length(); for(int i=0;i<length;i++){ if(ok1&&ok2&&ok3) break; String character = password.substring(i,i+1); if(GROUP1.contains(character)){ ok1 = true; continue; } if(GROUP2.contains(character)){ ok2 = true; continue; } if(GROUP3.contains(character)){ ok3 = true; continue; } } return ok1&&ok2&&ok3; } }
2、注册验证器(WEB-INF/classes/validators.xml)
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator Config 1.0//EN" "http://www.opensymphony.com/xwork/xwork-validator-config-1.0.dtd"> <validators> <validator name="strongpassword" class="wiva.struts2.train.validator.StrongPasswordValidator"></validator> </validators>
3.使用(*Action-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="password"> <field-validator type="strongpassword"> <param name="minLength">6</param> <message>少包含一个数字、一个小写字母和一个大写字母且不能少于6个</message> </field-validator> </field> </validators>
之前所使用和编写的验证程序都是声明性的,先声明,后使用。在某些场合,可能因为验证规则过于复杂,用声明性验证会困难一些,因而需要为它们编写必要的验证代码,即需要进行“编程验证”。
Struts2提供了一个com.opensymphony.xwork2.Validateable接口,可以在自己的动作类内通过实现该接口以提供编程验证的功能。
package com.opensymphony.xwork2;
public interface Validateable {
void validate();
}
如果动作类实现了该接口,Struts会调用它的validate方法,所以应把用来验证用户输入的代码编写在这个方法内。ActionSupport实现了该接口,因此动作类继承ActionSupport就不需要直接实现该接口了。
用户注册程序。如果用户输入的用户名已经在数据库中存在了,则要求用户换另外一个用户名进行注册。
动作类
package wiva.struts2.train.action; import java.util.LinkedList; import java.util.List; import com.opensymphony.xwork2.ActionSupport; public class UserRegAction extends ActionSupport { /** * */ private static final long serialVersionUID = 2227569782574386186L; private String userName; private String password; private static List<String> userNames = new LinkedList<String>(); static{ //实际业务中,userNames中的内容应该从数据库中查询出来 userNames.add("admin"); userNames.add("wzhting"); } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public void validate() { if(userNames.contains(userName)) addFieldError("userName", "用户名"+userName+"已经存在"); } }
若针对某个动作方法单独进行验证,你需要编写一个方法public void validate方法名().方法名的第一个字母大写
<s:form action="addAction"> <s:textfield name="userName" label="用户名"></s:textfield> <s:submit value="添加"></s:submit> </s:form> <s:form action="editAction"> <s:textfield name="userName" label="用户名"></s:textfield> <s:submit value="修改"></s:submit> </s:form>
动作类
package wiva.struts2.train.action; import com.opensymphony.xwork2.ActionSupport; public class ValidateAction extends ActionSupport { private static final long serialVersionUID = -739143505400361615L; private String userName; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String add(){ return SUCCESS; } public String edit(){ return SUCCESS; } public void validateAdd() { if(userName==null||userName.length()==0) addFieldError("userName","请输入用户名"); } }