RCP数据模型验证框架

Struts(for)RCP( http://struts4rcp.googlecode.com)发布了0.1版本,但还缺少一个重要元素,那就是数据模型验证框架,MVC框架总是少不了它。
验证框架需要实现哪些功能?
1. 对Action执行过程中的数据进行透明化检验,Action只需声明验证规则,而不参与验证过程。
2. 可以服务器端验证,也以可客户端验证,或者数据模型自验证。
3. 验证规则捆绑方便,可以使用注解,也可以使用XML配置,以及直接编码捆绑。
4. 验证规则可自定义,并且内置规则丰富。
5. 验证出错信息国际化。
现成的验证框架已经不少,像Struts, WebWork, Hibernate, JSF等都提供了验证框架,是否可以重用?
由于B/S开发的盛行,大多数已有验证框架都向B/S结构倾斜,虽然它们也能验证C/S结构应用。
而且验证框架众多,不易选择大众口味,所以还是由框架本身提供,然后适配到其它验证框架。
如果重新定义验证框架,它应该属于哪个包?
它并不是MVC控制器框架必需的,而且它需要在服务器端和客户端同时使用,
甚至给其它第三方包复用,所以,它应该放在util包内,与序列化器相似。
最后决定放在com.googlecode.struts4rcp.util.validator包下。
首先,需要定义验证器接口,它将作为验证框架的中心接口,如:
/**
 * 数据验证器
 */
public interface Validator {

	/**
	 * 验证数据
	 * @param model 数据模型
	 * @throws ValidationException 数据验证失败时抛出
	 */
	void validate(Object model) throws ValidationException;

}

基本的验证器实现如:
/**
 * 必需验证器
 */
public class RequiredValidator implements Validator {

	public void validate(Object model) throws ValidationException {
		if (model == null)
			throw new ValidationException();
		if (model instanceof String && ((String)model).trim().length() == 0)
			throw new ValidationException();
		if (model instanceof Collection && ((Collection<?>)model).size() == 0)
			throw new ValidationException();
		if (model instanceof Map && ((Map<?, ?>)model).size() == 0)
			throw new ValidationException();
	}

}

/**
 * 正则表达式验证器
 */
public class PatternValidator implements Validator {

	protected final String pattern;

	public PatternValidator(String pattern) {
		this.pattern = pattern;
	}

	public void validate(Object model) throws ValidationException {
		if (model == null)
			return;
		if (! (model instanceof String))
			return;
		String str = (String)model;
		str = str.trim();
		if (str.trim().length() == 0)
			return;
		if (! str.matches(pattern))
			throw new ValidationException();
	}

}

还有Length, Range, Email, URL, Phone, ZipCode, CreditCard, IdentificationCard等等。
以上都是原子级验证器的实现,可通过组合,链,委托等方式,进行更复杂的验证规则处理,如:
/**
 * 验证器链
 */
public class ValidatorChain implements Validator {

	private Collection<Validator> validators;

	public ValidatorChain(Validator... validators) {
		this.validators = Arrays.asList(validators);
	}

	public void validate(Object model) throws ValidationException {
		if (validators != null && validators.size() > 0) {
			for (Validator validator : validators) {
				validator.validate(model);
			}
		}
	}

}

/**
 * 字段验证器
 */
public class FieldValidator implements Validator {

	protected final String filedName;

	protected final Validator validator;

	public FieldValidator(String filedName, Validator validator) {
		this.filedName = filedName;
		this.validator = validator;
	}

	public void validate(Object model) throws ValidationException {
		if (model == null)
			validator.validate(null);
		else if (model instanceof Map)
			validator.validate(((Map)model).get(filedName));
		else
			validator.validate(BeanUtils.getProperty(model, filedName));
	}

}

等等。
不管验证规则多复杂,最终得到的都是一个Validator总接口。
这样,服务器端可通过拦载器,实现验证框架的集成:(此集成拦截器属于server包)
/**
 * 验证拦截器
 */
public class ValidationInterceptor implements ActionInterceptor {

	public Serializable intercept(Action<Serializable, Serializable> action,
			Serializable model) throws Exception {
		Action<Serializable, Serializable> srcAction = ActionContext.getContext().getAction();
		Validator validator = null;
		if (srcAction instanceof ValidationAction) { // Action自声明
			ValidationAction<Serializable, Serializable> validationAction = (ValidationAction<Serializable, Serializable>)srcAction;
			validator = validationAction.getValidator();
		} else {
			validator = ValidationManager.getValidator(srcAction); // 从配置读取
		}
		if (validator != null)
			validator.validate(model); // 验证
		return action.execute(model);
	}

}

然后,就是绑定规则,框架应支持多种绑定方式,以适应不同应用情况:
第一种方式,使用注解:
在Action上声明,表示只对指定Action请求进行验证,如:
public class LoginAction implements Action<Account, User> {

	@Required // 不带field属性,表示对整个model进行校验,这里表示传入model不能为null,如果需要对比多个字段时,也可能需要用到
	@Required(field="username")
	@Length(field="username", min=3, max=20)
	@Required(field="password")
	@Length(field="password", min=6, max=20)
	public User execute(Account account) throws Exception {
		// ......
	}
}

在数据模型上声明,表示对所有该类型的数据模型进行验证,如:
public class Account {
	
	@Required
	@Length(min=3, max=20)
	public String getUsername() {
		// ......
	}

	@Required
	@Length(min=6, max=20)
	public String getPassword() {
		// ......
	}
}

第二种方式,使用XML配置:
<validation>
	<!--定义验证器-->
	<validator name="required" class="com.googlecode.struts4rcp.util.validator.RequiredValidator" />
	<validator name="length" class="com.googlecode.struts4rcp.util.validator.LengthValidator" />
	<!--只对指定Action请求进行验证-->
	<action name="loginAction">
		<required /> <!--放在field外面,表示对整个model进行校验,这里表示传入model不能为null,如果需要对比多个字段时,也可能需要用到-->
		<field name="username">
			<required />
			<length min="3" max="20" />
		</field>
		<field name="password">
			<required />
			<length min="6" max="20" />
		</field>
	</action>
	<!--对所有该类型的数据模型进行验证-->
	<model class="com.xxx.demo.domain.Account">
		<field name="username">
			<required />
			<length min="3" max="20" />
		</field>
		<field name="password">
			<required />
			<length min="6" max="20" />
		</field>
	</model>
</validation>

第三种方式,直接编码构建规则:
public class LoginAction implements ValidationAction<Account, User> {

	public Validator getValidator() {
		return new ValidatorChain(
			new RequiredValidator(), // 传入model不能为null
			new FieldValidator("username", new ValidatorChain(
				new RequiredValidator(), // 用户名不能为空
				new LengthValidator(3, 20))), // 用户名长度限制
			new FieldValidator("password", new ValidatorChain(
				new RequiredValidator(), 
				new LengthValidator(6, 20))));
	}

	public User execute(Account account) throws Exception {
		// ......
	}

}

你可能感兴趣的:(数据结构,框架,应用服务器,struts,正则表达式)