在使用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,各位看仔细了哦。