JFinal极速开发框架使用笔记(三) 分析Model和ActiveRecord
JFinal框架的一些新发现的用法:
在JFinal框架中,实体类并不需要设置属性,更不需要配置getset方法就可以很方便的操作数据库,如果需要设置或者获取属性,可以直接使用一下方式:
User user = new User().set("id", "MY_SEQ.nextval").set("age", 18); user.save(); // 获取id值 Integer id = user.get("id");
但是,如果有需要使用getset方法的情况,就可以使用JFinal框架中的生成器来方便的生成方法。
JFinal框架中的实体类以及getset方法生成器:
package com.demo.common.model; import javax.sql.DataSource; import com.demo.common.DemoConfig; import com.jfinal.kit.PathKit; import com.jfinal.kit.PropKit; import com.jfinal.plugin.activerecord.generator.Generator; import com.jfinal.plugin.druid.DruidPlugin; /** * 本 demo 仅表达最为粗浅的 jfinal 用法,更为有价值的实用的企业级用法 * 详见 JFinal 俱乐部: http://jfinal.com/club * * 在数据库表有任何变动时,运行一下 main 方法,极速响应变化进行代码重构 */ public class _JFinalDemoGenerator { public static DataSource getDataSource() { PropKit.use("a_little_config.txt"); DruidPlugin druidPlugin = DemoConfig.createDruidPlugin(); druidPlugin.start(); return druidPlugin.getDataSource(); } public static void main(String[] args) { // base model 所使用的包名 String baseModelPackageName = "com.demo.common.model.base"; // base model 文件保存路径 String baseModelOutputDir = PathKit.getWebRootPath() + "/../src/com/demo/common/model/base"; // model 所使用的包名 (MappingKit 默认使用的包名) String modelPackageName = "com.demo.common.model"; // model 文件保存路径 (MappingKit 与 DataDictionary 文件默认保存路径) String modelOutputDir = baseModelOutputDir + "/.."; // 创建生成器 Generator generator = new Generator(getDataSource(), baseModelPackageName, baseModelOutputDir, modelPackageName, modelOutputDir); // 设置是否生成链式 setter 方法 generator.setGenerateChainSetter(false); // 添加不需要生成的表名 generator.addExcludedTable("adv"); // 设置是否在 Model 中生成 dao 对象 generator.setGenerateDaoInModel(true); // 设置是否生成链式 setter 方法 generator.setGenerateChainSetter(true); // 设置是否生成字典文件 generator.setGenerateDataDictionary(false); // 设置需要被移除的表名前缀用于生成modelName。例如表名 "osc_user",移除前缀 "osc_"后生成的model名为 "User"而非 OscUser generator.setRemovedTableNamePrefixes("t_"); // 生成 generator.generate(); } }
还需要在继承了JFinalConfig的主文件中设置:
public static DruidPlugin createDruidPlugin() { return new DruidPlugin(PropKit.get("jdbcUrl"), PropKit.get("user"), PropKit.get("password").trim()); }
JFinal框架向接受前台表单传过来的参数并增加有两种方法,一种是getBean方式,一种是getModel方式。
getModel方式用来接收表单域传过来的Model对象,表单域名称以”modelName.attrName”方式命名, getModel 使用的 attrName 必须与数据表字段名完全一样。
getBean 方法用于支持传统 Java Bean, 包括支持使用 jfnal 生成器生成了 getter、 setter 方法的 Model, 页面表单传参时使用与 setter 方法相一致的 attrName,而非数据表字段名。getModel 与 getBean 区别在于前者使用数表字段名而后者使用与 setter 方法一致的属性名进行数据注入。
除了这个之外,JFinal还可以通过使用空字符串“”实现,表单域中使用正常方式提交,不用加前缀,在后台接受时,使用getModel方法,加一个“”,就可以正常接收数据了。
@Before(StudentTestValidator2.class) public void savebeanscore(){ StudentTest st=getModel(StudentTest.class,""); st.save(); redirect("/student/layui"); }
同样的,JFinal这种方式也可以在表单域中设置专门的前缀,然后再后台用同样的方式用该前缀参数使用getModel方式接受。
ActiveRecord
ActiveRecord 是 JFinal 最核心的组成部分之一,通过 ActiveRecord 来操作数据库, 将极大地减少代码量,极大地提升开发效率。
ActiveRecord 是作为 JFinal 的 Plugin 而存在的,所以使用时需要在 JFinalConfig 中配置ActiveRecordPlugin。
public void configPlugin(Plugins me) { // C3p0Plugin cp = new C3p0Plugin("jdbc:mysql://localhost/db_name", // "userName", "password"); // me.add(cp); loadPropertyFile("a_little_config.txt"); DruidPlugin dp = new DruidPlugin(getProperty("jdbcUrl"), getProperty("user"), getProperty("password")); me.add(dp); ActiveRecordPlugin arp = new ActiveRecordPlugin(dp); me.add(arp); arp.setDialect(new MysqlDialect()); arp.addMapping("blog","id", Blog.class); arp.addMapping("student","studentid", Student.class); arp.addMapping("studenttest","id", StudentTest.class); /*DruidPlugin dp = new DruidPlugin(getProperty("jdbcUrl"), getProperty("user"), getProperty("password")); me.add(dp); ActiveRecordPlugin arp = new ActiveRecordPlugin(dp); me.add(arp); //arp.addMapping("blog", "id", Blog.class); arp.addMapping("student", "studentid", Student.class); //arp.addMapping("studenttest", "id", StudentTest.class); */ // 此方法用来配置JFinal的Plugin,如下代码配置了Druid数据库连接池插件与ActiveRecord // 数据库访问插件。通过以下的配置,可以在应用中使用 ActiveRecord 非常方便地操作数据库。 }
DruidPlugin是druid数据源插件,
ActiveRecordPlugin后者是ActiveRecrod 支持插件。
ActiveReceord 中定义了 addMapping(String tableName, Class<?extends Model> modelClass>)方法,该方法建立了数据库表名到 Model 的映射关系。
另外,以上代码中 arp.addMapping(“user”, User.class),表的主键名为默认为“id”,如果主键名称为 “user_id”则需要手动指定,如: arp.addMapping(“user”, “user_id”, User.class)。
ActiveRecord中的Model
Model 是 ActiveRecord 中最重要的组件之一, 它充当 MVC 模式中的 Model 部分。
public class StudentTest extends Model<StudentTest> { /** * */ private static final long serialVersionUID = 1L; public static final StudentTest dao = new StudentTest(); }
以上代码中继承 Model,便立即拥有的众多方便的操作数据库的方法。在类中声明的 dao 静态对象是为了方便查询操作而定义的,该对象并不是必须的。基于 ActiveRecord的 Model 无需定义属性, 无需定义 getter、 setter 方法,无需 XML 配置,无需 Annotation 配置,极大降低了代码量。
特别注意: User 中定义的 public static final User dao 对象是全局共享的, 只能用于数据库查询,不能用于数据承载对象。 数据承载需要使用 new User().set(…)来实现。
JFinal 独创 Db + Record 模式
Db 类及其配套的 Record 类, 提供了在 Model 类之外更为丰富的数据库操作功能。 使用Db 与 Record 类时,无需对数据库表进行映射, Record 相当于一个通用的 Model。 以下为 Db +Record 模式的一些常见用法:
Dialect 多数据库支持
目 前 ActiveRecordPlugin 提 供 了 MysqlDialect 、 OracleDialect 、 PostgresqlDialect 、SqlServerDialect、 Sqlite3Dialect、 AnsiSqlDialect 实现类。 MysqlDialect 与 OracleDialect 分别实现对 Mysql 与 Oracle 的支持, AnsiSqlDialect 实现对遵守 ANSI SQL 数据库的支持。 以下是数据库 Dialect 的配置代码:
public void configPlugin(Plugins me) { // C3p0Plugin cp = new C3p0Plugin("jdbc:mysql://localhost/db_name", // "userName", "password"); // me.add(cp); loadPropertyFile("a_little_config.txt"); DruidPlugin dp = new DruidPlugin(getProperty("jdbcUrl"), getProperty("user"), getProperty("password")); me.add(dp); ActiveRecordPlugin arp = new ActiveRecordPlugin(dp); me.add(arp); arp.setDialect(new MysqlDialect()); arp.addMapping("blog","id", Blog.class); arp.addMapping("student","studentid", Student.class); arp.addMapping("studenttest","id", StudentTest.class); /*DruidPlugin dp = new DruidPlugin(getProperty("jdbcUrl"), getProperty("user"), getProperty("password")); me.add(dp); ActiveRecordPlugin arp = new ActiveRecordPlugin(dp); me.add(arp); //arp.addMapping("blog", "id", Blog.class); arp.addMapping("student", "studentid", Student.class); //arp.addMapping("studenttest", "id", StudentTest.class); */ // 此方法用来配置JFinal的Plugin,如下代码配置了Druid数据库连接池插件与ActiveRecord // 数据库访问插件。通过以下的配置,可以在应用中使用 ActiveRecord 非常方便地操作数据库。 }
表关联操作
JFinal ActiveRecord 天然支持表关联操作,并不需要学习新的东西, 此为无招胜有招。 表关联操作主要有两种方式:一是直接使用 sql 得到关联数据;二是在 Model 中添加获取关联数据的方法。
假定现有两张数据库表: user、 blog,并且 user 到 blog 是一对多关系, blog 表中使用 user_id关联到 user 表。如下代码演示使用第一种方式得到 user_name:
public void relation() { String sql = "select b.*, u.user_name from blog b inner join user u on b.user_id=u.id where b.id=?"; Blog blog = Blog.dao.findFirst(sql, 123); String name = blog.getStr("user_name"); }
以下代码演示第二种方式在 Blog 中获取相关联的 User 以及在 User 中获取相关联的 Blog:
public class Blog extends Model<Blog>{ public static final Blog dao = new Blog(); public User getUser() { return User.dao.findById(get("user_id")); } } public class User extends Model<User>{ public static final User dao = new User(); public List<Blog> getBlogs() { return Blog.dao.find("select * from blog where user_id=?", get("id")); } }
复合主键
JFinal ActiveRecord 从 2.0 版本开始, 采用极简设计支持复合主键,对于 Model 来说需要在映射时指定复合主键名称,以下是具体例子:
ActiveRecordPlugin arp = new ActiveRecordPlugin(druidPlugin); // 多数据源的配置仅仅是如下第二个参数指定一次复合主键名称 arp.addMapping("user_role", "userId, roleId", UserRole.class); //同时指定复合主键值即可查找记录 UserRole.dao.findById(123, 456); //同时指定复合主键值即可删除记录 UserRole.dao.deleteById(123, 456);
如上代码所示,对于 Model 来说,只需要在添加 Model 映射时指定复合主键名称即可开始使用复合主键, 在后续的操作中 JFinal 会对复合主键支持的个数进行检测,当复合主键数量不正确时会报异常,尤其是复合主键数量不够时能够确保数据安全。 复合主键不限定只能有两个,可以是数据库支持下的任意多个。对于 Db + Record 模式来说,复合主键的使用不需要配置,直接用即可:
Db.findById("user_role", "roleId, userId", 123, 456);
Db.deleteById("user_role", "roleId, userId", 123, 456);
其他的JFinal的ActiveRecord得用法,如分页等等,就不一一记录了,可以参考JFinal官方文档。