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;
}
jfinal路由简单解析的更多相关文章
- ASP.NET路由模型解析
大家好,我又来吹牛逼了 ~-_-~ 转载请注明出处:来自吹牛逼之<ASP.NET路由模型解析> 背景:很多人知道Asp.Net中路由怎么用的,却不知道路由模型内部的运行原理,今天我就给大家 ...
- kubernetes源码解析---- apiserver路由构建解析(1)
kubernetes源码解析---- apiserver路由构建解析(1) apiserver作为k8s集群的唯一入口,内部主要实现了两个功能,一个是请求的路由和处理,简单说就是监听一个端口,把接收到 ...
- Python Flask框架路由简单实现
Python Flask框架路由的简单实现 也许你听说过Flask框架.也许你也使用过,也使用的非常好.但是当你在浏览器上输入一串路由地址,跳转至你所写的页面,在Flask中是怎样实现的,你是否感到好 ...
- kubernetes源码解析---- apiserver路由构建解析(2)
kubernetes源码解析---- apiserver路由构建解析(2) 上文主要对go-restful这个包进行了简单的介绍,下面我们通过阅读代码来理解apiserver路由的详细构建过程. (k ...
- 对 cloudwu 简单的 cstring 进行简单解析
题外话 以前也用C写过字符串,主要应用的领域是,大字符串,文件读取方面.写的很粗暴,用的凑合着.那时候看见云风前辈的一个开源的 cstring 串. 当时简单观摩了一下,觉得挺好的.也没细看.过了较长 ...
- 基于DOM的XSS注入漏洞简单解析
基于DOM的XSS注入漏洞简单解析http://automationqa.com/forum.php?mod=viewthread&tid=2956&fromuid=21
- 15.5 自学Zabbix之路15.5 Zabbix数据库表结构简单解析-其他 表
点击返回:自学Zabbix之路 自学Zabbix之路15.5 Zabbix数据库表结构简单解析-其他 表 1. Actions表 actions表记录了当触发器触发时,需要采用的动作. 2.Aler ...
- 深度优先搜索DFS和广度优先搜索BFS简单解析(新手向)
深度优先搜索DFS和广度优先搜索BFS简单解析 与树的遍历类似,图的遍历要求从某一点出发,每个点仅被访问一次,这个过程就是图的遍历.图的遍历常用的有深度优先搜索和广度优先搜索,这两者对于有向图和无向图 ...
- List<T>集合的Sort自定义排序用法简单解析
List<T>集合的Sort自定义排序用法简单解析: 如下:一系列无序数字,如果想要他们倒序排列,则使用如下代码: 那么如何理解这段代码呢? (x,y)表示相邻的两个对象,如果满足条件:x ...
随机推荐
- mvn exec用法,运行jar后台驻留进程
java工程如果打包成war,那依赖的jar包都会被包含进去. 不过如果开发java的后台驻留进程,那一般会打包成jar包的形式,要想在运行进程的时候找到所有的依赖包,基本有如下两种方式: 方式一: ...
- UVa12298 Super Poker II(母函数 + FFT)
题目 Source http://acm.hust.edu.cn/vjudge/problem/23590 Description I have a set of super poker cards, ...
- ViewState与Session
在asp时代, 大家都知道一个html控件的值,比如input 控件值,当我们把表单提交到服务器后, 页面再刷新回来的时候, input里面的数据已经被清空. 这是因为web的无状态性导致的, 服务端 ...
- java获取日期
/* * 获取昨天日期 方法一,这个方法好像有点慢 */Date dt = new Date(); Calendar cal = Calendar.getInstance();cal.add(Cale ...
- BZOJ4444 : [Scoi2015]国旗计划
首先将坐标离散化,因为区间互不包含,可以理解为对于每个起点输出最少需要多少个战士. 将环倍长,破环成链,设$f[i]$表示区间左端点不超过$i$时右端点的最大值,可以通过$O(n)$递推求出. 那么如 ...
- 【BZOJ1864】[Zjoi2006]三色二叉树 树形DP
1864: [Zjoi2006]三色二叉树 Description Input 仅有一行,不超过500000个字符,表示一个二叉树序列. Output 输出文件也只有一行,包含两个数,依次表示最多和最 ...
- 多表头固定demo--html Table
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- ACM 独木舟上的旅行
独木舟上的旅行 时间限制:3000 ms | 内存限制:65535 KB 难度:2 描述 进行一次独木舟的旅行活动,独木舟可以在港口租到,并且之间没有区别.一条独木舟最多只能乘坐两个人,且乘客 ...
- 【HDU】1536 S-Nim
http://acm.hdu.edu.cn/showproblem.php?pid=1536 题意:同nim...多堆多询问...单堆n<=10000,每次取的是给定集合的数= = #inclu ...
- URAL 1031. Railway Tickets(spfa)
题目链接 不知为何会在dp里呢...INF取小了,2Y. #include <cstring> #include <cstdio> #include <string> ...