在使用SQL模板参数时,很容易遇到开始日期和结束日期的查询,通常这种查询使用Between的效率最高。而JFinal自带的#para()指令就很尴尬了,它不支持参数为空时使用默认值。因此在模板中只能写成:
BETWEEN if(START_DATE) #para(START_DATE) #else #para('1000-01-01 00:00:00') #end
AND if(END_DATE) #para(END_DATE) #else #para('9999-12-31 23:59:59') #end可以看到,写法相当之别扭。与波总沟通后,决定自己扩展个指令#parad()来支持默认值,于是上面的SQL就可以写成:
BETWEEN #parad(START_DATE, '1000-01-01 00:00:00') AND #parad( END_DATE, '9999-12-31 23:59:59')
这样就顺眼多了。。。
可是要达到这样的程度,就需要2步走:
实现扩展指令#parad()
注册扩展指令到ActiveRecordPlugin的SQL模板引擎
第1步,扩展指令#parad():
public class ParadDirective extends Directive {
private int index = -1;
private String paraName = null;
private static boolean checkParaAssigned = true;
public static void setCheckParaAssigned(boolean checkParaAssigned) {
ParadDirective.checkParaAssigned = checkParaAssigned;
}
public void setExprList(ExprList exprList) {
if (exprList.length() == 0) {
throw new ParseException("The parameter of #para directive can not be blank", location);
}
if (exprList.length() == 1) {
Expr expr = exprList.getExpr(0);
if (expr instanceof Const && ((Const)expr).isInt()) {
index = ((Const)expr).getInt();
if (index < 0) {
throw new ParseException("The index of para array must greater than -1", location);
}
}
}
if (checkParaAssigned && exprList.getLastExpr() instanceof Id) {
Id id = (Id)exprList.getLastExpr();
paraName = id.getId();
}
this.exprList = exprList;
}
public void exec(Env env, Scope scope, Writer writer) {
SqlPara sqlPara = (SqlPara)scope.get(SqlKit.SQL_PARA_KEY);
if (sqlPara == null) {
throw new TemplateException("#para directive invoked by getSqlPara(...) method only", location);
}
write(writer, "?");
if (index == -1) {
// #para(paraName) 中的 paraName 没有赋值时抛出异常
// issue: http://www.jfinal.com/feedback/1832
if (checkParaAssigned && paraName != null && !scope.exists(paraName)) {
throw new TemplateException("The parameter \""+ paraName +"\" must be assigned", location);
}
// 屏蔽掉原代码
//sqlPara.addPara(exprList.eval(scope));
Object[] array = exprList.evalExprList(scope);
if(array[0] != null && (array[0] instanceof String && StrKit.notBlank((String) array[0]))) { //校验的同时,String类型参数不能为空字串
// 第一个参数不为空则注册参数到sqlPara
sqlPara.addPara(array[0]);
} else if(array.length > 1) {
// 将Default值注册到sqlPara
sqlPara.addPara(array[array.length -1 ]);
} else {
throw new TemplateException("The parameter \""+ paraName +"\" must be assigned or give a default value", location);
}
} else {
Object[] paras = (Object[])scope.get(SqlKit.PARA_ARRAY_KEY);
if (paras == null) {
throw new TemplateException("The #para(" + index + ") directive must invoked by getSqlPara(String, Object...) method", location);
}
if (index >= paras.length) {
throw new TemplateException("The index of #para directive is out of bounds: " + index, location);
}
sqlPara.addPara(paras[index]);
}
}将原#para()指令中的代码原样抄一遍,然后上面代码中“屏蔽掉原代码”之后的才是重点,这里我就不解释源码了,看客自己分析吧。
第2步,注册扩展指令到ActiveRecordPlugin的SQL模板引擎
// 数据操作插件
ActiveRecordPlugin arp = new ActiveRecordPlugin(druidPlugin);
// 注册支持默认参数值的标签
arp.getEngine().addDirective("parad", ParadDirective.class);同样,自己看,不解释。
到此,支持默认参数的#parad()指令就可以使用了。@JFinal
注意,#para()和#parad()就差了个字母d,各位看仔细了哦。