web框架之jfinal

web框架之jfinal

介绍

web框架除了现最流行的spring mvc,还有其他如jfinal,jersery等。现在学习jfinal的基础。
jfinal有相关的开发者社区,其中最有名是一个叫“波总”的人。 官方文档在https://www.jfinal.com/doc/2-4。
jfinal的优点:开发极简,秒速启动,拥有很多与spring类似的特性,内嵌undertow,jetty,上手快,学习成本低。
jfinal的缺点:文档不够丰富,案例不够完善,感觉功能配套不是很齐全。


Hello World

jfinal的最重要的类是JFinalConfig,基本所有的相关的配置都是在这个类上进行。
最简单的使用:

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package io.github.black.jfinal.demo;

import com.jfinal.config.*;
import com.jfinal.json.JacksonFactory;
import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
import com.jfinal.plugin.druid.DruidPlugin;
import com.jfinal.server.undertow.UndertowServer;
import com.jfinal.template.Engine;
import io.github.black.jfinal.demo.controller.HelloController;
import io.github.black.jfinal.demo.entity._MappingKit;
import io.github.black.jfinal.demo.handler.ResourcesHandler;

public class DemoConfig extends JFinalConfig {

public static void main(String[] args) {
UndertowServer.start(DemoConfig.class,8091,true);
}

@Override
public void configConstant(Constants constants) {
constants.setDevMode(true);
}

@Override
public void configRoute(Routes routes) {
routes.add("/hello", HelloController.class);
}

@Override
public void configEngine(Engine engine) {

}

@Override
public void configPlugin(Plugins plugins) {

}

@Override
public void configInterceptor(Interceptors interceptors) {

}

@Override
public void configHandler(Handlers handlers) {


}

@Override
public void onStart() {
}

@Override
public void onStop() {
}
}


1
2
3
4
5
6
7
8
public class HelloController extends Controller {

public void index(){
renderText("Hello JFinal World");
}


}

然后打开浏览器http://localhost:8091/hello

很有意思的一点,可以很方便返回一个二维码:
首先添加maven配置:

1
2
3
4
5
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>3.2.1</version>
</dependency>

demo如下:

1
2
3
4
5
6
7
public void qrCode(){
// 二维码携带的数据
String data = "dengdb.github.io";

// 渲染二维码图片,长度与宽度为 200 像素
renderQrCode(data, 200, 200);
}


参数注入以及拦截器

jfinal使用@Inject进行字段进行注入,只能是由jfinal管理的对象才行,如controller,Interceptor等。对于非jfinal组件,可以使用Aop.get(); 至于Aop.inject()没找到该怎么用。

1
2
3
4
5
6
7
8
9
10
11
12
public class LoginService {

private LoginDao loginDao = Aop.get(LoginDao.class);

}

在jfinalConfig中开启配置
public void configConstant(Constants constants) {
constants.setDevMode(true);
// 开启对 jfinal web 项目组件 Controller、Interceptor、Validator 的注入
constants.setInjectDependency(true);
}

经过测试,在不同的地方使用Aop.get()获取到的是同一个对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class LoginServiceT {

private LoginDao loginDao = Aop.get(LoginDao.class);

public String loginT(){
System.out.println(loginDao);
return loginDao.save();
}
}

public class LoginService {

private LoginDao loginDao = Aop.get(LoginDao.class);

public String login(){
System.out.println(loginDao);
return loginDao.save();
}
}

查看控制台打印日志,两个loginDao为同一个对象。
关于jfinal的入参注入问题,官文有相关文档,大致有以下几种方式:
1.在Action中直接使用,jfinal自动转换。

1
2
3
4
5
6
public class HelloController extends Controller {

public void getJson(User user){
renderJson("name",user.getName());
}
}

我用post+json方式测试过,返回的是null,官文案例使用form表单方式,没测试过。
2.使用getPara()方式。 controller里内置了很多方法,如renderText(),renderJson,getPara()等,在controller中使用getpara()或者其重载方法,可以很方便的获取入参。
3.使用HttpKit。 jfinal内置了很多kit,如PropKit,Aop其实也算一个kit,DbKit。在controller中使用HttpKit可以获取入参:HttpKit.readData(getRequest());

JSON的支持

jfinal支持四种json,其中包括jacsonJson和fastJson。只需在jfinalConfig中配置即可。renderJson会按照配置的json进行转换。

1
2
3
4
5
6
7
8
@Override
public void configConstant(Constants constants) {
constants.setDevMode(true);
//配置json
constants.setJsonFactory(new JacksonFactory());
// 开启对 jfinal web 项目组件 Controller、Interceptor、Validator 的注入
constants.setInjectDependency(true);
}


Model的使用

使用jfinal的generator生成model和配置。

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
41
42
43
44
45
46
47
48
49
50
51
52
53
package io.github.black.jfinal.demo;

import com.jfinal.kit.PathKit;
import com.jfinal.plugin.activerecord.generator.Generator;
import com.jfinal.plugin.druid.DruidPlugin;

import javax.sql.DataSource;

public class ModelGenerator {

private static DruidPlugin getDP(){
DruidPlugin dp = new DruidPlugin("jdbc:mysql://10.108.136.128/blackdb", "root", "123456");
return dp;
}

public static void main(String[] args) {
// base model 所使用的包名
String baseModelPkg = "io.github.black.jfinal.demo.entity.base";
// base model 文件保存路径
String baseModelDir = PathKit.getWebRootPath() + "/src/main/java/io/github/black/jfinal/demo/entity/base";
// model 所使用的包名
String modelPkg = "io.github.black.jfinal.demo.entity";
// model 文件保存路径
String modelDir = baseModelDir + "/..";

DruidPlugin dp = getDP();
dp.start();
DataSource ds = dp.getDataSource();
Generator gernerator = new Generator(ds, baseModelPkg, baseModelDir, modelPkg, modelDir);
// 在 getter、setter 方法上生成字段备注内容
gernerator.setGenerateRemarks(true);

// 设置是否生成链式 setter 方法
// gernerator.setGenerateChainSetter(false);
// 添加不需要生成的表名
// gernerator.addExcludedTable("adv");

//覆盖掉其中的 isSkipTable(String tableName) 方法,可以随心所欲控制想要的处理的 table
ModelMetaBuilder metaBuilder = new ModelMetaBuilder(ds);
gernerator.setMetaBuilder(metaBuilder);
// 设置是否在 Model 中生成 dao 对象
gernerator.setGenerateDaoInModel(true);
// 设置是否生成链式 setter 方法
gernerator.setGenerateChainSetter(true);
// 设置是否生成字典文件
gernerator.setGenerateDataDictionary(false);
// 设置需要被移除的表名前缀用于生成modelName。例如表名 "osc_user",移除前缀 "osc_"后生成的model名为 "User"而非 OscUser
// gernerator.setRemovedTableNamePrefixes("t_");
// 生成
gernerator.generate();
dp.stop();
}
}

小结:
生成器根据数据库配置,扫描相关的表,生成相应的model。这里最主要的是,获取DataSource,然后是配置model的包路径,baseModel一般在model的base下面;gernerator.addExcludedTable(“adv”)可以排除不需要的表,如果太多,也可以使用MetaBuilder,复写isSkipTable()方法,随心所欲的控制想要处理的table。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class ModelMetaBuilder extends MetaBuilder {

public ModelMetaBuilder(DataSource dataSource){
super(dataSource);
}

/**
* isSkipTable 方法 return true 时将过滤掉当前 table
* @param tableName
* @return
*/
protected boolean isSkipTable(String tableName) {
if("user".equalsIgnoreCase(tableName)|| "wesd_cert".equalsIgnoreCase(tableName)){
return false;
}
return true;
}
}

上诉代码执行后,会在model下生成一个_MappingKit类(或者其他名字),该类需要在jfinalConfig中使用

1
2
3
4
5
6
7
8
9
@Override
public void configPlugin(Plugins plugins) {
DruidPlugin dp = new DruidPlugin("jdbc:mysql://10.108.136.128/blackdb", "root", "123456");
plugins.add(dp);
ActiveRecordPlugin arp = new ActiveRecordPlugin(dp);
_MappingKit.mapping(arp);
// arp.addMapping("user", User.class);
plugins.add(arp);
}


Kit的使用

PropKit.use()
HttpKit.readData(),HttpKit.post(),HttpKit.get()
DbKit.getConfig()
更多参考com.jfinal.kit包

总结

jfinal的开发和代码真的是极简,上手快。 但是实际应用的案例太少,还有很多的功能需要完善。
jfinal还有关于redis插件和其他模板渲染插件以及缓存插件,任务调度插件,以后再测试。