SECTION 01 Validator 总览
每个应用程序都有责任确保它们插入到后台资料库的数据是合法有效的,毕竟,如果这些应用程序所依赖的数据一旦遭到了破坏,那将是灾难性的,那应用程序还能拿什么来使自己正常运转呢?比如说,使用正规关系数据库的一个应用程序,数据库中的每个字段都有自己一定的规则和约束,来保证存储在其中的数据在一定程度上的正确性。任何要使用后台资料库数据的应用程序都有责任保护它们提交的数据的完整性。
任何试图插入或更新不符合标准的数据的操作都有可能被发现并拒绝。这种检测可能遍布在整个应用程序的每个角落,在表现层可能进行一些验证,在业务逻辑层,商业逻辑对象一般也有商业逻辑的验证,还有在后台资料库也要对数据进行检查。
不幸的是,由于这种验证在应用程序中无处不在,造成了应用程序在一定程度上的验证数据的代码冗余。这并不是应用程序所希望的,因为这种在多处的重复劳动,使得应用程序的部署和维护要花去更多的时间。如果在整个应用程序中,这些验证规则可以重复使用,将使得应用程序更加富有弹性,换句话说就是,部署更快捷,定制更容易,程序更灵活。
Jakarta Commons 项目Validator框架简介
Validator是由David Winterfeldt创建的开源项目,它也是Jakarta Commons的一个子项目。Commons项目主要是提供一些像Validator这样的一些可重用组件。其他著名的Commons组件还有如BeanUtils,Digester,Logging框架等。Validator 1.0版本发布于2002年11月初。
使用Validator的好处
.使用Validator框架比一般的在应用程序的代码中定义验证规则有好多优点,如:
.可以在一处为应用程序定义验证规则;
.验证规则和应用程序是松耦合的;
.服务器端和客户端的验证规则可以在同一处定义;
.配置新验证规则或修改已有验证规则变得更加简单;
.支持国际化;
.支持正则表达式;
.可以用于Web应用程序也可用于标准的Java应用程序;
.采用声明的方法实现而不是编程实现;
除了之外,Validator最大的特征就是自身支持可插性(pluggability)。在文章的后
面你将会看到使用Validator框架内置的验证规则来更好地完成你的工作,而更重要的是,Validator框架允许你自定义验证程序,并插入到框架中。
Struts和Validator的关系
应该指出的是Validator框架本身是因Struts框架而建立的。Validator的创建者David Winterfeldt在使用Struts的过程中发现,在许多ActionForm类中需要反复使用同一个验证规则,这样造成了大量的代码冗余。于是他决定创建Validator框架来消除这种冗余,这样Validator就诞生了。
尽管Validator架构最初是为Struts架构而生,但它还是被设计和构造成了可以独立于Struts架构而单独使用。这一个特征使得你可以在任何的应用程序中使用这个框架,不必管它是不是Struts架构的。并不会因为你不使用Struts框架而影响Validator架构对你的应用程序作用。事实上,这就是为什么Validator是Jakarta Commons项目的一部分而不直接是Struts项目的一部分。
现在,我们来将这个框架整合应用到像基于Struts构架这样的Web应用程序上。在文章的最后中我们再介绍如何把它应用到其他类型的应用程序中,如基于EJB的应用程序。
Validator组件概述
Validator架构有下面这些组件组成:
Validators;
配置文件;
资源绑定;
JSP自定义标签;
Validator Form类;
什么是Validators?
一个Validator就是,执行一个验证规则时Validator框架调用的一个Java类。框架根据配置文件中定义的方法签名来调用这个Validaotor类。一般情况下,每个Validator类提供一个单独的验证规则,然后这些规则可以组合成更复杂的规则集。
Validate 验证, 这件事情, 写程序是非常重要的, 要先判断数据是否正确, 才让动作或事件继续执行下去, 那么, 每次都写相同的验证模式, 不如对于这个 JavaBean 的数据验证透过 XML 的设定, 如果正确则为验证成功, 发生错误则为验证失败. 对于完全没有用过 Bean Validation 的人来说, 听起来, 可能有点吃力, 不过看过例子可能就了解了.
最新版本为 v1.0.2
binary 下载
source 下载
这次请下载 source 因为有许多范例程序在其中.
SECTION 02 基本范例
大家可以查看 org.apache.commons.validator.example.* 的文件, 其实很简单, 只有 ValidateExample.java 及 ValidateBean.java 这两个程序, 还有 validator-example.xml 来作为 Bean 的验证设定. 另外 applicationResources.properties 是设定多国语言 (i18n)
大家可以直接参阅 ValidateExample, 设定 Validator 的方法其实很简单
ValidatorResources resources = new ValidatorResources();
in = ValidateExample.class.getResourceAsStream("validator-example.xml");
ValidatorResourcesInitializer.initialize(resources, in);
ValidateBean bean = new ValidateBean();
Validator validator = new Validator(resources, "ValidateBean");
validator.addResource(Validator.BEAN_KEY, bean);
ValidatorResults results = null;
results = validator.validate();
在 global 的地方是告知, 各种情况需要用到那一个 Validator 来判断, 并且设定错误讯息, 将会参考 ApplicationResource.properties 的内容来显示, 而 form 的判断模式, 可以放入显示时候的名称, "errors.required=The {0} field is required." 如果发生验证失败, 将会把 nameForm.firstname.displayname ( 也就是写在 properties 中的 First Name ) 取代 {0} 的地方
public class TestValidator {
/**
* Checks if the field is required.
*
* @param value The value validation is being performed on.
* @return boolean If the field isn't null
and
* has a length greater than zero,
* true
is returned.
* Otherwise false
.
*/
public static boolean validateRequired(Object bean, Field field) {
String value = ValidatorUtil.getValueAsString(bean, field.getProperty());
return !GenericValidator.isBlankOrNull(value);
}
}
ValidatorPlugIn.java , 是一个实现 PlugIn ( "init()" & "destroy()" ) 的一个 Servlet
public class ValidatorPlugIn implements PlugIn {
public void init(ActionServlet servlet, ModuleConfig config)
throws ServletException {
......
initResources();
......
}
protected void initResources() throws IOException, ServletException {
......
ValidatorResourcesInitializer.initialize(resources, bis, false);
......
}
public void destroy() {
.....
}
}
而 ValidatorResourcesInitializer 就是属于 commons-validator 的组件,
另外的 /WEB-INF/validator-rules.xml, 包含了 client 端 javascirpt 的验证, 和 commons-validator 的验证.
最后的 /WEB-INF/validation.xml, 就是针对 FormBean 来作验证, 当然你可以自行用 commons-validator 对于 ValueObject 作验证.
SECTION 07 总结
如果不是要与 EIS ( DB layer ) 层级作处理的, 大家可以对于输入的资料通过 Validator 标准的模式, 撰写自己公司商业逻辑的 validator.下面我就举例说明
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.validator.Field;
import org.apache.commons.validator.GenericValidator;
import org.apache.commons.validator.ValidatorAction;
import org.apache.commons.validator.ValidatorUtil;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.validator.Resources;
import java.text.SimpleDateFormat;
import java.text.ParsePosition;
import java.util.Date;
import org.apache.commons.lang.StringUtils;
import org.apache.struts.validator.FieldChecks;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.Log;
/**
* ValidationUtil Helper class for performing custom validations that
* aren't already included in the core Struts Validator.
*
*
* View Source
*
private static final Log log = LogFactory.getLog(ValidationUtil.class);
//~ Methods ================================================================
/**
* Validates that two fields match.
* @param bean
* @param va
* @param field
* @param errors
* @param request
* @return boolean
*/
public static boolean validateTwoFields(
Object bean,
ValidatorAction va,
Field field,
ActionErrors errors,
HttpServletRequest request) {
String value =
ValidatorUtil.getValueAsString(bean, field.getProperty());
String sProperty2 = field.getVarValue("secondProperty");
String value2 = ValidatorUtil.getValueAsString(bean, sProperty2);
if (!GenericValidator.isBlankOrNull(value)) {
try {
if (!value.equals(value2)) {
errors.add(
field.getKey(),
Resources.getActionError(request, va, field));
return false;
}
} catch (Exception e) {
errors.add(
field.getKey(),
Resources.getActionError(request, va, field));
return false;
}
}
return true;
}
}
在你创建好检验功能后,你需要把他加到validation-rules.xml
"-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.0//EN"
"http://jakarta.apache.org/commons/dtds/validator_1_0.dtd">
method="validateTwoDateFields"
methodParams="java.lang.Object,
org.apache.commons.validator.ValidatorAction,
org.apache.commons.validator.Field,
org.apache.struts.action.ActionErrors,
javax.servlet.http.HttpServletRequest"
depends="date" msg = "errors.twodatefields">
var bValid = true;
var focusField = null;
var i = 0;
var fields = new Array();
oTwoDateFields = new twodatefields();
for (x in oTwoDateFields) {
var field = form[oTwoDateFields[x][0]];
var secondField = form[oTwoDateFields[x][2]("secondProperty")];
var datePattern = oTwoDateFields[x][2]("datePatternStrict");
var value;
var secondValue;
if (field.type == "select-one") {
var si = field.selectedIndex;
value = field.options[si].value;
secondValue = secondField.options[si].value;
} else {
value = field.value;
secondValue = secondField.value;
}
if ((field.type == 'text' ||
field.type == 'textarea' ||
field.type == 'select-one' ||
field.type == 'radio' ||
field.type == 'password') &&
(datePattern.length > 0) &&
(value.length > 0) &&
(secondValue.length > 0)) {
var MONTH = "MM";
var DAY = "dd";
var YEAR = "yyyy";
var orderMonth = datePattern.indexOf(MONTH);
var orderDay = datePattern.indexOf(DAY);
var orderYear = datePattern.indexOf(YEAR);
var fromdt = new Date();
var todt = new Date();
fromdt.setYear(value.substr(orderYear,4));
fromdt.setMonth(value.substr(orderMonth,2)-1);
fromdt.setDate(value.substr(orderDay,2));
todt.setYear(secondValue.substr(orderYear,4));
todt.setMonth(secondValue.substr(orderMonth,2)-1);
todt.setDate(secondValue.substr(orderDay,2));
if (todt < fromdt) {
if (i == 0) {
focusField = field;
}
fields[i++] = oTwoDateFields[x][1];
bValid = false;
}
}
}
if (fields.length > 0) {
focusField.focus();
alert(fields.join('/n'));
}
return bValid;
}]]>