Struts2.2 Validation
数据验证的方式:
客户端 js 验证;
服务器端:格式、业务逻辑验证;
Struts2 Validation 机制是 Struts2 的另一个特色:
1 、以拦截器的方式剥离验证逻辑;
2 、可配置的验证逻辑;
3 、客户端与服务器端统一验证;
4 、内置常用验证支持;
Struts2 验证模式:
1 、基于 Action 的验证,在 Action 中编写验证逻辑代码
2 、声明式验证,使用配置文件设定验证逻辑
3 、自定义验证,自己编写验证代码(如日期格式字符串);
4 、复合式验证,同时使用声明验证和 Action 验证
5 、 Ajax 验证,以 Ajax 方式触发上述验证方式,提高用户体验
这里我们将 1 、 2 、 3 、 5 各举一个例子。
基于 Action 的验证:
实现方法:
1 、重载 ActionSupport 的 validate 方法,此方法将被 validation 拦截器调用,这里可以使用 validateXXX 指定触发验证的方法名, XXX 表示 jsp 调用 Action 中的方法
2 、添加验证错误消息: addActionError(msg) 、 addFieldError ( field , msg )
workflow 拦截器将通过 hasErrors ()判断是否存在错误,如果存在验证错误则转到标识为 input 的 Result 页面,如果不存在错误则继续后续处理流程
register.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="s" uri="/struts-tags"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <title><s:text name="page.title" /> </title> <style type="text/css"> .errorMessage { color: red;//控制错误消息样式 } </style> </head> <body> <s:form action="register" namespace="/validation" sid="registerForm"> <s:textfield name="user.username" key="user.username" /> <s:password name="user.password" key="user.password" showPassword="true" /> <s:textfield name="user.mail" key="user.mail" /> <s:date name="user.birth" format="yyyy-MM-dd" var="birth" /> <s:textfield name="user.birth" key="user.birth" value="%{birth}" /> <s:submit value="%{getText('user.submit')}" /> </s:form> </body> </html>
说明: <s: fielderror /> 是将所有的错误提示都显示出来。
RegisterAction.java
package struts.demo.action;
import java.util.regex.Pattern;
import struts.demo.bean.User;
import com.opensymphony.xwork2.ActionSupport;
/**
* @author xudongwang 2011-5-20
*
*/
public class RegisterAction extends ActionSupport {
private User user;
getter和setter方法
public String entry_register() {
return SUCCESS;
}
public String execute() {
System.out.println("通过了验证");
return SUCCESS;
}
// 该方法是针对execute方法的,所以在调用execute方法之前调用
public void validateExecute() {
System.out.println("进入到方法验证了");
if(user==null){
return;
}
if (user.getUsername() == null || user.getUsername().isEmpty()) {
this.addFieldError("user.username",
getText("validate.user.username.required"));
return;
} else if (user.getUsername() == null || user.getUsername().isEmpty()) {
this.addFieldError("user.username",
getText("validate.user.username.required"));
return;
}
if (user.getPassword() == null || user.getPassword().isEmpty()) {
this.addFieldError("user.password",
getText("validate.user.password.required"));
} else if (user.getPassword().length() < 12
|| user.getPassword().length() > 32) {
this.addFieldError(
"user.password",
getText("validate.user.password.length", new String[] {
"12", "32" }));
}
String mailRegex = "\\b(^[_A-Za-z0-9-]+(\\.[_A-Za-z0-9-]+)*@([A-Za-z0-9-])+((\\.com)|(\\.net)|(\\.org)|(\\.info)|(\\.edu)|(\\.mil)|(\\.gov)|(\\.biz)|(\\.ws)|(\\.us)|(\\.tv)|(\\.cc)|(\\.aero)|(\\.arpa)|(\\.coop)|(\\.int)|(\\.jobs)|(\\.museum)|(\\.name)|(\\.pro)|(\\.travel)|(\\.nato)|(\\..{2,3})|(\\..{2,3}\\..{2,3}))$)\\b";
if (user.getMail() == null || user.getMail().isEmpty()) {
this.addFieldError("user.mail",
getText("validate.user.mail.required"));
} else if (!Pattern.matches(mailRegex, user.getMail())) {
this.addFieldError("user.mail",
getText("validate.user.mail.invalidate"));
}
}
}
注意:
1 、这里需要继承 ActionSupport
2 、 getText ( key )用于加载国际化资源,如果不需要,则直接使用 String
struts.xml :
<package name="validation" namespace="/validation" extends="struts-default"> <action name="register-form" class="struts.demo.action.RegisterAction" method="entry_register"> <result>/register.jsp</result> </action> <action name="register" class="struts.demo.action.RegisterAction"> <result>/welcome.jsp</result> <result name="input">/register.jsp</result> </action> </package>
说明:这里的 input 跟上面说的那样如果验证不通过,则进入 input 的 result 页面里
RegisterAction_en.properties :
page.title=User Register user.username=Username user.password=Password user.mail=Mail user.birth=Birth user.submit=Register validate.user.username.required=Username is required validate.user.username.length=Username length must between ${minLength} and ${maxLength} validate.user.username.exist=Username is existed validate.user.password.required=Password is required validate.user.password.length=Password length must between ${minLength} and ${maxLength} validate.user.mail.required=Mail is required validate.user.mail.invalidate=Email is invalidate validate.user.birth.range=Birth must between ${min} and ${max} RegisterAction_zh.properties: page.title=\u7528\u6237\u6CE8\u518C user.username=\u8D26\u53F7 user.password=\u5BC6\u7801 user.mail=\u90AE\u4EF6 user.birth=\u751F\u65E5 user.submit=\u6CE8\u518C validate.user.username.required=\u8BF7\u8F93\u5165\u8D26\u53F7 validate.user.username.length=\u8D26\u53F7\u957F\u5EA6\u5FC5\u987B\u5728${minLength}\u5230${maxLength}\u4F4D\u4E4B\u95F4 validate.user.username.exist=\u8D26\u53F7\u5DF2\u5B58\u5728 validate.user.password.required=\u8BF7\u8F93\u5165\u5BC6\u7801 validate.user.password.length=\u5BC6\u7801\u957F\u5EA6\u5FC5\u987B\u5728${minLength}\u5230${maxLength}\u4F4D\u4E4B\u95F4 validate.user.mail.required=\u8BF7\u8F93\u5165\u90AE\u4EF6 validate.user.mail.invalidate=\u8BF7\u8F93\u5165\u6B63\u786E\u7684\u90AE\u4EF6 validate.user.birth.range=\u51FA\u751F\u65E5\u671F\u5FC5\u987B\u5728${min}\u5230${max}\u4E4B\u95F4
RegisterAction_zh.properties :
page.title=\u7528\u6237\u6CE8\u518C user.username=\u8D26\u53F7 user.password=\u5BC6\u7801 user.mail=\u90AE\u4EF6 user.birth=\u751F\u65E5 user.submit=\u6CE8\u518C validate.user.username.required=\u8BF7\u8F93\u5165\u8D26\u53F7 validate.user.username.length=\u8D26\u53F7\u957F\u5EA6\u5FC5\u987B\u5728${minLength}\u5230${maxLength}\u4F4D\u4E4B\u95F4 validate.user.username.exist=\u8D26\u53F7\u5DF2\u5B58\u5728 validate.user.password.required=\u8BF7\u8F93\u5165\u5BC6\u7801 validate.user.password.length=\u5BC6\u7801\u957F\u5EA6\u5FC5\u987B\u5728${minLength}\u5230${maxLength}\u4F4D\u4E4B\u95F4 validate.user.mail.required=\u8BF7\u8F93\u5165\u90AE\u4EF6 validate.user.mail.invalidate=\u8BF7\u8F93\u5165\u6B63\u786E\u7684\u90AE\u4EF6 validate.user.birth.range=\u51FA\u751F\u65E5\u671F\u5FC5\u987B\u5728${min}\u5230${max}\u4E4B\u95F4
声明式验证:
声明式验证:以配置的的方式进行验证
验证规则文件:其命名规则
ActionClassName-validation.xml 或 ActionClassName-alias-validation.xml
RegisterAction-register-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="user.username"> <field-validator type="requiredstring"> <message key="validate.user.username.required" /> </field-validator> <field-validator type="stringlength"> <param name="minLength">6</param> <param name="maxLength">32</param> <message key="validate.user.username.length" /> </field-validator> </field> <field name="user.password"> <field-validator type="requiredstring"> <message key="validate.user.password.required" /> </field-validator> <field-validator type="stringlength"> <param name="minLength">12</param> <param name="maxLength">32</param> <message key="validate.user.password.length" /> </field-validator> </field> <field name="user.mail"> <field-validator type="requiredstring"> <message key="validate.user.mail.required" /> </field-validator> <field-validator type="email"> <message key="validate.user.mail.invalidate" /> </field-validator> </field> </validators>
验证规则文件说明:
field 中 name 字段名, Action 属性名称
field-validator 中 type 字段验证器类型
param ,验证器的参数, name 指定参数名,标签体内指定参数值
message ,验证消息, key 指定国际化消息,标签体内指定固有消息
validator
type ,针对 Action 的验证器类型
parame name
messge key
field-validator 与 validator 功能相似,可以根据喜好选择使用
struts.xml
<package name="validation" namespace="/validation" extends="struts-default"> <action name="register-form" class="struts.demo.action.RegisterAction" method="entry_register"> <result>/register.jsp</result> <result name="input">/register.jsp</result> </action> <action name="register" class="struts.demo.action.RegisterAction"> <result>/welcome.jsp</result> <result name="input">/register.jsp</result> </action> </package>
从上面可以看到有两个 action 中的 name 是映射到 RegisterAction 中的,所以验证文件的名称必须写成 RegisterAction-register-validation.xml ,这里的 register 就是对应 action 中的 name 的,而不能写成 RegisterAction-validation.xml ,如果写成后者,则这两个 action 都会进行验证
Action 验证中的 register.jsp 不变,并且将 RegisterAction 中 validateExecute 方法去除
Struts 内置的常用验证器:
验证器名称 |
说明 |
参数 |
required |
检查值不为 null |
|
requiredstring |
检查值不为 null 、 empty |
trim :字符串 trim ,默认为 true |
stringlength |
检查字符串长度范围 |
trim :字符串 trim ,默认为 true minLength: 最小长度, maxLength :最大长度 |
int |
检查 int 值大小范围 |
max :最大值, min :最小值 |
|
检查 email 是否有效 |
|
url |
检查 url 是否有效 |
|
regex |
检查值是否符合正则表达式 |
expression :正则表达式 caseSensitive :严格大小写, trim :字符串 trim |
fieldexpression |
使用 OGNL 表达式验证 |
expression : OGNL 表达式 |
visitor |
将具体验证映射给 Model |
|
conversion |
数据映射类型转换异常 |
|
expression |
功能类似 fieldexpression 仅用于 ActionError |
expression : OGNL 表达式 |
自定义验证器:
因为 Struts2 内置的验证器功能比较单一,所以可以自定义验证器
实现方法 :
1 、继承 FieldValidatorSupport 类
2 、实现其父接口 Validator 的 validate ( obj )方法
3 、在 src 下创建 validators.xml ,配置自定义验证器
4 、在 Action 中使用
例如实现日期有效范围的检查,在 Struts2 内置的 date 验证器仅支持 MM/dd/yyyy 格式
参数:
format :日期格式字符串,默认 yyyy-MM-dd
min :起始日期
max :截至日期
DateRangeValidator.java :
package struts.demo.validator;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import com.opensymphony.xwork2.validator.ValidationException;
import com.opensymphony.xwork2.validator.validators.FieldValidatorSupport;
public class DateRangeValidator extends FieldValidatorSupport {
private String format = "yyyy-MM-dd";
private String min;
private String max;
getter/setter
public void validate(Object object) throws ValidationException {
String fieldName = getFieldName();
Object fieldValue = getFieldValue(fieldName, object);
if (fieldValue == null) {
return;
}
if (format == null) {
throw new ValidationException("format parameter is required!");
}
SimpleDateFormat dateFmt = new SimpleDateFormat(format);
Date srcDate, minDate, maxDate = null;
try {
if (fieldValue instanceof Date) {
srcDate = (Date) fieldValue;
} else {
srcDate = dateFmt.parse((String) fieldValue);
}
} catch (ParseException e) {
throw new ValidationException(e.getMessage());
}
if (min == null && max == null) {
return;
}
if (min != null) {
try {
minDate = dateFmt.parse(min);
if (minDate.compareTo(srcDate) >= 0) {
addFieldError(fieldName, object);
}
} catch (ParseException e) {
throw new ValidationException(e.getMessage());
}
}
if (max != null) {
try {
maxDate = dateFmt.parse(max);
if (maxDate.compareTo(srcDate) <= 0) {
addFieldError(fieldName, object);
}
} catch (ParseException e) {
throw new ValidationException(e.getMessage());
}
}
}
}
src/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="daterange" class="struts.demo.validator.DateRangeValidator" /> </validators>
RegisterAction-register-validation.xml 添加:
<field name="user.birth"> <field-validator type="daterange"> <param name="format">yyyy-MM-dd</param> <param name="min">1980-01-01</param> <param name="max">2000-12-31</param> <message key="validate.user.birth.range" /> </field-validator> </field>
register.jsp :
<s:date name="user.birth" format="yyyy-MM-dd" var="birth" /> <s:textfield name="user.birth" key="user.birth" value="%{birth}" />
复合式验证:
Struts2 的验证顺序:
首先进行声明式验证:通过用于验证用户输入格式
然后进行 Action 验证:通常用于验证数据的业务有效性
Ajax 验证:
使用 Ajax 方式调用数据验证
服务端验证方式不变
以 ajax 调用服务器端进行数据验证
实现方法:
1 、为 Action 配置添加 jsonValidationWorkflowStack 拦截器
2 、为 form 添加 submit 事件
3 、在 submit 事件中使用 ajax 发送表单参数
4 、将验证错误显示在页面上
5 、无错误则提交表单
修改 RegisterAction 配置
应用 jsonValidationWorkflowStack 拦截器
<action name="register" class="struts.demo.action.RegisterAction"> <interceptor-ref name="jsonValidationWorkflowStack"></interceptor-ref> <result>/welcome.jsp</result> <result name="input">/register.jsp</result> </action>
修改 register.jsp
为 form 注册 submit 事件
添加类库
<script type="text/javascript" src="<s:url value='/struts/utils.js' />"></script> <script type="text/javascript" src="<s:url value='/struts/xhtml/validation.js' />"></script> <script type="text/javascript" src="<s:url value='/js/jquery-1.4.2.js' />"></script> $(document).ready( function() { $("#registerForm").submit( function() { validate(); return false; }); });
前两个是 Struts 内置 js 类库
ajax 请求,错误信息提示
function validate() { var url = '<s:url action="register" namespace="/validation"/>'; var params = $("#registerForm").serialize() + "&struts.enableJSONValidation=true&struts.validateOnly=true"; $.ajax( { url : '<s:url action="register" namespace="/validation"/>', data : params, cache : false, dataType : "text", success : function(text) { var form = $("#registerForm")[0]; StrutsUtils.clearValidationErrors(form); var errorsObject = StrutsUtils.getValidationErrors(text); if (errorsObject.fieldErrors) { StrutsUtils.showValidationErrors(form, errorsObject); } else { form.submit(); } } }); }
struts.enableJSONValidation=true&struts.validateOnly=true : jsonValidation 拦截器参数, struts.enableJSONValidation: 启用 json 验证, struts.validateOnly: 仅执行验证
var errorsObject = StrutsUtils.getValidationErrors(text) :解析表示错误信息的 json
StrutsUtils.showValidationErrors(form, errorsObject) :显示错误信息( xhtml theme )
jsonValidation 拦截器
验证错误的 json 格式
由 jsonValidation 拦截器自动生成;
推荐阅读
-
Java Validation Api如何实现自定义注解
-
Tinymce+jQuery.Validation使用产生的BUG
-
ASP.NET jQuery 实例12 通过使用jQuery validation插件简单实现用户注册页面验证功能_jquery
-
struts2.2以前版本远程执行任意代码漏洞修复方案
-
Spring Validation方法实现原理分析
-
Spring自带的校验框架Validation的使用实例
-
ASP.NET中Validation验证控件正则表达式特殊符号的说明
-
springMVC引入Validation的具体步骤详解
-
struts2 validation.xml 验证规则代码解析
-
ASP.NET中Validation验证控件正则表达式特殊符号的说明