资讯专栏INFORMATION COLUMN

jfinal路由简单解析

cncoder / 3146人阅读

摘要:在中,通过对所有的类进行过滤。在这个类中,均以成员变量的形式存在。中放置的是和的键值对。在中主要是调用了方法。

在jfinal中,通过JFinalFilter对所有的类进行过滤。

以下是路由的调用关系(我在调用关系旁边做了标记,会贴出具体的代码和解释):

-1-
Config:
    Routes -2-
    Interceptors
    Handlers
-3-
public void init(){
    createJFinalConfig
    -4-
    init:
        initActionMapping:
            new ActionMapping 
            buildActionMapping -5-
        initHandler
            new ActionHandler 
            getHandler 
        initRender
}
-6-    
public void dofilter(){
    -7-
    handle:
        Action action = new actionMapping.getAction(target) -8-
        new ActionInvocation.invoke()
        render
}



-1-
Config是基本的配置。

在Config这个类中,Routes、Interceptors、Handlers均以成员变量的形式存在。

class Config {
    private static final Routes routes = new Routes(){public void config() {}};
    private static final Interceptors interceptors = new Interceptors();
    private static final Handlers handlers = new Handlers();
}

-2-
Routes
在Route中有两个Map:map和viewPathMap。
map中放置的是controllerKey和controllerClass的键值对。
viewPathMap中放置的是controllerKey和viewPath的键值对。

public abstract class Routes {    
    private final Map> map = new HashMap>();
    private final Map viewPathMap = new HashMap();
    public Routes add(String controllerKey, Class controllerClass, String viewPath) {
        if (controllerKey == null)
            throw new IllegalArgumentException("The controllerKey can not be null");
        // if (controllerKey.indexOf(".") != -1)
            // throw new IllegalArgumentException("The controllerKey can not contain dot character: "."");
        controllerKey = controllerKey.trim();
        if ("".equals(controllerKey))
            throw new IllegalArgumentException("The controllerKey can not be blank");
        if (controllerClass == null)
            throw new IllegalArgumentException("The controllerClass can not be null");
        if (!controllerKey.startsWith("/"))
            controllerKey = "/" + controllerKey;
        if (map.containsKey(controllerKey))
            throw new IllegalArgumentException("The controllerKey already exists: " + controllerKey);
        
        map.put(controllerKey, controllerClass);
        
        if (viewPath == null || "".equals(viewPath.trim()))    // view path is controllerKey by default
            viewPath = controllerKey;
        
        viewPath = viewPath.trim();
        if (!viewPath.startsWith("/"))                    // "/" added to prefix
            viewPath = "/" + viewPath;
        
        if (!viewPath.endsWith("/"))                    // "/" added to postfix
            viewPath = viewPath + "/";
        
        if (baseViewPath != null)                        // support baseViewPath
            viewPath = baseViewPath + viewPath;
        
        viewPathMap.put(controllerKey, viewPath);
        return this;
    }
}

-3-
JFinalFilter中的init方法

public void init(FilterConfig filterConfig) throws ServletException {
        createJFinalConfig(filterConfig.getInitParameter("configClass"));
        
        if (jfinal.init(jfinalConfig, filterConfig.getServletContext()) == false)
            throw new RuntimeException("JFinal init error!");
        
        handler = jfinal.getHandler();
        constants = Config.getConstants();
        encoding = constants.getEncoding();
        jfinalConfig.afterJFinalStart();
        
        String contextPath = filterConfig.getServletContext().getContextPath();
        contextPathLength = (contextPath == null || "/".equals(contextPath) ? 0 : contextPath.length());
    }

-4-
在JFinalFilter中调用了方法jfinal.init,进行初始化

boolean init(JFinalConfig jfinalConfig, ServletContext servletContext) {
        this.servletContext = servletContext;
        this.contextPath = servletContext.getContextPath();
        
        initPathUtil();
        
        Config.configJFinal(jfinalConfig);    // start plugin and init logger factory in this method
        constants = Config.getConstants();
        
        initActionMapping();
        initHandler();
        initRender();
        initOreillyCos();
        initTokenManager();
        
        return true;
    }

-5-
在initActionMapping中将Routes和Interceptors组织起来。其中,在initActionMapping中有一个重要的方法:buildActionMapping

    void buildActionMapping() {
        mapping.clear();
        Set excludedMethodName = buildExcludedMethodName();
        ActionInterceptorBuilder interceptorBuilder = new ActionInterceptorBuilder();
        Interceptor[] globalInters = interceptors.getGlobalActionInterceptor();
        interceptorBuilder.addToInterceptorsMap(globalInters);
        for (Entry> entry : routes.getEntrySet()) {
            Class controllerClass = entry.getValue();
            Interceptor[] controllerInters = interceptorBuilder.buildControllerInterceptors(controllerClass);
            
            boolean sonOfController = (controllerClass.getSuperclass() == Controller.class);
            Method[] methods = (sonOfController ? controllerClass.getDeclaredMethods() : controllerClass.getMethods());
            for (Method method : methods) {
                String methodName = method.getName();
                if (excludedMethodName.contains(methodName) || method.getParameterTypes().length != 0)
                    continue ;
                if (sonOfController && !Modifier.isPublic(method.getModifiers()))
                    continue ;
                
                Interceptor[] methodInters = interceptorBuilder.buildMethodInterceptors(method);
                Interceptor[] actionInters = interceptorBuilder.buildActionInterceptors(globalInters, controllerInters, methodInters, method);
                String controllerKey = entry.getKey();
                
                ActionKey ak = method.getAnnotation(ActionKey.class);
                String actionKey;
                if (ak != null) {
                    actionKey = ak.value().trim();
                    if ("".equals(actionKey))
                        throw new IllegalArgumentException(controllerClass.getName() + "." + methodName + "(): The argument of ActionKey can not be blank.");
                    
                    if (!actionKey.startsWith(SLASH))
                        actionKey = SLASH + actionKey;
                }
                else if (methodName.equals("index")) {
                    actionKey = controllerKey;
                }
                else {
                    actionKey = controllerKey.equals(SLASH) ? SLASH + methodName : controllerKey + SLASH + methodName;
                }
                
                Action action = new Action(controllerKey, actionKey, controllerClass, method, methodName, actionInters, routes.getViewPath(controllerKey));
                if (mapping.put(actionKey, action) != null)
                    throw new RuntimeException(buildMsg(actionKey, controllerClass, method));
            }
        }
        
        // support url = controllerKey + urlParas with "/" of controllerKey
        Action actoin = mapping.get("/");
        if (actoin != null)
            mapping.put("", actoin);
    }

-6-
JFinalFilter中的doFilter。在doFilter中主要是调用了handle方法。

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest)req;
        HttpServletResponse response = (HttpServletResponse)res;
        request.setCharacterEncoding(encoding);
        
        String target = request.getRequestURI();
        if (contextPathLength != 0)
            target = target.substring(contextPathLength);
        
        boolean[] isHandled = {false};
        try {
            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);
    }

-7-
handle方法

/**
     * handle
     * 1: Action action = actionMapping.getAction(target)
     * 2: new Invocation(...).invoke()
     * 3: render(...)
     */
    public final void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) {
        if (target.indexOf(".") != -1) {
            return ;
        }
        
        isHandled[0] = true;
        String[] urlPara = {null};
        //通过url得到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.init(request, response, urlPara[0]);
            
            if (devMode) {
                boolean isMultipartRequest = ActionReporter.reportCommonRequest(controller, action);
                //用获得的action进行调用处理请求!!!
                new Invocation(action, controller).invoke();
                if (isMultipartRequest) ActionReporter.reportMultipartRequest(controller, action);
            }
            else {
                new Invocation(action, controller).invoke();
            }
            
            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.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();
        }
    }

-8-
getAction方法:通过url得到action

    Action getAction(String url, String[] urlPara) {
        Action action = mapping.get(url);
        if (action != null) {
            return action;
        }
        
        // --------
        int i = url.lastIndexOf(SLASH);
        if (i != -1) {
            action = mapping.get(url.substring(0, i));
            urlPara[0] = url.substring(i + 1);
        }
        
        return action;
    }

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/65780.html

相关文章

  • jFinal路由解析源码分析

    摘要:只是暴露接口,配置信息最终保存在的静态类中。整个项目只有一个,作为静态类可以保证它是唯一的,而它的静态成员也是整个项目中唯一的。至此的路由解析模块就分析完了。 jFinal的路由解析是在JFinalFilter中做的,这个Filter也需要在web.xml中配置。JFinalFilter实现了javax.servlet.Filter接口,从这里也可以看出jFinal是基于Servlet...

    CatalpaFlat 评论0 收藏0
  • 快速上手JFinal

    摘要:是国产的框架,由五大部分组成。本文通过一个例子上手,旨在熟悉中各组件的用法。指的是表名,指的是主键数据库连接池使用的是,还支持。默认访问方法,这点类似于如果之前有基础,上手会非常快。映射在上使用了校验拦截器,使用了权限拦截器。 JFinal是国产的MVC框架,由 Handler、Interceptor、Controller、Render、Plugin 五大部分组成。本文通过一个例子上手...

    susheng 评论0 收藏0
  • 使用 jfinal + beetl + bootstrap 实现商城展示及管理系统

    摘要:使用在线商品展示系统使用使用导入项目安装依赖库启动项目打开开始使用吧配置如何开发项目可能会用到仅供参考持续开发端所有页面端所有页面微信分享后台商品管理系统后台管理使用模板简单效果如下欢迎提问 使用 jfinal+beetl 在线商品展示系统 showImg(https://segmentfault.com/img/remote/1460000009341465);showImg(htt...

    liuyix 评论0 收藏0
  • 使用 jfinal + beetl + bootstrap 实现商城展示及管理系统

    摘要:使用在线商品展示系统使用使用导入项目安装依赖库启动项目打开开始使用吧配置如何开发项目可能会用到仅供参考持续开发端所有页面端所有页面微信分享后台商品管理系统后台管理使用模板简单效果如下欢迎提问 使用 jfinal+beetl 在线商品展示系统 showImg(https://segmentfault.com/img/remote/1460000009341465);showImg(htt...

    weknow619 评论0 收藏0

发表评论

0条评论

cncoder

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<