JFinal的validator详解和防止表单重复提交

时间:2022-01-22 18:24:38

JFinal的架构中没有专门的Validator,它的validator就是Interceptor。完全可以把它当成一个普通的Interceptor使用。

例如在save方法上添加@Before({ Tx.class, SkuValidator.class }),表示它将执行Tx、SkuValidator中的public void intercept(Invocation inv) 方法,该方法是Interceptor的接口方法。Validator是抽象类,实现了Interceptor,定义了protected abstract void validate(Controller c);和protected abstract void handleError(Controller c);这两个方法就是我们继承Validator之后需要实现的方法。

Validator的intercept方法的实现如下,这是一个典型的模板方法模式的应用。

final public void intercept(Invocation invocation) {
Validator validator = null;
try {validator = getClass().newInstance();}
catch (Exception e) {throw new RuntimeException(e);}

validator.controller = invocation.getController();
validator.invocation = invocation;

try {validator.validate(validator.controller);
catch (ValidateException e) {/* should not be throw */}// short circuit validate need this

if (validator.invalid)
validator.handleError(validator.controller);

else
invocation.invoke();
}

Validator类是抽象类,不可能有自己的实例,validator = getClass().newInstance();这句话就可以实例化子类的一个实例,然后给validator的私有属性赋值,再调用其validate方法,这里利用了多态,在自己的validate方法中实现你的验证逻辑,这个方法的参数传入Controller,你就可以调用一切Controller的方法,比如获取参数等。如果验证有错,调用addError,该方法中首先设置invalid为true,然后将错误信息设置到controller中。最后如果设置了shortCircuit,将直接抛出异常,validator.validate方法如果检测到这个异常,然后什么也不做,以后的也就不验证了,所以短路验证只需要设置该shortcircuit为真即可。【通过异常巧妙地实现短路验证】。

protected void addError(String errorKey, String errorMessage) {
invalid = true;
controller.setAttr(errorKey, errorMessage);
if (shortCircuit) {
throw new ValidateException();
}
}

验证逻辑调用完事儿之后,判断invalid成员,如果为真,表示有错误,直接调用handleError,否则通过。handleError方法也需要你自己实现,可以跳转到某些页面或者返回原来的页面,当然在之前可以准备一个回显的数据,可以调用参数传进来的controller的一切方法。另外validator自己提供了一些校验的方法,例如validateRequired,validateRegex等。



// 校验表单是否重复提交,在保存的时候应用即可,其他代码完全不用修改
// 1.进入input页面之前调用controller.createToken
// 2.在input页面中加入隐藏域<input type="hidden" name="jfinal_token"  value="${jfinal_token!''}">
// 3.在保存的方法中应用这个拦截器



public class FormTokenValidator implements Interceptor{


    /**
     * @param inv
     * @see com.jfinal.aop.Interceptor#intercept(com.jfinal.aop.Invocation)
     */
    @Override
    public void intercept(Invocation inv){
        Controller controller = inv.getController();
        if(!controller.validateToken()){
            //其他事情
            controller.render("/common/error_page.html");
        } else{
            inv.invoke();
        }
    }


}