Jelajahi Sumber

优化表达式解析

zhou-hao 5 tahun lalu
induk
melakukan
cd2e478bac

+ 26 - 18
hsweb-core/src/main/java/org/hswebframework/web/utils/ExpressionUtils.java

@@ -1,5 +1,7 @@
 package org.hswebframework.web.utils;
 
+import lombok.SneakyThrows;
+import org.apache.commons.codec.digest.DigestUtils;
 import org.hswebframework.expands.script.engine.DynamicScriptEngine;
 import org.hswebframework.expands.script.engine.DynamicScriptEngineFactory;
 import org.hswebframework.expands.script.engine.ExecuteResult;
@@ -70,31 +72,37 @@ public class ExpressionUtils {
      * @param vars       变量
      * @param language   表达式语言
      * @return 解析结果
-     * @throws Exception 解析错误
      */
-    public static String analytical(String expression, Map<String, Object> vars, String language) throws Exception {
-        Matcher matcher = PATTERN.matcher(expression);
+    @SneakyThrows
+    public static String analytical(String expression, Map<String, Object> vars, String language) {
+        if(!expression.contains("${")){
+            return expression;
+        }
         DynamicScriptEngine engine = DynamicScriptEngineFactory.getEngine(language);
         if (engine == null) {
             return expression;
         }
-        vars = new HashMap<>(vars);
-        vars.putAll(getDefaultVar());
-        while (matcher.find()) {
-            String real_expression = matcher.group();
-            String e_id = String.valueOf(real_expression.hashCode());
-            if (!engine.compiled(e_id)) {
-                engine.compile(e_id, real_expression);
+
+        return TemplateParser.parse(expression, var -> {
+            Object fast = vars.get(var);
+            if (fast != null) {
+                return fast.toString();
             }
-            ExecuteResult result = engine.execute(e_id, vars);
-            if (!result.isSuccess()) {
-                throw new RuntimeException(result.getMessage(), result.getException());
+            String id = DigestUtils.md5Hex(var);
+
+            try {
+                if (!engine.compiled(id)) {
+
+                    engine.compile(id, var);
+
+                }
+                return String.valueOf(engine.execute(id, vars).getIfSuccess());
+            } catch (RuntimeException e) {
+                throw e;
+            } catch (Exception e) {
+                throw new RuntimeException(e);
             }
-            String obj = String.valueOf(result.get());
-            // expression = matcher.replaceFirst(obj);
-            expression = expression.replace("${" + real_expression + "}", obj);
-        }
-        return expression;
+        });
     }
 
 }

+ 141 - 0
hsweb-core/src/main/java/org/hswebframework/web/utils/TemplateParser.java

@@ -0,0 +1,141 @@
+package org.hswebframework.web.utils;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.beanutils.BeanUtilsBean;
+
+import java.util.Arrays;
+import java.util.function.Function;
+
+
+@Slf4j
+public class TemplateParser {
+    private static final char[] DEFAULT_PREPARE_START_SYMBOL = "${".toCharArray();
+
+    private static final char[] DEFAULT_PREPARE_END_SYMBOL = "}".toCharArray();
+
+    @Getter
+    @Setter
+    private char[] prepareStartSymbol = DEFAULT_PREPARE_START_SYMBOL;
+
+    @Getter
+    @Setter
+    private char[] prepareEndSymbol = DEFAULT_PREPARE_END_SYMBOL;
+
+    @Getter
+    @Setter
+    private String template;
+
+    @Getter
+    @Setter
+    private Object parameter;
+
+    private char[] templateArray;
+
+    private int pos;
+
+    private char symbol;
+
+    private char[] newArr;
+
+    private int len = 0;
+
+    public void setParsed(char[] chars, int end) {
+        for (int i = 0; i < end; i++) {
+            char aChar = chars[i];
+            if (newArr.length <= len) {
+                newArr = Arrays.copyOf(newArr, len + templateArray.length);
+            }
+            newArr[len++] = aChar;
+        }
+
+    }
+
+    public void setParsed(char... chars) {
+       setParsed(chars,chars.length);
+    }
+
+    private void init() {
+        templateArray = template.toCharArray();
+        pos = 0;
+        newArr = new char[templateArray.length * 2];
+    }
+
+    private boolean isPrepare() {
+        for (char c : prepareStartSymbol) {
+            if (c == symbol) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean isPrepareEnd() {
+        for (char c : prepareEndSymbol) {
+            if (c == symbol) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean next() {
+        symbol = templateArray[pos++];
+        return pos < templateArray.length;
+    }
+
+
+    public String parse(Function<String, String> propertyMapping) {
+        init();
+        boolean inPrepare = false;
+
+        char[] expression = new char[128];
+        int expressionPos = 0;
+
+        while (next()) {
+            if (isPrepare()) {
+                inPrepare = true;
+            } else if (isPrepareEnd()) {
+                inPrepare = false;
+
+
+                setParsed(propertyMapping.apply(new String(expression, 0, expressionPos)).toCharArray());
+                expressionPos = 0;
+            } else if (inPrepare) {
+                expression[expressionPos++] = symbol;
+            } else {
+                setParsed(symbol);
+            }
+        }
+
+        if (isPrepareEnd()) {
+
+            setParsed(propertyMapping.apply(new String(expression, 0, expressionPos)).toCharArray());
+
+        } else {
+            setParsed(symbol);
+        }
+
+        return new String(newArr, 0, len);
+    }
+
+
+    public static String parse(String template, Object parameter) {
+        return parse(template, var -> {
+
+            try {
+                return BeanUtilsBean.getInstance().getProperty(parameter, var);
+            } catch (Exception e) {
+                log.warn(e.getMessage(), e);
+            }
+            return "";
+        });
+    }
+
+    public static String parse(String template, Function<String, String> parameterGetter) {
+        TemplateParser parser = new TemplateParser();
+        parser.template = template;
+        return parser.parse(parameterGetter);
+    }
+}

+ 32 - 0
hsweb-core/src/test/java/org/hswebframework/web/utils/ExpressionUtilsTest.java

@@ -0,0 +1,32 @@
+package org.hswebframework.web.utils;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.Collections;
+
+
+public class ExpressionUtilsTest {
+
+
+    @Test
+    public void test() {
+        String expression = ExpressionUtils.analytical("test-${#name}", Collections.singletonMap("name", "test"), "spel");
+
+        Assert.assertEquals(expression,"test-test");
+
+        String res = ExpressionUtils.analytical("test-${3+2}", Collections.singletonMap("name", "test"), "spel");
+
+        Assert.assertEquals(res,"test-5");
+    }
+
+    @Test
+    public void testComplete(){
+
+        TemplateParser.parse("${#data[payload][a_name]} ${#data[payload][b_name]} 发生 ${#data[payload][alarm_type_name]}",e->{
+            System.out.println(e);
+            return e;
+        });
+
+    }
+}

+ 33 - 0
hsweb-core/src/test/java/org/hswebframework/web/utils/TemplateParserTest.java

@@ -0,0 +1,33 @@
+package org.hswebframework.web.utils;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.Collections;
+
+import static org.junit.Assert.*;
+
+public class TemplateParserTest {
+
+
+    @Test
+    public void test() {
+
+        String result = TemplateParser.parse("test-${name}-${name}", Collections.singletonMap("name", "test"));
+
+        Assert.assertEquals(result, "test-test-test");
+    }
+
+    @Test
+    public void testLarge() {
+        String str = "";
+        for (int i = 0; i < 1000; i++) {
+            str += "test-" + i;
+        }
+        String result = TemplateParser.parse("test-${name}", Collections.singletonMap("name", str));
+
+        Assert.assertEquals(result, "test-" + str);
+    }
+
+
+}