5.4 生成器与 JavaBean
1、生成器的使用
ActiveRecord 模块的 com.jfinal.plugin.activerecord.generator 包下,提供了一个 Generator 工具类,可自动生成 Model、BaseModel、MappingKit、DataDictionary 四类文件。
生成后的 Model 将与 java bean 合体,立即拥有了 getter、setter 方法,使之遵守传统的 java bean 规范,立即拥有了传统 JavaBean 所有的优势,开发过程中不再需要记忆字段名。
使用生成器通常只需配置 Generator 的四个参数即可,以下是具体使用示例:
// model 所使用的包名 (MappingKit 默认使用的包名) String modelPackageName = "com.xxx.common.model"; // base model 所使用的包名 String baseModelPackageName = modelPackageName + ".base"; // base model 文件保存路径 String baseModelOutputDir = PathKit.getWebRootPath() + "/src/main/java/" + baseModelPackageName.replace('.', '/'); // model 文件保存路径 (MappingKit 与 DataDictionary 文件默认保存路径) String modelOutputDir = baseModelOutputDir + "/.."; System.out.println("输出路径:"+ baseModelOutputDir); Generator gen = new Generator(getDataSource(), baseModelPackageName, baseModelOutputDir, modelPackageName, modelOutputDir); gen.setGenerateRemarks(true); // 在 getter、setter 方法上生成字段备注内容 gen.generate();
baseModelPackageName、baseModelOutputDir、modelPackageName、modelOutputDir,四个参数分别表示 base model 的包名,baseModel 的输出路径,model 的包名,model 的输出路径。
由于后三个参数可以根据第一个参数来生成,所以通常只需要配置 modelPackageName 这一个参数即可。
可在官网下载 jfinal-demo 项目,其中的生成器可直接用于项目:http://www.jfinal.com
生成器的各部分组件都可以扩展,例如,MetaBuilder 可以指定 table 的过滤规则:https://jfinal.com/feedback/7290
此外,生成器 Generator 提供了很多 setter 配置方法,可以很方便控制生成的结果,如下配置可以指定生成器依赖的模板文件:
// 指定 base model 文件生成的模板文件 generator.setBaseModelTemplate(...); // 指定 model model 文件生成的模板文件 generator.setModelTemplate(...); // 指定 MappingKit 文件生成的模板文件 generator.setMappingKitTemplate(...)
以上代码可以用于指定生成器所依赖的模板文件,将模板文件放入 src/main/resources 目录下面可以被生成器获取到。定制模板文件一般需要在原有模板文件的基础之上做修改,原有模板文件在 jfinal 源码中有提供:https://gitee.com/jfinal/jfinal/tree/master/src/main/java/com/jfinal/plugin/activerecord/generator
后缀为 ".jf" 即为生成器所需的模板文件,里面所使用的语法为 enjoy 模板引擎语法。
2、相关生成文件
BaseModel 是用于被最终的 Model 继承的基类,所有的 getter、setter 方法都将生成在此文件内,这样就保障了最终 Model 的清爽与干净,BaseModel不需要人工维护,在数据库有任何变化时重新生成一次即可。
MappingKit 用于生成 table 到 Model 的映射关系,并且会生成主键/复合主键的配置,也即无需在 configPlugin(Plugins me) 方法中书写任何样板式的映射代码。
DataDictionary 是指生成的数据字典,会生成数据表所有字段的名称、类型、长度、备注、是否主键等信息。
3、 table 过滤、排除
Generator 内部工作流程由 MetaBuilder、ModelGenerator、BaseModelGenerator、MappingKitGenerator、DataDictionaryGenerator 组件组合而成,而这些组件都可以通过继承扩展,或者独立配置,然后再组装到 Generator 中,从而实现个性化的定制功能
下面代码通过配置 MetaBuilder 实现 table 过滤功能,过滤掉的 table 将不会生成相应的类与映射文件:
MetaBuilder metaBuilder = new MetaBuilder(dataSource) // 使用 filter 方法定制过滤逻辑,返回 true 表示过滤掉当前 table .filter(tableName -> { return tableName.startsWith("sys_"); }); Generator gen = new Generator(dataSource, baseModelPackageName, baseModelOutputDir); gen.setMetaBuilder(metaBuilder); gen.generate();
以上代码通过创建 MetaBuilder 对象,并单独对它进行 filter 配置,然后再通过 generator.setMetaBuilder(...) 将其注入到生成器之中,从而实现了 talbe 的定制化过滤。
注意:jfinal 4.9.05 版本之后,filter(...) 方法将更名为 skip(...);
除此之外,还可以通过继承 MetaBuilder、ModelGenerator、BaseModelGenerator 等等组件,然后再将其注入到生成器之中,实现更多的个性化功能。
4、使用生成器的主要优势
充分利用海量的针对于 Bean 设计的第三方工具,例如 jackson、freemarker
快速响应数据库表变动,极速重构,提升开发效率,提升代码质量
拥有 IDE 代码提示不用记忆数据表字段名,消除记忆负担,避免手写字段名出现手误
BaseModel 设计令 Model 中依然保持清爽,在表结构变化时极速重构关联代码
自动化 table 至 Model 映射
自动化主键、复合主键名称识别与映射
MappingKit 承载映射代码,JFinalConfig 保持干净清爽
有利于分布式场景和无数据源时使用 Model
新设计避免了以往自动扫描映射设计的若干缺点:引入新概念(如注解)增加学习成本、性能低、jar包扫描可靠性与安全性低
5、Model 与 Bean 合体后注意事项
合体后 JSP 模板输出 Bean 中的数据将依赖其 getter 方法,输出的变量名即为 getter 方法去掉 ”get” 前缀字符后剩下的字符首字母变小写,如果希望 JSP 仍然使用之前的输出方式,可以在系统启动时调用一下 ModelRecordElResolver. setResolveBeanAsModel(true);
Controller 之中的 getModel() 需要表单域名称对应于数据表字段名,而 getBean() 则依赖于setter方法,表单域名对应于 setter 方法去掉 ”set” 前缀字符后剩下的字符串字母变小写。
许多类似于 jackson、fastjson 的第三方工具依赖于 Bean 的 getter 方法进行操作,所以只有合体后才可以使用 jackson、fastjson
JFinalJson将 Model 转换为json数据时,json 的 keyName 是原始的数据表字段名,而 jackson、fastjson 这类依赖于 getter 方法转化成的 json 的 keyName 是数据表字段名转换而成的驼峰命名
建议 mysql 数据表的字段名直接使用驼峰命名,这样可以令 json 的 keyName 完全一致,也可以使 JSP 在页面中取值时使用完全一致的属性名。注意:mysql 数据表的名称仍然使用下划线命名方式并使用小写字母,方便在 linux 与 windows 系统之间移植。
总之,合体后的 Bean 在使用时要清楚使用的是其 BaseModel 中的 getter、setter 方法还是其 Model 中的 get(String attrName) 方法
6、常见问题解决
Sql Server 数据库在使用生成器之时,会获取到系统自带的表,需要对这些表进行过滤,具体办法参考:http://www.jfinal.com/share/211