JFinal 是基于 Java 语言的极速 WEB + ORM 框架。
JFinal在使用时会通过web.xml进行相应的配置,例如下面的例子:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<!-- jfinal配置 -->
<filter>
<filter-name>jfinal</filter-name>
<filter-class>com.jfinal.core.JFinalFilter</filter-class>
<init-param>
<param-name>configClass</param-name>
<param-value>com.jfinal.demo.Config</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>jfinal</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
其中configClass
参数的值com.jfinal.demo.Config
是项目定义的JFinalConfig
的实现类,其中会进行一些项目初始化的配置:
这里主要关注configRoute方法,例如如下的例子:
这里使用Routes.add()
方法,向Routes
添加了一个Controller
。通过这种方式用来配置 JFinal 访问路由,如下代码配置了将”/test”映射到TestController,当访问/test时候将访问到TestController的index()方法,访问/test/info时候将访问到TestController的info()方法:
这里也可以通过使用JFinal的拓展组件,同样也可以像Spring一样去配置路由,原理也是一样的:
大概知道JFinal的路由配置方法以后,看看其是怎么对请求进行解析的。
从上面的web.xml配置可以看到,其配置了一个过滤器com.jfinal.core.JFinalFilter
,对应的作用范围是/*
。也就是说这个Filter会拦截所有的请求。
JFinalFilter实现了javax.servlet.Filter接口,从这里也可以看出jFinal是基于Servlet实现的。JFinalFilter在项目初始化时对jFinal项目的配置(com.jfinal.core.Config)、路由表(Route)、映射表(ActionMapping)等进行配置,其中路由解析是在JFinalFilter的dofilter方法完成的。
以jfinal3.6版本为例,查看JFinalFilter的dofilter方法的具体实现,首先获取request,response,设置编码,然后通过request.getRequestURI方法获取当前请求路径,如果contextPathLength不等于0的话,通过subString截取除主机名之后的action请求:
isHandled作为一个标记位,表示是否需要doFilter这个请求。然后通过handler链进行处理:
handler在初始化的时候被赋值,查看JFinalFilter的init方法,主要是在Jfinal.init进行初始化:
在JFinal.init方法调用了initHandler进行初始化:
可以看到实际对应的是ActionHandler。也就是说实际调用的是ActionHandler.handle(target, request, response, isHandled)方法:
继续跟进ActionHandler.handle(target, request, response, isHandled)方法,首先调用target.indexOf('.')!=-1
进行判断,这里应该是为了过滤掉一些静态资源的请求,类似1.png、1.html等:
然后把isHandled标记改为true,表示要这个请求会被处理掉。然后调用actionMapping#getAction方法,根据用户的请求地址从actionMapping中获取相应的Action。
查看具体实现,根据用户的请求从map中获取Action(可以理解为是用于处理HTTP请求的)。这里是从mapping中获取的,mapping的初始化是在com.jfinal.core.ActionMapping
的buildActionMapping
方法,这里主要处理前面configRoute的配置,遍历Routes
所有Controller
、以及对应的method
,然后进行相应的封装:
继续看获取Action处理的逻辑,如果没有获取到Action,那么截取到最后一个/
之前的路径重新从map集合中获取Action,最后返回对应的Action:
拿到对应的Action后会继续找到对应的Controller以及相应的方法执行相应的逻辑:
以配合shiro进行鉴权为例:
shiro.ini的配置如下,对于/admin/下的一级路由,需要认证后才能访问:
#路径角色权限设置
[urls]
/login = anon
/doLogin = anon
/resources/** = anon
/logout = logout
/admin/* = authc
正常情况下,未授权直接访问/admin/page会返回302跳转到登陆接口:
根据前面的分析,在没有获取到Action的前提下,JFinal会截取到最后一个/
之前的路径重新从map集合中获取Action。也就是说/admin/page、/admin/page/、/admin/page/bypass请求到的Action是一致的。
对于结尾最后一个/
的问题,shiro在之前已经有修复过了,所以/admin/page/是无法绕过的,但是JFinal在处理的时候比较粗糙,使用/admin/page/bypass即可绕过shiro的鉴权处理:
64 篇文章
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!