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())
);