jfinalOA信用盘网站开发源码研究之核心组件Handler

  1. 概述lOA信用盘网站开发haozbbs.com Q1446595067

JFinal 采用微内核全方位扩展架构,全方位是指其扩展方式在空间上的表现形式。JFinal由Handler、Interceptor、Controller、Render、Plugin五大部分组成。

而诚如标题所言,本文的关注中心将是jfinal中的核心组件Handler。

  1. 定义

现在先让我们来看看Handler的定义。首先,第一次看到这个类的时候我可以说是有点小意外,因为在我的预想里面,这个Handler应该是作为一个接口存在,但没想到jfinal直接将其定义为了一个抽象类。其实这也是有着相当的合理性的:现在的很多大型框架里,为了增加框架的适应性和可扩展性,往往一个功能的继承链都是从一个接口开始,然后依次是AbstractXxx,XxxImpl,XxxImplWrapper,XxxAdapter等等;这么一套下来,有的时候真的让人感觉蛋疼无比。诸如Spring里的不少接口,2002年就定义了,但直到如今也没见到第二个实现。那么这种设计的合理性就需要掂量一下了。

jfinal一直宣称的“功能强大,学习简单”在这里就能体现一二了,其直接简化了继承链体系,直接去掉了接口这一层的继承链,并且下方的继承链截图中我们可以看到,Handler的继承链只有两层,这就让理解起来轻松很多;读者可以对比下Spring的BeanFactory的继承链,或者对.NET有所涉猎的可以去看看WPF里控件的一字常长蛇阵般的继承体系。继承链可以增加框架的灵活性,但同时它也会大大增加使用者对于框架的理解难度。世间的万物有利必有弊!

/**

Handler从其定义上就清晰得表明其是一个链表结构。这一点上也非常契合过往的MVC框架里对web请求的处理方式。

Handler.handle作为该接口唯一的方法定义, 其子类可以使用如下两种方式来控制整体的请求处理逻辑扭转:

  1. 在handle的实现中通过主动调用next.handle来将请求处理逻辑交给下一个Handler
  2. 通过给方法的第四个参数赋值 isHandled[0] = true 来告知jfinal的核心Filter——JFinalFilter不要将请求处理逻辑交给之后的Filter了,本次请求的处理工作已经完毕了。
  3. 所以next.handle控制的是jfinal内部的逻辑跳转;而 isHandled[0] = true则是负责控制Servlet层面的逻辑跳转; 这里注意区分下影响范围, 虽然最终的表示形式可能一致。
  4. 继承链

只盯着一个抽象类,我们能得到的信息有限,接下来就让我们看看Handler在jfinal中的继承链体系。

Handler继承链

以上是jfinal3.4版本为止,提供所有内置Handler扩展,现在就让我们一个个得对其作一个简要的分析。
3.1 ContextPathHandler

这个类为view层的上下文提供了一个context path的键值对。
2, 通过配置该Handler, 你可以在View层的模板中通过${CONTEXT_PATH}来获取到本项目的request.getContextPath() 值。这样系统的灵活性就得到了加强。

3.2 DruidStatViewHandler

该Handler依然是jfinal提供的内置扩展,用来调度druid提供的监控功能。针对满足匹配条件的请求,该Handler会承接所有的请求处理逻辑。不会将逻辑向后传递给其他Handler或Filter。
我们可以从中得到启发,再有类似的功能需求可以直接借鉴其实现方式来做。

3.3 FakeStaticHandler

对于习惯了SpringMVC,struts2的请求路径的开发人员,可能一开始对jfinal中请求路径里没有后缀感到些许的不适应。此时我们就可以通过配置该Handler来模拟类似的效果。
默认的后缀是.html; 当然可以通过提供的构造函数参数来修改这一默认行为。

3.4 ServerNameRedirect301Handler

负责处理301重定向的Handler。该Handler会监控每一个请求, 对于满足条件的请求自动返回一个301的状态码,以及相应的最终URL地址。
注意到目前位置,其还没有提供通配符功能,所以如果有多个类似的需求,你需要配置多个该Handler。

3.5 UrlSkipHandler

该Handler的主要功能是依据配置的正则匹配符,筛选出不被JFinalFilter处理的请求,以交给JFinalFilter之后的其他Filter去处理。即该请求不属于JFinalFilter的处理范围。
3.6 ActionHandler

该Handler作为jfinal中当之无愧的核心Handler,已经在之前的文章jfinal源码研究之处理请求中进行了涉猎,这里就不再赘述。
3.7 自定义Handler

另外让我们来看看jcbase中对Handler的扩展,借此见识下Handler的实际的应用场景,以此有一个比较深入的了解。

// ------------------------------------- ResourceHandler
/**

  • 资源地址初始化
  • 这个类的功能和jfinal提供的ContextPathHandler比较类似,不过因为自定义的原因,所以更加灵活,读者可以根据自身需求自行取舍。
    */
    public class ResourceHandler extends Handler {

    @Override
    public void handle(String target, HttpServletRequest request,
    HttpServletResponse response, boolean[] isHandled) {
    // 统一设置basePath
    ServletContext context = request.getServletContext();
    if (context.getAttribute("res_url") == null) {
    context.setAttribute("static_url", PropKit.get("static_url"));
    String context_path=context.getContextPath().equals("/")?"":context.getContextPath();
    context.setAttribute("res_url", context_path+"/res/");
    context.setAttribute("context_path", context_path);
    }
    next.handle(target, request, response, isHandled);
    }

}

// ------------------------------------- SessionIdHandler
/**

  • 有时候session相关的id会是由url来承载,此时为了适配jfinal中的ActionHandler, 我们就需要截取掉这一部分
    */
    public class SessionIdHandler extends Handler {

    @Override
    public void handle(String target, HttpServletRequest request,
    HttpServletResponse response, boolean[] isHandled) {
    boolean isFromURL = request.isRequestedSessionIdFromURL();
    if (isFromURL) {
    target = target.substring(0, target.indexOf(';'));
    }
    next.handle(target, request, response, isHandled);
    }

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
  1. 总结

在大致探究了Handler的定义和继承链体系之后,接下来研究一些细节性内容。

Handler通过JFinalConfig.configHandler(Handlers me)来配置自定义的Handler。最后这些Handler会和jfinal默认添加的ActionHandler一起组织成链式结构(借助Handler中定义的next字段)。用户添加进参数Handlers中的顺序即为该链式结构的顺序,也是用户请求依次经过Handler的顺序。并且该链式结构的最后一个Item一定是ActionHandler——即用户请求正常情况下最终将被ActionHandler处理。关于该链式结构的细节可以查看源码HandlerFactory.getHandler。
Handler实现类中,由调用者自主决定是否将处理流程向后传递,框架不负责这方面的逻辑调度,将该权限全部下放给Handler。 所以除非明确清楚逻辑到此结束,否则在Handler.handle的实现中必须主动发起调用next.handle,来确保逻辑继续。若不主动调用next.handle 则代表请求不交给下一个Handler, Handler请求链条针对该请求的处理到此为止。
另外在Handler.handle的实现中,我们可以通过设置第四个方法参数isHandled[0] = true;来控制是否将请求发给其他Filter去处理,这里的isHandled[0] = true;代表本次请求由本Filter全权处理了,不需要交给接下来的Filter。
在经过一系列用户配置的前置Handler处理后,请求被最终传递到了ActionHandler,jfinal将在这里回调用户自定义的Action和配置的相关Interceptor。更多的细节我们将在Interceptor一章中论述,这里就不再讨论了。
所以Handler可以接管所有web请求,并对应用拥有完全的控制权,可以很方便地实现更高层的功能性扩展。
  1. Links

猜你喜欢

转载自blog.51cto.com/13871280/2143975