jfinal路由简单解析

 

在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<String, Class<? extends Controller>> map = new HashMap<String, Class<? extends Controller>>();
    private final Map<String, String> viewPathMap = new HashMap<String, String>();
    public Routes add(String controllerKey, Class<? extends Controller> 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<String> excludedMethodName = buildExcludedMethodName();
        ActionInterceptorBuilder interceptorBuilder = new ActionInterceptorBuilder();
        Interceptor[] globalInters = interceptors.getGlobalActionInterceptor();
        interceptorBuilder.addToInterceptorsMap(globalInters);
        for (Entry<String, Class<? extends Controller>> entry : routes.getEntrySet()) {
            Class<? extends Controller> 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;
    }

posted on 2016-08-13 11:30  szllq2000  阅读(2708)  评论(0编辑  收藏  举报