Welcome 微信登录
编程资源 图片资源库 蚂蚁家优选 PDF转换器

首页 / 操作系统 / Linux / JFinal - Handler 处理流程

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/zzString 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 得到)。public final void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) {
   if (target.indexOf(".") != -1) {
       return ;
    }
   
    isHandled[0] = true;
    String[] urlPara= {null};
   
   // actionMapping 根据 target 得到对应的 action
    Action action = actionMapping.getAction(target, urlPara);
   
   if (action == null) {
       if (log.isWarnEnabled()) {
            String qs= request.getQueryString();
            log.warn("404 Action Not Found: " + (qs == null ? target : target + "?" + qs));
        }
        renderFactory.getErrorRender(404).setContext(request, response).render();
       return ;
    }
   
   try {
       // 由 action 得到对应的 Controller
        Controller controller = action.getControllerClass().newInstance();
       
       // Controller 初始化
        controller.init(request, response, urlPara[0]);
       
       if (devMode) {
           if (ActionReporter.isReportAfterInvocation(request)) {
               new Invocation(action, controller).invoke();
                ActionReporter.report(controller, action);
            }else {
                ActionReporter.report(controller, action);
               new Invocation(action, controller).invoke();
            }
        }
       else {
           // 调用 Controller 相应的处理方法
            new Invocation(action, controller).invoke();
        }
       
       // 获取对应的 Render,如果是一个 ActionRender,就再交给 handler 处理;如果 Render == null会按照默认Render处理;
        Render render = controller.getRender();
       if (render instanceof ActionRender) {
            String actionUrl= ((ActionRender)render).getActionUrl();
           if (target.equals(actionUrl))
               throw new RuntimeException("The forward action url is the same as before.");
           else
                handle(actionUrl, request, response, isHandled);
           return ;
        }
       
       if (render == null)
            render= renderFactory.getDefaultRender(action.getViewPath() + action.getMethodName());
       
       // 调用 Render 实现类讲数据写入页面
        render.setContext(request, response, action.getViewPath()).render();
    }
   catch (RenderException e) {
       if (log.isErrorEnabled()) {
            String qs= request.getQueryString();
            log.error(qs== null ? target : target + "?" + qs, e);
        }
    }
   catch (ActionException e) {
       int errorCode = e.getErrorCode();
       if (errorCode == 404 && log.isWarnEnabled()) {
            String qs= request.getQueryString();
            log.warn("404 Not Found: " + (qs == null ? target : target + "?" + qs));
        }
       else if (errorCode == 401 && log.isWarnEnabled()) {
            String qs= request.getQueryString();
            log.warn("401 Unauthorized: " + (qs == null ? target : target + "?" + qs));
        }
       else if (errorCode == 403 && log.isWarnEnabled()) {
            String qs= request.getQueryString();
            log.warn("403 Forbidden: " + (qs == null ? target : target + "?" + qs));
        }
       else if (log.isErrorEnabled()) {
            String qs= request.getQueryString();
            log.error(qs== null ? target : target + "?" + qs, e);
        }
        e.getErrorRender().setContext(request, response, action.getViewPath()).render();
    }
   catch (Throwable t) {
       if (log.isErrorEnabled()) {
            String qs= request.getQueryString();
            log.error(qs== null ? target : target + "?" + qs, t);
        }
        renderFactory.getErrorRender(500).setContext(request, response, action.getViewPath()).render();
    }
}View Cod下面看看拦截器链如何处理public class Invocation {
   
   private Action action;
   private static final Object[] NULL_ARGS = new Object[0];    // Prevent new Object[0] by jvm for paras of action invocation.
   
    boolean useInjectTarget;
   private Object target;
   private Method method;
   private Object[] args;
   private MethodProxy methodProxy;
   private Interceptor[] inters;
   private Object returnValue = null;
   
   private int index = 0;
   
   // InvocationWrapper need this constructor
    protected Invocation() {
       this.action = null;
    }
   
   public Invocation(Action action, Controller controller) {
       this.action = action;
       this.inters = action.getInterceptors();
       this.target = controller;
       this.args = NULL_ARGS;
    }
   
   public Invocation(Object target, Method method, Object[] args, MethodProxy methodProxy, Interceptor[] inters) {
       this.action = null;
       this.target = target;
       this.method = method;
       this.args = args;
       this.methodProxy = methodProxy;
       this.inters = inters;
    }
   
   public void invoke() {
       if (index < inters.length) {
            inters[index++].intercept(this);
        }
       else if (index++ == inters.length) {    // index++ ensure invoke action only one time
            try {
               // Invoke the action
                if (action != null) {
                    returnValue= action.getMethod().invoke(target, args);
                }
               // Invoke the method
                else {
                   // if (!Modifier.isAbstract(method.getModifiers()))
                       // returnValue = methodProxy.invokeSuper(target, args);
                    if (useInjectTarget)
                        returnValue= methodProxy.invoke(target, args);
                   else
                        returnValue= methodProxy.invokeSuper(target, args);
                }
            }
           catch (InvocationTargetException e) {
                Throwable t= e.getTargetException();
               throw t instanceof RuntimeException ? (RuntimeException)t : new RuntimeException(e);
            }
           catch (RuntimeException e) {
               throw e;
            }
           catch (Throwable t) {
               throw new RuntimeException(t);
            }
        }
    }
   
   // ... many sets and gets
}  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");}} 用到父类 Controller 的 render 方法,通过 renderFactory.getRender 得到 render 实例。 public abstract class Controller {   
   
   // ...
   // render below ---
    private static final RenderFactory renderFactory = RenderFactory.me();
   
   /**
   * Hold Render object when invoke renderXxx(...)
    */
    private Render render;
   
   public Render getRender() {
       return render;
    }
   
   /**
   * Render with any Render which extends Render
    */
    public void render(Render render) {
       this.render = render;
    }
   
   /**
   * Render with view use default type Render configured in JFinalConfig
    */
    public void render(String view) {
        render= renderFactory.getRender(view);
    }
   
   /**
   * Render with jsp view
    */
    public void renderJsp(String view) {
        render= renderFactory.getJspRender(view);
    }
   
   /**
   * Render with freemarker view
    */
    public void renderFreeMarker(String view) {
        render= renderFactory.getFreeMarkerRender(view);
    }
   
   /**
   * Render with velocity view
    */
    public void renderVelocity(String view) {
        render= renderFactory.getVelocityRender(view);
    }
   
   /**
   * Render with json
   * <p>
   * Example:<br>
   * renderJson("message", "Save successful");<br>
   * renderJson("users", users);<br>
    */
    public void renderJson(String key, Object value) {
        render= renderFactory.getJsonRender(key, value);
    }
   
   /**
   * Render with json
    */
    public void renderJson() {
        render= renderFactory.getJsonRender();
    }
   
   /**
   * Render with attributes set by setAttr(...) before.
   * <p>
   * Example: renderJson(new String[]{"blogList", "user"});
    */
    public void renderJson(String[] attrs) {
        render= renderFactory.getJsonRender(attrs);
    }
   
   /**
   * Render with json text.
   * <p>
   * Example: renderJson("{"message":"Please input password!"}");
    */
    public void renderJson(String jsonText) {
        render= renderFactory.getJsonRender(jsonText);
    }
   
   /**
   * Render json with object.
   * <p>
   * Example: renderJson(new User().set("name", "JFinal").set("age", 18));
    */
    public void renderJson(Object object) {
        render= object instanceof JsonRender ? (JsonRender)object : renderFactory.getJsonRender(object);
    }
   
   /**
   * Render with text. The contentType is: "text/plain".
    */
    public void renderText(String text) {
        render= renderFactory.getTextRender(text);
    }
   
   /**
   * Render with text and content type.
   * <p>
   * Example: renderText("&lt;user id="5888"&gt;James&lt;/user&gt;", "application/xml");
    */
    public void renderText(String text, String contentType) {
        render= renderFactory.getTextRender(text, contentType);
    }
   
   /**
   * Render with text and ContentType.
   * <p>
   * Example: renderText("&lt;html&gt;Hello James&lt;/html&gt;", ContentType.HTML);
    */
    public void renderText(String text, ContentType contentType) {
        render= renderFactory.getTextRender(text, contentType);
    }
   
   /**
   * Forward to an action
    */
    public void forwardAction(String actionUrl) {
        render= new ActionRender(actionUrl);
    }
   
   /**
   * Render with file
    */
    public void renderFile(String fileName) {
        render= renderFactory.getFileRender(fileName);
    }
   
   /**
   * Render with file
    */
    public void renderFile(File file) {
        render= renderFactory.getFileRender(file);
    }
   
   /**
   * Redirect to url
    */
    public void redirect(String url) {
        render= renderFactory.getRedirectRender(url);
    }
   
   /**
   * Redirect to url
    */
    public void redirect(String url, boolean withQueryString) {
        render= renderFactory.getRedirectRender(url, withQueryString);
    }
   
   /**
   * Render with view and status use default type Render configured in JFinalConfig
    */
    public void render(String view, int status) {
        render= renderFactory.getRender(view);
        response.setStatus(status);
    }
   
   /**
   * Render with url and 301 status
    */
    public void redirect301(String url) {
        render= renderFactory.getRedirect301Render(url);
    }
   
   /**
   * Render with url and 301 status
    */
    public void redirect301(String url, boolean withQueryString) {
        render= renderFactory.getRedirect301Render(url, withQueryString);
    }
   
   /**
   * Render with view and errorCode status
    */
    public void renderError(int errorCode, String view) {
       throw new ActionException(errorCode, renderFactory.getErrorRender(errorCode, view));
    }
   
   /**
   * Render with render and errorCode status
    */
    public void renderError(int errorCode, Render render) {
       throw new ActionException(errorCode, render);
    }
   
   /**
   * Render with view and errorCode status configured in JFinalConfig
    */
    public void renderError(int errorCode) {
       throw new ActionException(errorCode, renderFactory.getErrorRender(errorCode));
    }
   
   /**
   * Render nothing, no response to browser
    */
    public void renderNull() {
        render= renderFactory.getNullRender();
    }
   
   /**
   * Render with javascript text. The contentType is: "text/javascript".
    */
    public void renderJavascript(String javascriptText) {
        render= renderFactory.getJavascriptRender(javascriptText);
    }
   
   /**
   * Render with html text. The contentType is: "text/html".
    */
    public void renderHtml(String htmlText) {
        render= renderFactory.getHtmlRender(htmlText);
    }
   
   /**
   * Render with xml view using freemarker.
    */
    public void renderXml(String view) {
        render= renderFactory.getXmlRender(view);
    }
   
   public void renderCaptcha() {
        render= renderFactory.getCaptchaRender();
    }
} 根据 Controller 可以看出还能使用 renderJosn、renderText 等多种方法,这里一笔带过。就先写到这里吧~~----- End -----Jfinal学习之路---Controller使用 http://www.linuxidc.com/Linux/2014-07/104323.htmJFinal开发8个常见问题 http://www.linuxidc.com/Linux/2015-02/113421.htmJFinal的详细介绍:请点这里
JFinal的下载地址:请点这里本文永久更新链接地址:http://www.linuxidc.com/Linux/2016-09/135257.htm