ActiveRecord提供了基础的方法,实际开发项目中扩展一下用起来就更方便了,幸好官方提供的有Enjoy Template Engine,可以很方便的实现扩展,今天就分享一下我在一个项目中的扩展方案。
首先我们编写Enjoy SQL模板文件,resources/all.sql
#define in(field,values) #if(values && values.size()>0) #(field) in ( #for(value:values) #para(value)#(for.last?'':',') #end ) #else false #end #end #define where(where) #for(x : where) #(for.first ? " where": " and") #if(x.key=="_in") #for(inx : x.value) #@in( inx.key,inx.value) #end #elseif(x.key=="") #(x.value) #else #(x.key) #para(x.value) #end #end #end ### count查询,table、[field]、[where] #sql("count") select #if(field) count(#(field)) #else count(*) #end from #(table) #@where(where) #end ### sum查询,table、field、[where] #sql("sum") select sum(#(field)) from #(table) #@where(where) #end ### column查询,table、field、[where] #sql("column") select #(field) from #(table) #@where(where) #end ### 修改操作 table、where、update #sql("update") update #(table) set #for(x : update) #(x.key) = #para(x.value)#(for.last?'':',') #end #@where(where) #end ### 查询数据 table、[fields]、where、[orderby] #sql("query") select #if(fields) #(fields) #else * #end from #(table) #@where(where) #if(orderby) order by #(orderby) #end #end ### 删除数据 table、[fields]、where、[orderby] #sql("delete") delete from #(table) #@where(where) #end
文件中提供了增删改查的一些模板,主要是实现动态条件,上面的参数需要定义一个参数类,使用字典形式,大体如下 :
package com.aaa.xapi.helpers; import com.jfinal.kit.Kv; /** * 结合 jfinal 的 Enjoy SQL 模板,快速生成参数 */ public class Dict extends Kv { /* 总体结构预览 { table:'table', field:'id', fields:'id,name', update:{ name:'新的名称', age:'新的年龄' }, where:{ id:1, age:2 _in:{ id:[2,3,4] }, _or:{ id:2, name like:23 } } orderby:'id desc', } * */ public static Dict create() { return new Dict(); } public static Dict table(String table) { return new Dict().tbl(table); } public Dict() { } /** * 指定查询的table * * @param table * @return */ public Dict tbl(String table) { String newTable = table; if (table.equals("Order") || table.equals("User") ) { newTable = "`" + newTable + "`"; } this.set("table", newTable); return this; } /** * 添加where条件 * * @param key * @param value * @return */ public Dict where(Object key, Object value) { Kv where = (Kv) this.getOrDefault("where", Kv.create()); where.set(key, value); this.set("where", where); return this; } /** * 添加where条件 * * @param key * @param value * @return */ public Dict eq(Object key, Object value) { return where(key + " = ", value); } /** * 添加where条件 * * @param key * @param value * @return */ public Dict neq(Object key, Object value) { return where(key + " != ", value); } /** * 添加where条件 * * @param key * @param value * @return */ public Dict gt(Object key, Object value) { return where(key + " > ", value); } /** * 添加where条件 * * @param key * @param value * @return */ public Dict gte(Object key, Object value) { return where(key + " >= ", value); } /** * 添加where条件 * * @param key * @param value * @return */ public Dict lt(Object key, Object value) { return where(key + " < ", value); } /** * 添加where条件 * * @param key * @param value * @return */ public Dict lte(Object key, Object value) { return where(key + " <= ", value); } /** * 添加where条件 * * @param key * @param value * @return */ public Dict like(Object key, Object value) { return where(key + " like ", "%" + value + "%"); } /** * 添加where条件 * * @param key * @param values * @return */ public Dict in(String key, Object values) { Kv where = (Kv) this.getOrDefault("where", Kv.create()); Kv _in = (Kv) where.getOrDefault("_in", Kv.create()); _in.set(key, values); where.set("_in", _in); this.set("where", where); return this; } /** * 添加where条件 * * @param values * @return */ public Dict idIn(Object values) { Kv where = (Kv) this.getOrDefault("where", Kv.create()); Kv _in = (Kv) where.getOrDefault("_in", Kv.create()); _in.set("Id", values); where.set("_in", _in); this.set("where", where); return this; } /** * sql * * @param sql * @return */ public Dict whereSql(String sql) { return where("", sql); } public Dict whereSql(String sql, Object... args) { return where("", String.format(sql, args)); } /** * 添加要修改的字段和值 * * @param key * @param value * @return */ public Dict update(Object key, Object value) { Kv update = (Kv) this.getOrDefault("update", Kv.create()); update.set(key, value); this.set("update", update); return this; } /** * 要查询的字段 * * @param selectFields * @return */ public Dict fields(String selectFields) { this.set("fields", selectFields); return this; } /** * 要查询的字段 * * @param field * @return */ public Dict field(String field) { this.set("field", field); return this; } /** * 排序条件 * * @param orderby * @return */ public Dict orderby(String orderby) { this.set("orderby", orderby); return this; } public Dict orderbyIdDesc() { this.set("orderby", "Id desc"); return this; } }
该类的目的就是方便生成sqltemplate里的目标,调用的template方法不同,使用的参数也不同。
我们配置ActiveRecordPlugin的时候需要添加一下all.sql
这样我们基本就可以使用了,如查询分页:
var dict = Dict.create(); dict.tbl("User"); if (StringHelper.hasValue(ps.getName())) { dict.like("Name", ps.getName()); } if (NumberHelper.hasValue(ps.getAge())) { dict.eq("Age", ps.getAge()); } User.dao.template("query",dict).paginate(1,20);
为了更方便使用,需要更进一步的优化,我们需要替换掉实体类的默认基类Model<M>,然后我们就可以随时扩展自己的基类。
首先定义自己的基类,让它集成Model<M>:
package com.aaa.xapi.basedto; import com.jfinal.plugin.activerecord.Db; import com.jfinal.plugin.activerecord.DbTemplate; import com.jfinal.plugin.activerecord.Model; import com.jfinal.plugin.activerecord.Page; import com.mpyf.xapi.helpers.Dict; import com.mpyf.xapi.services.SQL; import org.apache.calcite.linq4j.Linq4j; import java.util.List; /** * 自定义数据库模型基类 * * @param <M> */ public abstract class DbModel<M extends DbModel<M>> extends Model<M> { private String tableName; @Override public M dao() { this.tableName = _getTable().getName(); return super.dao(); } public int queryMaxId(){ return Db.queryInt("select IfNULL( max(Id),0) from "+tableName); } public List<M> queryByIds(List<Integer> ids) { return template(SQL.query, Dict.table(tableName).idIn(ids)).find(); } public List<M> queryByIds(Integer[] ids) { return template(SQL.query, Dict.table(tableName).idIn(Linq4j.asEnumerable(ids).toList())).find(); } public List<M> queryByFields(String field, Object values) { return template(SQL.query, Dict.table(tableName).in(field, values)).find(); } public List<M> query(Dict dict) { dict.tbl(tableName); return template(SQL.query, dict).find(); } public M queryFirst(Dict dict) { dict.tbl(tableName); return template(SQL.query, dict).findFirst(); } public Page<M> paginate(Dict dict, int pageIndex, int pageSize) { dict.tbl(tableName); return template(SQL.query, dict).paginate(pageIndex, pageSize); } public Page<M> paginate(Dict dict, PageParams ps) { dict.tbl(tableName); System.out.println( getSqlPara(SQL.query,dict).getSql()); return template(SQL.query, dict).paginate(ps.getPageIndex(), ps.getPageSize()); } public int count(Dict dict) { dict.tbl(tableName); return Db.template(SQL.count, dict).queryInt(); } public <T> List<T> column(Dict dict) { dict.tbl(tableName); if (dict.get("field") == null) { dict.field("Id"); } return Db.template(SQL.column, dict).query(); } public <T> List<T> column(String field, Dict dict) { dict.tbl(tableName).field(field); return column(dict); } public DbTemplate sumTemplate(Dict dict) { dict.tbl(tableName); return Db.template(SQL.sum, dict); } public int update(Dict dict) { dict.tbl(tableName); return Db.template(SQL.update, dict).update(); } public int delete(Dict dict) { dict.tbl(tableName); return Db.template(SQL.delete, dict).delete(); } }
DbModel里主要实现了对自定义template方法的调用,不过可以随时扩展其他的公共方法。
上面用到了一个SQL类是这样的,只是方便写template里key的名称:
public class SQL { public static final String query = "query"; public static final String update = "update"; public static final String count = "count"; public static final String column = "column"; public static final String sum = "sum"; public static final String delete = "delete"; }
生成模型的时候需要一个基类模板,也放在resources中,base_model_template.jf:
package #(baseModelPackageName); import com.jfinal.plugin.activerecord.IBean; import com.aaa.xapi.basedto.DbModel; /** * Generated by JFinal, do not modify this file. */ #if (generateChainSetter) @SuppressWarnings({"serial", "unchecked"}) #else @SuppressWarnings("serial") #end public abstract class #(tableMeta.baseModelName)<M extends #(tableMeta.baseModelName)<M>> extends DbModel<M> implements IBean { #set(b = generateChainSetter) #for(cm : tableMeta.columnMetas) #if (cm.remarks) /** * #(cm.remarks) */ #end #set(argName = javaKeyword.contains(cm.attrName) ? '_' + cm.attrName : cm.attrName) public #(b ? 'M' : 'void') set#(firstCharToUpperCase(cm.attrName))(#(cm.javaType) #(argName)) { set("#(cm.name)", #(argName)); #if (b) return (M)this; #end } #if (cm.remarks) /** * #(cm.remarks) */ #end #set(getterOfModel = getterTypeMap.get(cm.javaType)) #if (isBlank(getterOfModel)) #set(getterOfModel = 'get') #end public #(cm.javaType) get#(firstCharToUpperCase(cm.attrName))() { return #(getterOfModel)("#(cm.name)"); } #end }
在生成配置中需要指定模型基类:
generator.setBaseModelTemplate("base_model_template.jf");
到此便更改完成,我们增强了dao层,并且有一个自定义的dao层基类,可以随时新增一些公共方法。
举例几个用法:
///修改密码: User.dao.update(Dict.create().eq("Id", 1).update("Password", "123456")); //根据ids查询 user.dao.queryByIds(new []{1,2,3,4,5}) //根据条件查询 User.dao.queryFirst( Dict.create().eq("Account", ps.getAccount()).eq("Password", pwd).eq("UserType", ps.getUserType()) );