1. 分析
JFinal中刚新增like指令
在这之前大家的通常用法一般是自己拼装,如MySQL的用法:like concat('%', #para(title), '%')
自带的like指令功能单一,个人认为需要增强。
大神的like指令
https://jfinal.com/share/398
2. 方案
为了和JFinal新增指令不冲突,本指令命名为likePara。
like指令应该具备通用性强、自动适配百分号、支持多参数拼装等:
WHERE t.title #likePara("title", [1, '2', 3L], "4"),被解析为WHERE t.title LIKE ?,参数值为:'%title1234%';可以看出,多个不同类型的参数会toString()拼装,两端没有百分号则自动补充百分号,拼装规则为全Like;
#likePara('%', "value") 和 #likePara("%value"),参数值为:'%value',左边出现了百分号,拼装规则为左Like;同样,右Like拼装方式也一样;
3. 自定义标签
源码,基于Jboot的JbootDirectiveBase。:
- package com.jfinal.plugin.activerecord.sql;
- import java.util.ArrayList;
- import java.util.Collection;
- import java.util.List;
- import com.jfinal.plugin.activerecord.SqlPara;
- import com.jfinal.template.Env;
- import com.jfinal.template.TemplateException;
- import com.jfinal.template.expr.ast.ExprList;
- import com.jfinal.template.io.Writer;
- import com.jfinal.template.stat.ParseException;
- import com.jfinal.template.stat.Scope;
- import io.jboot.web.directive.base.JbootDirectiveBase;
- public class LikeParaDirective extends JbootDirectiveBase {
- public static final String DIRECTIVE_NAME = "likePara";
- @Override
- public void onRender(Env env, Scope scope, Writer writer) {
- SqlPara sqlPara = (SqlPara)scope.get(SqlKit.SQL_PARA_KEY);
- if (sqlPara == null) {
- throw new TemplateException("#" + DIRECTIVE_NAME + " directive invoked by getSqlPara(...) method only", this.location);
- }
- Object[] paraArray = this.exprList.evalExprList(scope);
- List<Object> paraList = new ArrayList<>();
- /*
- * 首先将参数全规划成List
- */
- for (Object para : paraArray) {
- if (para == null) { // 优先处理参数为Null的情况
- throw new ParseException("The parameter of #" + DIRECTIVE_NAME + " directive can not be null",
- this.location);
- } else if (para instanceof Collection<?>) { // 处理参数为Collection的情况
- paraList.addAll((Collection<?>)para);
- } else if (para.getClass().isArray()) { // 处理参数为Array的情况
- for (Object object : (Object[])para) {
- paraList.add(object);
- }
- } else { // 处理参数为一般类型的情况
- paraList.add(para);
- }
- }
- boolean leftLike = false;
- boolean rightLike = false;
- /*
- * 对规划好的参数List进行处理
- */
- // 处理左百分号(%)
- if ("%".equals(paraList.get(0))) {
- // 单独为百分号的情况
- leftLike = true;
- paraList.remove(0);
- } else if (String.valueOf(paraList.get(0)).startsWith("%")) {
- // 百分号开头的情况
- leftLike = true;
- paraList.set(0, String.valueOf(paraList.get(0)).substring(1));
- }
- // 处理右百分号(%)
- if (paraList.size() > 0) {
- int lastIndex = paraList.size() - 1;
- if ("%".equals(paraList.get(lastIndex))) {
- // 单独为百分号的情况
- rightLike = true;
- paraList.remove(lastIndex);
- } else if (String.valueOf(paraList.get(lastIndex)).endsWith("%")) {
- // 百分号结尾的情况
- rightLike = true;
- paraList.set(lastIndex,
- String.valueOf(paraList.get(0)).substring(0, String.valueOf(paraList.get(0)).length() - 1));
- }
- }
- /*
- * 构建LIKE参数字串
- */
- StringBuilder sb = new StringBuilder();
- // 左百分号(%)
- sb.append(leftLike ? '%' : "");
- sb.append(!(leftLike || rightLike) ? '%' : ""); // 左右都不包括百分号,则默认加上
- // 参数字串
- for (Object para : paraList) {
- sb.append(para);
- }
- // 右百分号(%)
- sb.append(rightLike ? '%' : "");
- sb.append(!(leftLike || rightLike) ? '%' : ""); // 左右都不包括百分号,则默认加上
- /*
- * 将解析好的参数给设置到SQL模板中
- */
- this.write(writer, "LIKE ?");
- sqlPara.addPara(sb.toString());
- }
- @Override
- public void setExprList(ExprList exprList) {
- if (exprList.length() == 0) {
- throw new ParseException("The parameter of #" + DIRECTIVE_NAME + " directive can not be blank",
- this.location);
- }
- this.exprList = exprList;
- }
- }
4. 测试
结果:
- ---------------------------------------------------
- 模板:#likePara('%', val, [1, '2', 3L], "4", '%')
- 入参:{"val":["v","alue",0]}
- 结果:LIKE '%value01234%'
- ---------------------------------------------------
- 模板:#likePara('%', val, [1, '2', 3L], "4", '%')
- 入参:{"val":["valu","e",0]}
- 结果:LIKE '%value01234%'
- ---------------------------------------------------
- 模板:#likePara(val, '%')
- 入参:{"val":"value"}
- 结果:LIKE 'value%'
- ---------------------------------------------------
- 模板:#likePara(val, '%')
- 入参:{"val":"%value"}
- 结果:LIKE '%value%'
- ---------------------------------------------------
- 模板:#likePara(val, '%')
- 入参:{"val":"va%lue"}
- 结果:LIKE 'va%lue%'
- ---------------------------------------------------
- 模板:#likePara('%', val, '%')
- 入参:{"val":"value"}
- 结果:LIKE '%value%'
- ---------------------------------------------------
- 模板:#likePara('%', val, '%')
- 入参:{"val":"value%"}
- 结果:LIKE '%value%%'
- ---------------------------------------------------
- 模板:#likePara('%', val, '%')
- 入参:{"val":"va%lue"}
- 结果:LIKE '%va%lue%'
- ---------------------------------------------------
- 模板:#likePara('%')
- 入参:{}
- 结果:LIKE '%'
- ---------------------------------------------------
- 模板:#likePara(val)
- 入参:{"val":"%"}
- 结果:LIKE '%'
- ---------------------------------------------------
- 模板:#likePara('%', val)
- 入参:{"val":"value"}
- 结果:LIKE '%value'
- ---------------------------------------------------
- 模板:#likePara('%', val)
- 入参:{"val":"value%"}
- 结果:LIKE '%value%'
- ---------------------------------------------------
- 模板:#likePara('%', val)
- 入参:{"val":"va%lue"}
- 结果:LIKE '%va%lue'
- ---------------------------------------------------
- 模板:#likePara(val)
- 入参:{"val":"value"}
- 结果:LIKE '%value%'
- ---------------------------------------------------
- 模板:#likePara(val)
- 入参:{"val":"%value"}
- 结果:LIKE '%value'
- ---------------------------------------------------
- 模板:#likePara(val)
- 入参:{"val":"value%"}
- 结果:LIKE 'value%'
- ---------------------------------------------------
- 模板:#likePara(val)
- 入参:{"val":"va%lue"}
- 结果:LIKE '%va%lue%'
- ---------------------------------------------------
- 模板:#likePara(val)
- 入参:{"val":["v","alue"]}
- 结果:LIKE '%value%'
- ---------------------------------------------------
- 模板:#likePara(val)
- 入参:{"val":["val","ue"]}
- 结果:LIKE '%value%'