分享

JFinal

 hongjing_z 2017-10-09

Handler 处理流程

doFilter - Handler 链中每个 handler.handle(...)

 

容器初始化时访问 web.xml 配置的 JFinalFilter.doFilter。沿着 Handler 链,每个 handler 调用 handle 方法进行处理,然后交给下一个 handler。

复制代码
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
    
    // 获取 request、response,设置编码
    HttpServletRequest request = (HttpServletRequest)req;
    HttpServletResponse response = (HttpServletResponse)res;
    request.setCharacterEncoding(encoding);
    
    // 初始化的时候可以看出 contextPathLength 为 0 或者为 项目名称的长度
    // 比如 target = webapp/xx/yy/zz,则截取后的 target = /xx/yy/zz
    String target = request.getRequestURI();
    if (contextPathLength != 0)
        target = target.substring(contextPathLength);
    
    // 在调用了 ActionHandler的 handle 方法之后,isHandled[0] 才会被置为 true。
    boolean[] isHandled = {false};
    try {
        // 重头戏,handler 链首到链尾 ActionHandler 依次进行处理
        handler.handle(target, request, response, isHandled);
    }
    catch (Exception e) {
        if (log.isErrorEnabled()) {
            String qs = request.getQueryString();
            log.error(qs == null ? target : target + "?" + qs, e);
        }
    }
    
    // 若最后 isHandled[0] = false,会执行下一个 Filter。
    if (isHandled[0] == false)
        chain.doFilter(request, response);
}
复制代码

 

JFinal 初始化过程中可以 add JFinal 库中的Handler 或自定义的 Handler。

例如:ContextPathHandler,JFinal 自身扩展的 Handler。

访问项目时就会走过 handler 方法设置 contextPath。这样在前端就可以通过 ${CONTEXT_PATH} 得到项目根路径。

复制代码
public class ContextPathHandler extends Handler {
    
    private String contextPathName;
    
    public ContextPathHandler() {
        contextPathName = "CONTEXT_PATH";
    }
    
    public ContextPathHandler(String contextPathName) {
        if (StrKit.isBlank(contextPathName))
            throw new IllegalArgumentException("contextPathName can not be blank.");
        this.contextPathName = contextPathName;
    }
    
    public void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) {
        request.setAttribute(contextPathName, request.getContextPath());
        System.out.println("哈哈哈");
        next.handle(target, request, response, isHandled);
    }
}
复制代码

 

FakeStaticHandler,也是 JFinal 自身扩展的 Handler。new FakeStaticHandler 时可定义后缀,访问路径 target 必须是以这个后缀结尾才可以进行下去。

复制代码
public class FakeStaticHandler extends Handler {
    
    private String viewPostfix;
    
    public FakeStaticHandler() {
        viewPostfix = ".html";
    }
    
    public FakeStaticHandler(String viewPostfix) {
        if (StrKit.isBlank(viewPostfix))
            throw new IllegalArgumentException("viewPostfix can not be blank.");
        this.viewPostfix = viewPostfix;
    }
    
    public void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) {
        if ("/".equals(target)) {
            next.handle(target, request, response, isHandled);
            return;
        }
        
        if (target.indexOf('.') == -1) {
            HandlerKit.renderError404(request, response, isHandled);
            return ;
        }
        
        int index = target.lastIndexOf(viewPostfix);
        if (index != -1)
            target = target.substring(0, index);
        next.handle(target, request, response, isHandled);
    }
}
复制代码

 

到达 Handler 链尾 ActionHandler 处理

访问交给 Handler 链尾 ActionHandler,调用 handle 方法进行处理:根据访问路径 target 得到 Action,由 Action 得到 Controller。接着 new Invocation(action, controller).invoke() 进入责任链,反射机制调用 Controller 的方法处理(此方法可根据 Action 得到)。

View Cod

下面看看拦截器链如何处理

View Code

 

复制代码
public class AInterceptor implements Interceptor  {
    public void intercept(Invocation inv) {
        System.out.println("Before invoking ");
        inv.invoke();
        System.out.println("After invoking ");
    }
}

public class BInterceptor implements Interceptor  {
    public void intercept(Invocation inv) {
        System.out.println("Before invoking ");
        inv.invoke();
        System.out.println("After invoking ");
    }
}

public class BInterceptor implements Interceptor  {
    public void intercept(Invocation inv) {
        System.out.println("Before invoking ");
        inv.invoke();
        System.out.println("After invoking ");
    }
}
复制代码

 

new Invocation(action, controller).invoke(),由 action 得到拦截器数组,如果数组为空,就可以利用反射机制进入 Controller 的方法进行处理的了;

如果拦截器数组不为空,就会遇到拦截器1 的拦截 - inters[0].intercept(this),数组下标 +1,拦截器1 继续调用这个 Invocation 实例的 invoke() 方法,并且会在前后加上一些目的性操作;

若下标未越界,接着会遇到拦截器2 的拦截 - inters[1].intercept(this),数组下标 +1,拦截器2 继续调用这个 Invocation 实例的 invoke() 方法,并且会在前面加上一些目的性操作;

如此继续直到下标越界,接着反射机制进入  Controller 的方法进行处理。

 

render(...)

接着上面 ActionHandler.handle 继续,在 Controller 方法处理的最后,往往要调用 render 方法来实例化 render 变量。例如,我自定义的一个 IndexController,在最后一步调用 render("next.html")。

复制代码
public class IndexController extends Controller {
    public void index() {
        // ...
        render("next.html");
    }
}
复制代码

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多