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/zz
String 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("<user id='5888'>James</user>", "application/xml");
*/
public void renderText(String text, String contentType) {
render = renderFactory.getTextRender(text, contentType);
}
/**
* Render with text and ContentType.
* <p>
* Example: renderText("<html>Hello James</html>", 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 等多种方法,这里一笔带过。
就先写到这里吧~~
JFinal - Handler 处理流程的更多相关文章
- Handler,Looper,MessageQueue流程梳理
目的:handle的出现主要是为了解决线程间通讯. 举个例子,android是不允许在主线程中访问网络,因为这样会阻塞主线程,影响性能,所以访问网络都是放在子线程中执行,对于网络返回的结果则需要显示在 ...
- Handler 机制(一)—— Handler的实现流程
由于Android采用的是单线程模式,开发者无法在子线程中更新 UI,所以系统给我提供了 Handler 这个类来实现 UI 更新问题.本贴主要说明 Handler 的工作流程. 1. Handler ...
- HDFS2.x之RPC流程分析
HDFS2.x之RPC流程分析 1 概述 Hadoop提供了一个统一的RPC机制来处理client-namenode, namenode-dataname,client-dataname之间的通信.R ...
- Jfinal 入门
Jfinal 入门 IDE----->IDEA 新建项目 新建web项目 添加maven特性 方便导入jar包,不用一个个导入了 配置pom.xml <dependencies> & ...
- jfinal拦截器301跳转
在jfinal的handle中加入 HandlerKit.redirect301("http://10.10.3.144:8080/bbb.rar", request, respo ...
- 面试:Handler 的工作原理是怎样的?
面试场景 平时开发用到其他线程吗?都是如何处理的? 基本都用 RxJava 的线程调度切换,嗯对,就是那个 observeOn 和 subscribeOn 可以直接处理,比如网络操作,RxJava 提 ...
- Android中消息系统模型和Handler Looper
http://www.cnblogs.com/bastard/archive/2012/06/08/2541944.html Android中消息系统模型和Handler Looper 作为Andro ...
- jfinal集成cas单点认证实践
本示例jfinal集成cas单点认证,采用获取到登录用户session信息后,在本地站点备份一份session信息,主要做以下几个步骤: 1.站点引入响应jar包: 2.在web.xml中配置对应过滤 ...
- 关于handler和异步任务
handler使用流程概要 首先在主线程新建一个handler实例,重写onhandlemessage(Message msg) 方法,对传过来的message进行处理 然后在子线程中完成操作,操作完 ...
随机推荐
- ASP.NET MVC EF 中使用异步控制器
最近悟出来一个道理,在这儿分享给大家:学历代表你的过去,能力代表你的现在,学习代表你的将来. 十年河东十年河西,莫欺少年穷 学无止境,精益求精 为什么使用异步操作/线程池 ASP.NET MVC ...
- 系统无法开始服务器进程。请检查用户名和密码。 (Exception from HRESULT: 0x8000401A)
开始-运行-cmd,输入aspnet_regiis.exe -i 重新注册iis 或者 出现以下错误:检索 COM 类工厂中 CLSID 为 {000209FF-0000-0000-C000-0000 ...
- url传参中文乱码
当使用url重定向传参的时候,比如: javascript:window.location.href='modifyBook.jsp?BName=<%=URLEncoder.encode(&qu ...
- web前端基础知识- Django基础
上面我们已经知道Python的WEB框架有Django.Tornado.Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了ORM.模型绑定.模板引擎.缓存.Sessi ...
- Life Cycle of Thread – Understanding Thread States in Java
Life Cycle of Thread – Understanding Thread States in Java 深入理解java线程生命周期. Understanding Life Cycle ...
- Windows Phone 十六、HttpClient
HttpClient 对象也可以实现网络请求 相对于 HttpWebRequest 对象来说,HttpClient 操作更简单,功能更强大 HttpClient 提供一系列比较简单的API来实现基本的 ...
- __PUBLIC__ 路径更改
config.php 'TMPL_PARSE_STRING' => array( '__PUBLIC__' => __ROOT__ . '/' . APP_NAME . '/Tpl/Pub ...
- 【转】python中的正斜杠、反斜杠
原文地址:http://www.cnblogs.com/followyourheart1990/p/4270566.html 首先,"/"左倾斜是正斜杠,"\" ...
- python生成器实现杨辉三角
def triangels(): """ 杨辉三角 """ lst = [1] n_count = 2 # 下一行列表长度 while Tr ...
- MongoDB - 在Windows上安装
1 下载MongoDB社区版, 下载链接 http://www.mongodb.org/downloads?_ga=1.129742796.1997610832.1481940266 2 安装Mong ...