Struts2 自定义验证器
前言
其实早在四月底就在JR上发表了这篇文章,这次再次搬出来一是为了资料集中,二是做一些修改和更详细的描述.和以往一样入门和介绍就不说了,如何学习在上篇文章Struts2+JFreeChart上有介绍.
正题
1.工程目录结构图:
2.以下依次帖代码:
a). web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<filter>
<filter-name>struts2</filter-name>
<filter-class>
org.apache.struts2.dispatcher.FilterDispatcher
</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>ValidatorDate.jsp</welcome-file>
</welcome-file-list>
</web-app>
b). struts.xml<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<filter>
<filter-name>struts2</filter-name>
<filter-class>
org.apache.struts2.dispatcher.FilterDispatcher
</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>ValidatorDate.jsp</welcome-file>
</welcome-file-list>
</web-app>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<include file="struts-validation.xml" />
</struts>
c). struts.properties<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<include file="struts-validation.xml" />
</struts>
struts.ui.theme=simple
d). struts-validation.xml<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="validationExamples" extends="struts-default"
namespace="/validation">
<action name="ValidatorField"
class="com.tangjun.validator.ValidatorAction">
<!-- 这里input表示验证失败后指定跳转到什么地方去 -->
<result name="input" type="dispatcher">/ValidatorDate.jsp</result>
<result>/success.jsp</result>
</action>
</package>
</struts>
e). ValidatorAction-validation.xml"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="validationExamples" extends="struts-default"
namespace="/validation">
<action name="ValidatorField"
class="com.tangjun.validator.ValidatorAction">
<!-- 这里input表示验证失败后指定跳转到什么地方去 -->
<result name="input" type="dispatcher">/ValidatorDate.jsp</result>
<result>/success.jsp</result>
</action>
</package>
</struts>
<?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="regexYearField">
<field-validator type="mydate">
<param name="maxYear">2008</param>
<param name="minYear">1900</param>
<message>
<![CDATA[ 不是一个有效的年份! ]]>
</message>
</field-validator>
</field>
<field name="regexMonthField">
<field-validator type="mydate">
<message>
<![CDATA[ 不是一个有效的月份! ]]>
</message>
</field-validator>
</field>
<field name="regexDayField">
<field-validator type="mydate">
<!-- 是否使用正则表达式验证日期 -->
<param name="isRegex">false</param>
<!-- 使用自定义正则表达式验证日期 -->
<!--
<param name="expression"></param>
-->
<message>
<![CDATA[ 当前月份的天数不对! ]]>
</message>
</field-validator>
</field>
</validators>
说明:验证文件需要和Action在同一目录下, 验证文件命名规则:验证文件xxxx-validation.xml,这个xxxx就是你前面action的类名字,xxx-xxx-validation.xml第二个xxx表示是别名.<!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="regexYearField">
<field-validator type="mydate">
<param name="maxYear">2008</param>
<param name="minYear">1900</param>
<message>
<![CDATA[ 不是一个有效的年份! ]]>
</message>
</field-validator>
</field>
<field name="regexMonthField">
<field-validator type="mydate">
<message>
<![CDATA[ 不是一个有效的月份! ]]>
</message>
</field-validator>
</field>
<field name="regexDayField">
<field-validator type="mydate">
<!-- 是否使用正则表达式验证日期 -->
<param name="isRegex">false</param>
<!-- 使用自定义正则表达式验证日期 -->
<!--
<param name="expression"></param>
-->
<message>
<![CDATA[ 当前月份的天数不对! ]]>
</message>
</field-validator>
</field>
</validators>
f). validators.xml
<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="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="mydate" class="com.tangjun.validator.DateEx"/>
</validators>
说明:在源码com.opensymphony.xwork2.validator.ValidatorFactory中,在325行至330那一段代码可以看出,如果不能在根目录下找到validators.xml文件,验证框架将调用默认的验证设置,即com.opensymphony.xwork2.<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="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="mydate" class="com.tangjun.validator.DateEx"/>
</validators>
validator.validators目录下default.xml里面的配置信息.最后一个<validator name="mydate" class="com.tangjun.validator.DateEx"/>就是我添加的默认验证器类型.
g). ValidatorAction
package com.tangjun.validator;
import com.opensymphony.xwork2.ActionSupport;
/**
* 验证日期
*
* @author lzl
*
*/
public class ValidatorAction extends ActionSupport {
private static final long serialVersionUID = -4829381083003175423L;
private Integer regexYearField;
private Integer regexMonthField;
private Integer regexDayField;
public ValidatorAction()
{
regexYearField = null;
regexMonthField = null;
regexDayField = null;
}
@Override
public String execute() throws Exception {
return SUCCESS;
}
public Integer getRegexDayField() {
return regexDayField;
}
public void setRegexDayField(Integer regexDayField) {
this.regexDayField = regexDayField;
}
public Integer getRegexMonthField() {
return regexMonthField;
}
public void setRegexMonthField(Integer regexMonthField) {
this.regexMonthField = regexMonthField;
}
public Integer getRegexYearField() {
return regexYearField;
}
public void setRegexYearField(Integer regexYearField) {
this.regexYearField = regexYearField;
}
}
h). BeanUtils
import com.opensymphony.xwork2.ActionSupport;
/**
* 验证日期
*
* @author lzl
*
*/
public class ValidatorAction extends ActionSupport {
private static final long serialVersionUID = -4829381083003175423L;
private Integer regexYearField;
private Integer regexMonthField;
private Integer regexDayField;
public ValidatorAction()
{
regexYearField = null;
regexMonthField = null;
regexDayField = null;
}
@Override
public String execute() throws Exception {
return SUCCESS;
}
public Integer getRegexDayField() {
return regexDayField;
}
public void setRegexDayField(Integer regexDayField) {
this.regexDayField = regexDayField;
}
public Integer getRegexMonthField() {
return regexMonthField;
}
public void setRegexMonthField(Integer regexMonthField) {
this.regexMonthField = regexMonthField;
}
public Integer getRegexYearField() {
return regexYearField;
}
public void setRegexYearField(Integer regexYearField) {
this.regexYearField = regexYearField;
}
}
package com.tangjun.validator;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class BeanUtils {
/* 默认验证日期正则表达式 */
private static final String DateExpression = "(([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))-02-29)";
/**
* 验证日期合法性(通过抛出错误方式来验证)
* @param date
* @return
*/
public static boolean validatorDate(String date) {
// 注意这个地方"yyyy-MM-dd"如果设置成了yyyy-mm-dd的话验证将失灵
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
// 这个的功能是不让系统自动转换 不把1996-13-3 转换为1997-3-1
sdf.setLenient(false);
try {
sdf.parse(date);
return true;
} catch (ParseException e) {
return false;
}
}
/**
* 使用正则表达式判定日期
*
* @param str
* @param expression
* @return
*/
public static boolean regexValidatorDate(String str, String expression) {
// 使用正则表达式进行判定
if (expression == null || expression.trim().length() == 0)
expression = BeanUtils.DateExpression;
Pattern pattern;
// System.out.println(expression);
pattern = Pattern.compile(expression, 2);
Matcher matcher = pattern.matcher(str.trim());
if (!matcher.matches()) {
return false;
}
return true;
}
}
说明:验证日期的正则表达式就是在网上找的,可以替换成自己的.import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class BeanUtils {
/* 默认验证日期正则表达式 */
private static final String DateExpression = "(([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))-02-29)";
/**
* 验证日期合法性(通过抛出错误方式来验证)
* @param date
* @return
*/
public static boolean validatorDate(String date) {
// 注意这个地方"yyyy-MM-dd"如果设置成了yyyy-mm-dd的话验证将失灵
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
// 这个的功能是不让系统自动转换 不把1996-13-3 转换为1997-3-1
sdf.setLenient(false);
try {
sdf.parse(date);
return true;
} catch (ParseException e) {
return false;
}
}
/**
* 使用正则表达式判定日期
*
* @param str
* @param expression
* @return
*/
public static boolean regexValidatorDate(String str, String expression) {
// 使用正则表达式进行判定
if (expression == null || expression.trim().length() == 0)
expression = BeanUtils.DateExpression;
Pattern pattern;
// System.out.println(expression);
pattern = Pattern.compile(expression, 2);
Matcher matcher = pattern.matcher(str.trim());
if (!matcher.matches()) {
return false;
}
return true;
}
}
i). DateEx
package com.tangjun.validator;
import java.util.HashMap;
import com.opensymphony.xwork2.validator.ValidationException;
import com.opensymphony.xwork2.validator.validators.FieldValidatorSupport;
public class DateEx extends FieldValidatorSupport {
private static HashMap<String, Integer> map = new HashMap<String, Integer>();
/* 默认最大年限 */
private static final Integer MAX_YEAR = 2008;
/* 默认最小年限 */
private static final Integer MIN_YEAR = 1900;
/* 最大年限 */
private Integer maxYear;
/* 最小年限 */
private Integer minYear;
/* 验证日期的正则表达式 */
private String expression;
/* 是否使用正则表达式验证 */
private Boolean isRegex;
public DateEx() {
maxYear = null;
minYear = null;
expression = null;
isRegex = false;
}
public void validate(Object object) throws ValidationException {
// 获得字段的名字
String fieldName = getFieldName();
// 获得输入界面输入的值
String value = getFieldValue(fieldName, object).toString();
if (value == null || value.length() <= 0)
return;
if (fieldName.equals("regexYearField"))
validateYear(value, object);
else if (fieldName.equals("regexMonthField"))
validateMonth(value, object);
else if (fieldName.equals("regexDayField"))
validateDay(value, object);
}
/**
* 验证年份
*
* @param object
* @throws ValidationException
*/
private void validateYear(String value, Object object)
throws ValidationException {
/* 设置默认值 */
if (maxYear == null) {
maxYear = MAX_YEAR;
}
if (minYear == null) {
minYear = MIN_YEAR;
}
Integer temp = null;
try {
temp = Integer.valueOf(value);
} catch (NumberFormatException ex) {
addFieldErrorEx(getFieldName(), object);
return;
}
if (temp != null) {
if (temp >= minYear && temp <= maxYear)
map.put("year", temp);
else
addFieldErrorEx(getFieldName(), object);
}
}
/**
* 验证月份
*
* @param object
* @throws ValidationException
*/
private void validateMonth(String value, Object object)
throws ValidationException {
try {
Integer temp = Integer.valueOf(value);
if (temp != null) {
if (temp >= 1 && temp <= 12)
map.put("month", temp);
else
addFieldErrorEx(getFieldName(), object);
}
} catch (NumberFormatException ex) {
addFieldErrorEx(getFieldName(), object);
return;
}
}
/**
* 验证日期
*
* @param object
* @throws ValidationException
*/
private void validateDay(String value, Object object)
throws ValidationException {
try {
Integer temp = Integer.valueOf(value);
if (temp != null) {
Integer year = map.get("year");
Integer month = map.get("month");
//直接使用天数
if(year==null || month==null)
{
return;
}
// 是否使用正则表达式验证
if (!isRegex) {
if(!BeanUtils.validatorDate(year + "-" + month + "-" + temp))
addFieldErrorEx(getFieldName(), object);
} else {
String StrDay = temp < 10 ? "0" + temp.toString() : temp
.toString();
String StrMonth = month < 10 ? "0" + month.toString()
: month.toString();
//前面已经验证过了
//String StrYear = year < 100 ? year < 10 ? "200" + year: "19" + year : "1" + year;
String str = year + "-" + StrMonth + "-" + StrDay;
System.out.println("Date:" + str);
if (expression == null) {
if(!BeanUtils.regexValidatorDate(str, null))
addFieldErrorEx(getFieldName(), object);
} else {
if (expression.trim().length() > 0) {
if(BeanUtils.regexValidatorDate(str, expression))
addFieldErrorEx(getFieldName(), object);
}
}
}
map.clear();
}
} catch (NumberFormatException ex) {
addFieldErrorEx(getFieldName(), object);
return;
}
}
/**
* 控制是否只显示一条报错信息
*
* @param arg0
* @param arg1
*/
private void addFieldErrorEx(String arg0, Object arg1) {
//if (this.getValidatorContext().getFieldErrors().size() == 0)
addFieldError(arg0, arg1);
}
public Integer getMaxYear() {
return maxYear;
}
public void setMaxYear(Integer maxYear) {
this.maxYear = maxYear;
}
public Integer getMinYear() {
return minYear;
}
public void setMinYear(Integer minYear) {
this.minYear = minYear;
}
public String getExpression() {
return expression;
}
public void setExpression(String expression) {
this.expression = expression;
}
public Boolean getIsRegex() {
return isRegex;
}
public void setIsRegex(Boolean isRegex) {
this.isRegex = isRegex;
}
}
说明:在DateEx里面,这个时候你就可以参照如IntRangeFieldValidator(反编译源码)等他实现的验证器来写自己的验证器了。这里注意了,你在这个类里面每写一个属性(含get set方法),就对应的一个xxxx-validation.xml这个配置文件里面<param name="expression"></param>这个name的名字了,可以在扩展类里面直接获得了,根据传入参数进行自定义方式验证了。如下object是validate传进来的参数,表示你输入的数据对象:import java.util.HashMap;
import com.opensymphony.xwork2.validator.ValidationException;
import com.opensymphony.xwork2.validator.validators.FieldValidatorSupport;
public class DateEx extends FieldValidatorSupport {
private static HashMap<String, Integer> map = new HashMap<String, Integer>();
/* 默认最大年限 */
private static final Integer MAX_YEAR = 2008;
/* 默认最小年限 */
private static final Integer MIN_YEAR = 1900;
/* 最大年限 */
private Integer maxYear;
/* 最小年限 */
private Integer minYear;
/* 验证日期的正则表达式 */
private String expression;
/* 是否使用正则表达式验证 */
private Boolean isRegex;
public DateEx() {
maxYear = null;
minYear = null;
expression = null;
isRegex = false;
}
public void validate(Object object) throws ValidationException {
// 获得字段的名字
String fieldName = getFieldName();
// 获得输入界面输入的值
String value = getFieldValue(fieldName, object).toString();
if (value == null || value.length() <= 0)
return;
if (fieldName.equals("regexYearField"))
validateYear(value, object);
else if (fieldName.equals("regexMonthField"))
validateMonth(value, object);
else if (fieldName.equals("regexDayField"))
validateDay(value, object);
}
/**
* 验证年份
*
* @param object
* @throws ValidationException
*/
private void validateYear(String value, Object object)
throws ValidationException {
/* 设置默认值 */
if (maxYear == null) {
maxYear = MAX_YEAR;
}
if (minYear == null) {
minYear = MIN_YEAR;
}
Integer temp = null;
try {
temp = Integer.valueOf(value);
} catch (NumberFormatException ex) {
addFieldErrorEx(getFieldName(), object);
return;
}
if (temp != null) {
if (temp >= minYear && temp <= maxYear)
map.put("year", temp);
else
addFieldErrorEx(getFieldName(), object);
}
}
/**
* 验证月份
*
* @param object
* @throws ValidationException
*/
private void validateMonth(String value, Object object)
throws ValidationException {
try {
Integer temp = Integer.valueOf(value);
if (temp != null) {
if (temp >= 1 && temp <= 12)
map.put("month", temp);
else
addFieldErrorEx(getFieldName(), object);
}
} catch (NumberFormatException ex) {
addFieldErrorEx(getFieldName(), object);
return;
}
}
/**
* 验证日期
*
* @param object
* @throws ValidationException
*/
private void validateDay(String value, Object object)
throws ValidationException {
try {
Integer temp = Integer.valueOf(value);
if (temp != null) {
Integer year = map.get("year");
Integer month = map.get("month");
//直接使用天数
if(year==null || month==null)
{
return;
}
// 是否使用正则表达式验证
if (!isRegex) {
if(!BeanUtils.validatorDate(year + "-" + month + "-" + temp))
addFieldErrorEx(getFieldName(), object);
} else {
String StrDay = temp < 10 ? "0" + temp.toString() : temp
.toString();
String StrMonth = month < 10 ? "0" + month.toString()
: month.toString();
//前面已经验证过了
//String StrYear = year < 100 ? year < 10 ? "200" + year: "19" + year : "1" + year;
String str = year + "-" + StrMonth + "-" + StrDay;
System.out.println("Date:" + str);
if (expression == null) {
if(!BeanUtils.regexValidatorDate(str, null))
addFieldErrorEx(getFieldName(), object);
} else {
if (expression.trim().length() > 0) {
if(BeanUtils.regexValidatorDate(str, expression))
addFieldErrorEx(getFieldName(), object);
}
}
}
map.clear();
}
} catch (NumberFormatException ex) {
addFieldErrorEx(getFieldName(), object);
return;
}
}
/**
* 控制是否只显示一条报错信息
*
* @param arg0
* @param arg1
*/
private void addFieldErrorEx(String arg0, Object arg1) {
//if (this.getValidatorContext().getFieldErrors().size() == 0)
addFieldError(arg0, arg1);
}
public Integer getMaxYear() {
return maxYear;
}
public void setMaxYear(Integer maxYear) {
this.maxYear = maxYear;
}
public Integer getMinYear() {
return minYear;
}
public void setMinYear(Integer minYear) {
this.minYear = minYear;
}
public String getExpression() {
return expression;
}
public void setExpression(String expression) {
this.expression = expression;
}
public Boolean getIsRegex() {
return isRegex;
}
public void setIsRegex(Boolean isRegex) {
this.isRegex = isRegex;
}
}
// 获得字段的名字
String fieldName = getFieldName();
// 获得输入界面输入的值
String value = getFieldValue(fieldName, object).toString();
总结
验证器是拦截器即Interceptor实现的,所以并没有看见任何代码把他们和我的action文件关联起来,他们默认的验证了,这方面可以参考Max On Java的文章.