概述

基于JFinal的web项目需要创建一个继承自JFinalConfig类的子类,该类用于对整个web项目进行配置。

JFinalConfig子类需要实现六个抽象方法,如下所示:

  1. public class DemoConfig extends JFinalConfig {
  2. public void configConstant(Constants me) {}
  3. public void configRoute(Routes me) {}
  4. public void configEngine(Engine me) {}
  5. public void configPlugin(Plugins me) {}
  6. public void configInterceptor(Interceptors me) {}
  7. public void configHandler(Handlers me) {}
  8. }

2.2 configConstant(..)

此方法用来配置JFinal常量值,如开发模式常量devMode的配置,如下代码配置了JFinal运行在开发模式:

  1. public void configConstant(Constants me) {
  2. me.setDevMode(true);
  3. }

在开发模式下,JFinal会对每次请求输出报告,如输出本次请求的URL、Controller、Method以及请求所携带的参数。

2.3 configRoute(..)

1、常用配置

此方法用来配置访问路由,如下代码配置了将 "/hello" 映射到HelloController这个控制器,通过以下的配置,http://localhost/hello  将访问 HelloController.index() 方法,而http://localhost/hello/methodName  将访问到 HelloController.methodName() 方法。

  1. public void configRoute(Routes me) {
  2. // 如果要将控制器超类中的 public 方法映射为 action 配置成 true,一般不用配置
  3. me.setMappingSuperClass(false);
  4. me.setBaseViewPath("/view");
  5. me.addInterceptor(new FrontInterceptor());
  6. me.add("/hello", HelloController.class);
  7. }

Routes.setBaseViewPath(baseViewPath) 方法用于为该 Routes 内部的所有 Controller 设置视图渲染时的基础路径,该基础路径与Routes.add(…, viewPath) 方法传入的viewPath以及 Controller.render(view) 方法传入的 view 参数联合组成最终的视图路径,规则如下:

finalView = baseViewPath + viewPath + view

注意:当view以 “/” 字符打头时表示绝对路径,baseViewPath 与 viewPath 将被忽略。

2、路由配置 API

Routes 类中添加路由的方法有两个:

  1. public Routes add(String controllerKey, Class<? extends Controller> controllerClass, String viewPath)
  2. public Routes add(String controllerKey, Class<? extends Controller> controllerClass)

第一个参数 controllerKey 是指访问某个 Controller 所需要的一个字符串,该字符串唯一对应一个 Controller,controllerKey仅能定位到Controller。

第二个参数 controllerClass 是该 controllerKey 所对应到的 Controller 。

第三个参数viewPath是指该Controller返回的视图的相对路径(该参数具体细节将在Controller相关章节中给出)。当viewPath未指定时默认值为controllerKey。

jfinal 3.6 新增了一个配置方法:setMappingSuperClass(boolean),默认值为 false。配置成为 true 时,你的 controller 的超类中的 public 方法也将会映射成 action。如果你的项目中使用了 jfinal weixin 项目的 MsgController,则需要将其配置成 true,因为 MsgController 中的 index() 需要被映射成 action 才能正常分发微信服务端的消息。

3、极简路由规则

JFinal 仅有四种路由,路由规则如下表:

从表中可以看出,JFinal访问一个确切的Action(Action定义见3.2节)需要使用controllerKey与method来精确定位,当method省略时默认值为index。

urlPara是为了能在url中携带参数值,urlPara可以在一次请求中同时携带多个值,JFinal默认使用减号“-”来分隔多个值(可通过constants. setUrlParaSeparator(String)设置分隔符),在Controller中可以通过getPara(int index)分别取出这些值。controllerKey、method、urlPara这三部分必须使用正斜杠“/”分隔。

注意,controllerKey自身也可以包含正斜杠“/”,如“/admin/article”,这样实质上实现了struts2的namespace功能。

JFinal在以上路由规则之外还提供了ActionKey注解,可以打破原有规则,以下是代码示例:

  1. public class UserController extends Controller {
  2. @ActionKey("/login")
  3. public void login() {
  4. render("login.html");
  5. }
  6. }

假定 UserController 的 controllerKey值为“/user”,在使用了@ActionKey(“/login”)注解以后,actionKey由原来的“/user/login”变为了“/login”。该注解还可以让actionKey中使用减号或数字等字符,如“/user/123-456”。

如果JFinal默认路由规则不能满足需求,开发者还可以根据需要使用Handler定制更加个性化的路由,大体思路就是在Handler中改变第一个参数String target的值。

4、路由拆分、模块化

JFinal路由还可以进行拆分配置,这对大规模团队开发十分有用,以下是代码示例:

  1. public class FrontRoutes extends Routes {
  2. public void config() {
  3. setBaseViewPath("/view/front");
  4. add("/", IndexController.class);
  5. add("/blog", BlogController.class);
  6. }
  7. }
  1. public class AdminRoutes extends Routes {
  2. public void config() {
  3. setBaseViewPath("/view/admin");
  4. addInterceptor(new AdminInterceptor());
  5. add("/admin", AdminController.class);
  6. add("/admin/user", UserController.class);
  7. }
  8. }
  1. public class MyJFinalConfig extends JFinalConfig {
  2. public void configRoute(Routes me) {
  3. me.add(new FrontRoutes());  // 前端路由
  4. me.add(new AdminRoutes());  // 后端路由
  5. }
  6. public void configConstant(Constants me) {}
  7. public void configEngine(Engine me) {}
  8. public void configPlugin(Plugins me) {}
  9. public void configInterceptor(Interceptors me) {}
  10. public void configHandler(Handlers me) {}
  11. }

如上三段代码,FrontRoutes类中配置了系统前端路由,AdminRoutes配置了系统后端路由,MyJFinalConfig.configRoute(…)方法将拆分后的这两个路由合并起来。使用这种拆分配置不仅可以让MyJFinalConfig文件更简洁,而且有利于大规模团队开发,避免多人同时修改MyJFinalConfig时的版本冲突。

FrontRoutes与AdminRoutes中分别使用setBaseViewPath(…)设置了各自Controller.render(view)时使用的baseViewPath。

AdminRoutes 还通过addInterceptor(new AdminInterceptor())添加了 Routes 级别的拦截器,该拦截器将拦截 AdminRoutes 中添加的所有 Controller,相当于业务层的inject拦截器,会在class拦截器之前被调用。这种用法可以避免在后台管理这样的模块中的所有class上使用@Before(AdminInterceptor.class),减少代码冗余。

2.4 configEngine(..)

此方法用来配置Template Engine,以下是代码示例:

  1. public void configEngine(Engine me) {
  2. me.addSharedFunction("/view/common/layout.html");
  3. me.addSharedFunction("/view/common/paginate.html");
  4. me.addSharedFunction("/view/admin/common/layout.html");
  5. }

上面的方法向模板引擎中添加了三个定义了 template function 的模板文件,更详细的介绍详见 Template Engine 那一章节的内容。

此方法用来配置JFinal的Plugin,如下代码配置了Druid数据库连接池插件与ActiveRecord数据库访问插件。通过以下的配置,可以在应用中使用ActiveRecord非常方便地操作数据库。

  1. public void configPlugin(Plugins me) {
  2. DruidPlugin dp = new DruidPlugin(jdbcUrl, userName, password);
  3. me.add(dp);
  4. ActiveRecordPlugin arp = new ActiveRecordPlugin(dp);
  5. arp.addMapping("user", User.class);
  6. me.add(arp);
  7. }

JFinal插件架构是其主要扩展方式之一,可以方便地创建插件并应用到项目中去。

2.6 configInterceptor(..)

此方法用来配置JFinal的全局拦截器,全局拦截器将拦截所有 action 请求,除非使用@Clear在Controller中清除,如下代码配置了名为AuthInterceptor的拦截器。

  1. public void configInterceptor(Interceptors me) {
  2. me.add(new AuthInterceptor());
  3. }

JFinal 的 Interceptor 非常类似于 Struts2,但使用起来更方便,Interceptor 配置粒度分为 Global、Inject、Class、Method四个层次,其中以上代码配置粒度为全局。Inject、Class与Method级的Interceptor配置将在后续章节中详细介绍。

2.7 configHandler(..)

此方法用来配置JFinal的Handler,如下代码配置了名为ResourceHandler的处理器,Handler可以接管所有web请求,并对应用拥有完全的控制权,可以很方便地实现更高层的功能性扩展。

  1. public void configHandler(Handlers me) {
  2. me.add(new ResourceHandler());
  3. }

具体用法可以参考 jfinal 源码中给出的几个功能的官方实现:https://gitee.com/jfinal/jfinal/tree/master/src/main/java/com/jfinal/ext/handler

注意:Handler 是全局共享的,所以要注意其中声明的属性的线程安全问题

2.8 onStart()、onStop() 回调配置

在 JFinalConfig 继承类中可以添加 onStart() 与 onStop(),JFinal 会在系统启动完成之后以及系统关闭之前分别回调这两个方法:

  1. // 系统启动完成后回调
  2. public void onStart() {
  3. }
  4. // 系统关闭之前回调
  5. public void onStop() {
  6. }

这两个方法可以很方便地在项目启动后与关闭前让开发者有机会进行额外操作,如在系统启动后创建调度线程或在系统关闭前写回缓存。

注意:jfinal 3.6 版本之前这两个方法名为:afterJFinalStart() 与 beforeJFinalStop()。为减少记忆成本、代码输入量以及输入手误的概率,jfinal 3.6 版本改为了目前更简短的方法名。老方法名仍然被保留,仍然可以使用,方便老项目升级到 jfinal 最新版本。

2.9 PropKit 读取配置

PropKit工具类用来读取外部键值对配置文件,PropKit可以极度方便地在系统任意时空使用,配置文件的格式如下:

  1. userName=james
  2. email=no-reply@jfinal.com
  3. devMode=true

如下是 PropKit 代码示例:

  1. PropKit.use("config.txt");
  2. String userName = PropKit.get("userName");
  3. String email = PropKit.get("email");
  4. // Prop 配合用法
  5. Prop p = PropKit.use("config.txt");
  6. Boolean devMode = p.getBoolean("devMode");

如下是在项目中具体的使用示例:

  1. public class AppConfig extends JFinalConfig {
  2. public void configConstant(Constants me) {
  3. // 第一次使用use加载的配置将成为主配置,可以通过PropKit.get(...)直接取值
  4. PropKit.use("a_little_config.txt");
  5. me.setDevMode(PropKit.getBoolean("devMode"));
  6. }
  7. public void configPlugin(Plugins me) {
  8. // 非第一次使用use加载的配置,需要通过每次使用use来指定配置文件名再来取值
  9. String redisHost = PropKit.use("redis_config.txt").get("host");
  10. int redisPort = PropKit.use("redis_config.txt").getInt("port");
  11. RedisPlugin rp = new RedisPlugin("myRedis", redisHost, redisPort);
  12. me.add(rp);
  13. // 非第一次使用 use加载的配置,也可以先得到一个Prop对象,再通过该对象来获取值
  14. Prop p = PropKit.use("db_config.txt");
  15. DruidPlugin dp = new DruidPlugin(p.get("jdbcUrl"), p.get("user")…);
  16. me.add(dp);
  17. }
  18. }

如上代码所示,PropKit可同时加载多个配置文件,第一个被加载的配置文件可以使用PorpKit.get(…)方法直接操作,非第一个被加载的配置文件则需要使用PropKit.use(…).get(…)来操作。

PropKit 的使用并不限于在 YourJFinalConfig 中,可以在项目的任何地方使用。此外PropKit.use(…)方法在加载配置文件内容以后会将数据缓存在内存之中,可以通过PropKit.useless(…)将缓存的内容进行清除。

JFinalConfig的更多相关文章

  1. JFinalConfig配置

    package com.sandu.common.config; import com.jfinal.config.Constants; import com.jfinal.config.Handle ...

  2. JFinal 3.3 学习 -- JFinalConfig (配置web项目)

    开篇  概述 基于JFinal的web项目需要创建一个继承自JFinalConfig类的子类,该类用于对整个web项目进行配置. JFinalConfig子类需要实现六个抽象方法,如下所示: publ ...

  3. JFinal学习

    1 jfinal-1.9-bin.jar 2 继承Controller编写控制器 public void sendJPushToXXX() { String userId = getPara(&quo ...

  4. JFinal - scheduler 插件做定时任务

    我在项目中遇到一个需求:服务运行期间,数据库要定期去监测某表并且更新. 正好项目是使用 jfinal 做的,于是就用了 jfinal-scheduler 插件来解决(jfinal-scheduler ...

  5. JFinal - Log 日志

    今天偶然发现 JFinal 的 Log 简单小巧.上代码. JFinal 在初始化的时候有初始化 Log. class Config { // ... static void configJFinal ...

  6. JFinal 国际化

    要支持国际化,需要在容器初始化的时候配置一个处理国际化的全局拦截器.比如可以使用 com.jfinal.i18n.I18nInterceptor 配置拦截器: public class MppConf ...

  7. JFinal - Handler 处理流程

    Handler 处理流程 doFilter - Handler 链中每个 handler.handle(...) 容器初始化时访问 web.xml 配置的 JFinalFilter.doFilter. ...

  8. JFinal 的初始化

    浅析初始化过程 首先要从 web 容器进行初始化 <?xml version="1.0" encoding="UTF-8"?> <web-ap ...

  9. 新建jfinal2.2项目并连接mysql

    一新建项目 1. new→Dynamic  Web Project 2修改Default Output Folder.一般用WebRoot\WEB-INF\class,然后下一步(注意路径要写对,不然 ...

随机推荐

  1. HDU 6003 Problem Buyer

    贪心题(好久不做了) 题解 考虑最一般的,判断合法性? 经典贪心问题:左端点升序,左端点相同,右端点降序,c[i]升序 优先队列,每次选择覆盖x的右端点最小的区间. 称此方法为“区间匹配贪心” 最小的 ...

  2. Ad Infinitum 8 - Math Programming Contest

    比赛链接 A题 如果当前数是1,那么后面无论是几都会加1或者当后面数是1的时候加2,所以记录一下后面的数中1的个数(加2)即可. 如果当前数是2,那么只有当后面的数为1或者为2时才可以加1,所以再记录 ...

  3. httpclient遇到java.net.URISyntaxException: Illegal character in scheme name at index 0:

    正准备按照大佬的解决办法处理, 看会一条回复,说url有空格 检查了一下,还真是有空格 去除url中的空格,问题解除

  4. 【DM642学习笔记九】XDS560仿真器 Can't Initialize Target CPU

    以前用的瑞泰的ICETEK-5100USB仿真器,现在换成XDS560试了试,速度快多了.把720*576的图片在imgae中显示也只需要四五秒钟.而5100仿真器需要三四分钟. 仿真器驱动安好后,刚 ...

  5. redis学习笔记06-主从复制和哨兵机制

    1.主从复制 为了保证线上业务的持续运行,防止主节点因宕机而重启数据恢复消耗太长时间,通常会准备一个备用节点,备份主节点的数据,当主节点出问题时立马顶上.这种机制就叫做主从复制.在了解redis的主从 ...

  6. 责任链模式(Chain of Responsibility、Handler)(请求处理建立链)

    (使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系.将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止.) 从名字中看出 ,系统中将会存在多个有类似处理能力的对 ...

  7. scikit-learn的基本使用

    在机器学习和数据挖掘的应用中,scikit-learn是一个功能强大的python包.在数据量不是过大的情况下,可以解决大部分问题.学习使用scikit-learn的过程中,我自己也在补充着机器学习和 ...

  8. 谷歌浏览器flash被禁用解决方法

    谷歌浏览器访问设置:chrome://settings/content/flash 把要启动flash插件的网址添加进去

  9. C#解析字符串公式

    /// <summary> /// 中缀表达式到逆波兰表达式的转换及求值 /// </summary> public class RpnExpression { #region ...

  10. LUOGU P3539 [POI2012]ROZ-Fibonacci Representation

    传送门 解题思路 打了个表发现每次x只会被比x大的第一个fab或比x小的第一个fab表示,就直接写了个爆搜骗分,结果过了.. 代码 #include<iostream> #include& ...