Jfinal控制器源码解读

本文对Jfinal的控制器源码作如下分析。html

PS:控制器是全部请求跳转的基础,本文就Jfinal控制器的继承关系及初始化的方法作出解释说明。web

啰嗦下:全部的请求和响应都是都是经过web容器封装,咱们主要跟踪JFinal的Controller是如何被初始化、如何处理业务逻辑,后续须要研究容器的加载机制,进而晋升到高级甚至技术专家的程度。数组

源码分析总结:慢慢随着源码的深刻,渐渐的对源码不会那那么的反感,刚开始读必定要静下心来,一步一脚印,别人用好几年甚至几十年写的代码,对于一个初中级开发来讲,很难理解的其设计的核心,咱们只有一边又一边的反复读取,才能理解做者设计的思想,无形之中提升本身的代码水平和代码架构;总之,天道酬勤、锲而不舍。架构

  • JFinal中Controller的继承关系
    JFinal中自定义的控制器经过继承JFinal提供的Controller(抽象的)便可,该类中有四个重要成员变量须要咱们关注
    public abstract class Controller {
        //Web请求
        private HttpServletRequest request;
    //响应
    private HttpServletResponse response; //Url参数 private String urlPara;
    //Url参数数组
    private String[] urlParaArray; }

    PS:后续咱们重点跟踪request、response、urlPara是如何被初始化,咱们猜测:这些变量都是Jfinal框架自己从web容器中获取。

    留个疑问:自定义的Controller是 单例吗?app

  • 自定义Controller的写法
    如上所示,自定义的Controller经过继承抽象类Controller便可,实例代码以下
public class BlogController extends Controller {
    
    static BlogService service = new BlogService();
    
    public void index() {
        setAttr("blogPage", service.paginate(getParaToInt(0, 1), 10));
        render("blog.html");
    }
}

将Controller绑定给容器
经过JFinalConfig实现的ConfigRoute方式将自定义的Controller绑定给容器,供请求时候调用,以下框架

     /**
     * 配置路由
     */
    public void configRoute(Routes me) {
        me.add("/", IndexController.class, "/index");    // 第三个参数为该Controller的视图存放路径
        me.add("/blog", BlogController.class);            // 第三个参数省略时默认与第一个参数值相同,在此即为 "/blog"
    }

    PS:为什么不弄个注解,让JFinal自动扫描自定义的控制器呢?按照常规思想,实现注解,省略了配置代码多好源码分析

       若是不弄注解:我将全部的Controller可以统一管理,可以快速找到我自定义的控制器有哪些,鄙人猜想,这应该是做者不整个Controller上的注解的缘由吧,但我以为这样的注解仍是有必要的,毕竟每一个人的使用方法不同,框架自己应该要知足庞大客户群体的需求,该注解可自定添加,从新JFinal加载Controller的逻辑代码便可

编码

  • Web过滤器
    经过从新Servlet.Filter的过滤方法,获取请求的Request和Response和相关参数,交由用户自定义的控制去实现相关的逻辑。
    过滤器的代码以下
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
            //从过滤器中获取请求
    HttpServletRequest request
    = (HttpServletRequest)req;
    //从过滤器中获取响应 HttpServletResponse response
    = (HttpServletResponse)res;
    //设置请求的编码 request.setCharacterEncoding(encoding); //获取请求的URI String target
    = request.getRequestURI(); if (contextPathLength != 0) {
    //从URI中去除根目录 target
    = target.substring(contextPathLength); } boolean[] isHandled = {false}; try {
    //处理器这块须要重点关注,通过分析处理器的实现为: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); } } if (isHandled[0] == false) { chain.doFilter(request, response); } }

    接下里咱们分析ActionHandler中handle方法的逻辑

    url

        public final void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) {
            if (target.indexOf('.') != -1) {
                return ;
            }
            
            isHandled[0] = true;
            String[] urlPara = {null};
    //基于URI和参数获取请求的action Action action
    = actionMapping.getAction(target, urlPara); if (action == null) { if (log.isWarnEnabled()) { String qs = request.getQueryString();
    //Action为null的状况下,记录查询字符串的日志 log.warn(
    "404 Action Not Found: " + (qs == null ? target : target + "?" + qs)); } renderManager.getRenderFactory().getErrorRender(404).setContext(request, response).render(); return ; } try {
    //从Action中获取当前请求对应的Controller的对象,这个地方每次都是实例化一次,因此JFinal的Controller不是单例 Controller controller
    = action.getControllerClass().newInstance();
    //controller调用初始化方法,赋值请求、响应和url参数 controller.init(request, response, urlPara[
    0]); if (devMode) { if (ActionReporter.isReportAfterInvocation(request)) { new Invocation(action, controller).invoke(); ActionReporter.report(target, controller, action); } else { ActionReporter.report(target, controller, action); new Invocation(action, controller).invoke(); } } else {
    //反射调用,仔细跟
    new Invocation(action, controller).invoke(); } Render render = controller.getRender(); if (render instanceof ForwardActionRender) { String actionUrl = ((ForwardActionRender)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 = renderManager.getRenderFactory().getDefaultRender(action.getViewPath() + action.getMethodName()); } 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(); String msg = null; if (errorCode == 404) { msg = "404 Not Found: "; } else if (errorCode == 401) { msg = "401 Unauthorized: "; } else if (errorCode == 403) { msg = "403 Forbidden: "; } if (msg != null) { if (log.isWarnEnabled()) { String qs = request.getQueryString(); log.warn(msg + (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 (Exception e) { if (log.isErrorEnabled()) { String qs = request.getQueryString(); log.error(qs == null ? target : target + "?" + qs, e); } renderManager.getRenderFactory().getErrorRender(500).setContext(request, response, action.getViewPath()).render(); } }

    以上代码经过反射代理的方式调用了Controller中的方法,最终renderManager实现跳转,Render是Jfinal对应web响应的一个封装,这种设计思想在实际开发中颇有必要,简洁代码,使用方便,下文给出Render实现类spa

     

       PS:Render这块是对响应进行了封装,具体更多的东西还须要自行分析和总机。

            天道酬勤,努力每一天,也欢迎您的指正,共同进步,请联系:xieyang@e6yun.com/cnxieyang@163.com

相关文章
相关标签/搜索