JFinal源码走读_5_Validator校验源码分析

时间:2022-04-22 18:20:55

jfnal特性之Validator后端验证源码探究

所谓Vadidator是什么

public abstract class Validator implements Interceptor

Validator是个抽象类,定义了必备的验证方法,具体的validator只需继承该类即可拥有极简的验证方式,从上面的代码也可以看出,所谓Validator实质上就是一个拦截器

Validator如何使用

官方文档很清晰,不赘言

具体代码分析

以demo中的BlogValidator为切入口,分析validate方法中的validateRequiredString方法的具体行为

protected void validateRequiredString(String field, String errorKey, String errorMessage) {
        // 根据方法调用时传递进来的表单域名称,获取对应的值,至于controller是如何可以被获取到的,涉及到Validator作为拦截器的intercept方法
        String value = controller.getPara(field);
        // 简单的判空操作
        if (value == null || "".equals(value.trim()))
            // 添加验证失败标志,为request添加error信息
            addError(errorKey, errorMessage);
    }

validator内部定义了许多验证方法,但是实现思路上与上面并无二致。

Validator的intercept方法

有关于拦截器的intercept方法何时被调用,在运行时初探时已经分析过,下面只关注Validator的intercept方法具体做了些什么

final public void intercept(ActionInvocation invocation) {
        Validator validator = null;
        try {
            // 又见反射,jfinal中无处不有反射的使用,actionmapping时contorller的获取也是如此
            // 获取当前validator拦截器的实例
            validator = getClass().newInstance();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        // 初始化validator
        validator.controller = invocation.getController();
        validator.invocation = invocation;

        try {
            // 调用 开发者继承重写的validate方法,即上一步分析的内容
            validator.validate(validator.controller);
        } catch (ValidateException e) {/* should not be throw */
        } // short circuit validate need this

        if (validator.invalid)
            // 验证不通过,测调用开发者继承重写的handleError方法
            // handleError如何处理,延后分析
            validator.handleError(validator.controller);
        else
            // 通过,继续递归调用的下一步
            invocation.invoke();
    }

intercept方法肯定会被调用,而它的逻辑又必须如此写,所以作者将其以final修饰,不希望被开发者修改

#handleError分析
protected void handleError(Controller controller) {
        // 本质上就是在request中设置之前从客户端传递过来的model属性,如 blog.title、blog.content等
        controller.keepModel(Blog.class);

        // 根据请求的地址不同,返回不同的响应
        String actionKey = getActionKey();
        if (actionKey.equals("/blog/save"))
            controller.render("add.jsp");
        else if (actionKey.equals("/blog/update"))
            controller.render("edit.jsp");
    }

小结

validate使用起来很简单也很有效,不过占用了一个action级别的拦截器,而action级别的拦截器用@before注解只能注册一个,如果有多个拦截器需要配置到action级别上,该如何做?使用拦截器栈即可