Browse Source

增加表达式方式传入查询条件

zhou-hao 6 years ago
parent
commit
093eee9b30

+ 32 - 1
hsweb-commons/hsweb-commons-entity/src/main/java/org/hswebframework/web/commons/entity/param/QueryParamEntity.java

@@ -1,5 +1,7 @@
 package org.hswebframework.web.commons.entity.param;
 
+import lombok.Getter;
+import lombok.Setter;
 import org.hswebframework.ezorm.core.NestConditional;
 import org.hswebframework.ezorm.core.dsl.Query;
 import org.hswebframework.ezorm.core.param.QueryParam;
@@ -7,6 +9,7 @@ import org.hswebframework.ezorm.core.param.Term;
 import org.hswebframework.web.commons.entity.Entity;
 import org.hswebframework.web.commons.entity.QueryEntity;
 import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -19,7 +22,7 @@ import java.util.function.Consumer;
  * {@link QueryParamEntity#single(String, Object)}<br>
  * 如:
  * <code>
- * QueryParamBean.single("id",id);
+ * QueryParamEntity.single("id",id);
  * </code>
  *
  * @author zhouhao
@@ -31,6 +34,9 @@ public class QueryParamEntity extends QueryParam implements QueryEntity {
 
     private static final long serialVersionUID = 8097500947924037523L;
 
+    @Getter
+    private String termExpression;
+
     /**
      * 创建一个空的查询参数实体,该实体无任何参数.
      *
@@ -116,6 +122,31 @@ public class QueryParamEntity extends QueryParam implements QueryEntity {
                 .end();
     }
 
+    /**
+     * 设置条件表达式,可以通过表达式的方式快速构建查询条件. 表达式是类似sql条件的语法,如:
+     * <pre>
+     *     name is 测试 and age gte 10
+     * </pre>
+     * <pre>
+     *     name is 测试 and (age gt 10 or age lte 90 )
+     * </pre>
+     *
+     * @param termExpression 表达式
+     * @see 3.0.5
+     */
+    public void setTermExpression(String termExpression) {
+        this.termExpression = termExpression;
+        setTerms(TermExpressionParser.parse(termExpression));
+    }
+
+    @Override
+    public List<Term> getTerms() {
+        List<Term> terms = super.getTerms();
+        if (CollectionUtils.isEmpty(terms) && StringUtils.hasText(termExpression)) {
+            setTerms(terms = TermExpressionParser.parse(termExpression));
+        }
+        return terms;
+    }
 
     @Override
     public String toString() {

+ 157 - 0
hsweb-commons/hsweb-commons-entity/src/main/java/org/hswebframework/web/commons/entity/param/TermExpressionParser.java

@@ -0,0 +1,157 @@
+package org.hswebframework.web.commons.entity.param;
+
+import org.hswebframework.ezorm.core.NestConditional;
+import org.hswebframework.ezorm.core.dsl.Query;
+import org.hswebframework.ezorm.core.param.Term;
+import org.hswebframework.ezorm.core.param.TermType;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 动态条件表达式解析器
+ * name=测试 and age=test
+ */
+public class TermExpressionParser {
+
+    public static List<Term> parse(String expression) {
+        Query<?, QueryParamEntity> conditional = QueryParamEntity.newQuery();
+
+        NestConditional<?> nest = null;
+
+        char[] buf = new char[128];
+        byte current = 0;
+        byte spaceLen = 0;
+
+        char[] currentColumn = null;
+
+        String currentTermType = null;
+        char[] currentValue = null;
+        char[] all = expression.toCharArray();
+        String currentType = "and";
+        for (char c : all) {
+
+            if (c == '(') {
+                nest = (nest == null ?
+                        (currentType.equals("or") ? conditional.orNest() : conditional.nest()) :
+                        (currentType.equals("or") ? nest.orNest() : nest.nest()));
+                current = 0;
+
+                continue;
+            } else if (c == ')') {
+                if (nest == null) {
+                    continue;
+                }
+                if (null != currentColumn) {
+                    currentValue = Arrays.copyOf(buf, current);
+                    nest.accept(new String(currentColumn), convertTermType(currentTermType), new String(currentValue));
+                    currentColumn = null;
+                    currentTermType = null;
+                }
+                Object end = nest.end();
+                nest = end instanceof NestConditional ? ((NestConditional) end) : null;
+                current = 0;
+                spaceLen++;
+                continue;
+            } else if (c == '=' || c == '>' || c == '<') {
+                if (currentTermType != null) {
+                    currentTermType += String.valueOf(c);
+                } else {
+                    currentTermType = String.valueOf(c);
+                }
+
+                if (currentColumn == null) {
+                    currentColumn = Arrays.copyOf(buf, current);
+                }
+                spaceLen++;
+                current = 0;
+                continue;
+            } else if (c == ' ') {
+                if (current == 0) {
+                    continue;
+                }
+                spaceLen++;
+                if (currentColumn == null && (spaceLen == 1 || spaceLen % 5 == 0)) {
+                    currentColumn = Arrays.copyOf(buf, current);
+                    current = 0;
+                    continue;
+                }
+                if (null != currentColumn) {
+                    if (null == currentTermType) {
+                        currentTermType = new String(Arrays.copyOf(buf, current));
+                        current = 0;
+                        continue;
+                    }
+                    currentValue = Arrays.copyOf(buf, current);
+                    if (nest != null) {
+                        nest.accept(new String(currentColumn), convertTermType(currentTermType), new String(currentValue));
+                    } else {
+                        conditional.accept(new String(currentColumn), convertTermType(currentTermType), new String(currentValue));
+                    }
+                    currentColumn = null;
+                    currentTermType = null;
+                    current = 0;
+                    continue;
+                } else if (current == 2 || current == 3) {
+                    String type = new String(Arrays.copyOf(buf, current));
+                    if (type.equalsIgnoreCase("or")) {
+                        currentType = "or";
+                        if (nest != null) {
+                            nest.or();
+                        } else {
+                            conditional.or();
+                        }
+                        current = 0;
+                        continue;
+                    } else if (type.equalsIgnoreCase("and")) {
+                        currentType = "and";
+                        if (nest != null) {
+                            nest.and();
+                        } else {
+                            conditional.and();
+                        }
+                        current = 0;
+                        continue;
+                    } else {
+                        currentColumn = Arrays.copyOf(buf, current);
+                        current = 0;
+                        spaceLen++;
+                    }
+                }
+                continue;
+            }
+
+            buf[current++] = c;
+        }
+        if (null != currentColumn) {
+            currentValue = Arrays.copyOf(buf, current);
+            if (nest != null) {
+                nest.accept(new String(currentColumn), convertTermType(currentTermType), new String(currentValue));
+            } else {
+                conditional.accept(new String(currentColumn), convertTermType(currentTermType), new String(currentValue));
+            }
+        }
+        return conditional.getParam().getTerms();
+    }
+
+    private static String convertTermType(String termType) {
+        if (termType == null) {
+            return TermType.eq;
+        }
+        switch (termType) {
+            case "=":
+                return TermType.eq;
+            case ">":
+                return TermType.gt;
+            case "<":
+                return TermType.lt;
+            case ">=":
+                return TermType.gte;
+            case "<=":
+                return TermType.lte;
+            default:
+                return termType;
+        }
+
+    }
+}

+ 57 - 0
hsweb-commons/hsweb-commons-entity/src/test/java/org/hswebframework/web/commons/entity/param/TermExpressionParserTest.java

@@ -0,0 +1,57 @@
+package org.hswebframework.web.commons.entity.param;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.serializer.SerializerFeature;
+import org.hswebframework.ezorm.core.param.Term;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.List;
+
+import static org.junit.Assert.*;
+
+public class TermExpressionParserTest {
+
+    @Test
+    public void testSimple() {
+        String expression = "name=测试 or age=10";
+        List<Term> terms = TermExpressionParser.parse(expression);
+
+        Assert.assertNotNull(terms);
+        Assert.assertEquals(terms.size(), 2);
+        Assert.assertEquals(terms.get(0).getColumn(), "name");
+        Assert.assertEquals(terms.get(0).getValue(), "测试");
+
+        Assert.assertEquals(terms.get(1).getColumn(), "age");
+        Assert.assertEquals(terms.get(1).getValue(), "10");
+        Assert.assertEquals(terms.get(1).getType(), Term.Type.or);
+    }
+
+    @Test
+    public void testNest() {
+        String expression = "name = 测试 and (age > 10 or age <= 20) and test like test2 and (age gt age2 or age btw age3,age4)";
+        System.out.println(expression);
+        List<Term> terms = TermExpressionParser.parse(expression);
+        System.out.println(JSON.toJSONString(terms, SerializerFeature.PrettyFormat));
+        Assert.assertNotNull(terms);
+        Assert.assertEquals(terms.size(), 4);
+        Assert.assertEquals(terms.get(1).getTerms().size(),2);
+        Assert.assertEquals(terms.get(0).getColumn(), "name");
+        Assert.assertEquals(terms.get(0).getValue(), "测试");
+
+        Assert.assertEquals(terms.get(1).getTerms().get(0).getColumn(), "age");
+        Assert.assertEquals(terms.get(1).getTerms().get(0).getTermType(), "gt");
+        Assert.assertEquals(terms.get(1).getTerms().get(0).getValue(), "10");
+        Assert.assertEquals(terms.get(1).getTerms().get(1).getColumn(), "age");
+        Assert.assertEquals(terms.get(1).getTerms().get(1).getTermType(), "lte");
+        Assert.assertEquals(terms.get(1).getTerms().get(1).getValue(), "20");
+        Assert.assertEquals(terms.get(1).getTerms().get(1).getType(), Term.Type.or);
+
+        Assert.assertEquals(terms.get(2).getColumn(), "test");
+        Assert.assertEquals(terms.get(2).getValue(), "test2");
+        Assert.assertEquals(terms.get(2).getTermType(), "like");
+
+
+    }
+
+}