Solon v3.1.0

solon-expression [预览]

</> markdown
<dependency>
    <groupId>org.noear</groupId>
    <artifactId>solon-expression</artifactId>
    <version>3.1.1-SNAPSHOT</version>
</dependency>

1、描述

基础扩展插件。为 Solon 提供了一套表达式通用接口。并内置 Solon Expression Language(简称,SnEL)“求值”表达式实现方案。纯 Java 代码实现,零依赖(可用于其它任何框架)。编译后为 30KB 多点儿。

解析后会形成一个表达式“树结构”。可做为中间 DSL,按需转换为其它表达式(比如 redis、milvus 的过滤表达式)

主要特点:

  • 总会输出一个结果(“求值”表达式嘛)
  • 通过上下文传递变量
  • 只能有一条表达式语句(即不能有 ; 号)
  • 不支持控制运算(即不能有 iffor 之类的),不能当脚本用。
  • 对象字段、属性、方法调用。可多层嵌套,但只支持 public(相对更安全些)
  • 支持模板表达式

如果有脚本需求,可用:Liquor!

2、简单示例

你好世界:

System.out.println(SnEL.eval("'hello world!'"));

SnELSnelEvaluator.getInstance() 快捷方式。可以直接使用 SnEL ,也可以按需实例化 SnelEvaluator

3、能力说明

能力示例备注
支持常量获取1, 'name', true, [1,2,3]数字、字符串、布尔、数组
支持变量获取name
支持字典获取map['name']
支持集合获取list[0]
支持对象属性或字段获取user.name, user['name']支持.[]
支持对象方法获取order.getUser(), list[0].getUser().getName()支持多级嵌套
支持对象静态方法获取Math.add(1, 2), Math.add(a, b)支持多级嵌套
支持优先级小括号(, )
支持算数操作符+, -, *, /, %加,减,乘,除,模
支持比较操作符<, <=, >, >=, ==, !=结果为布尔
支持like操作符LIKE, NOT LIKE(在相当于包含)结果为布尔
支持in操作符IN, NOT IN结果为布尔
支持三元逻辑操作符conditionExpr ? trueExpr: falseExpr
支持二元逻辑操作符AND, OR
支持一元逻辑操作符NOT

关键字须使用全大写(未来还可能会增多):

LIKE, NOT LIKE, IN, NOT IN ,AND, OR ,NOT

数据类型与符号说明:

1.1F(单精度)、1.1D(双精度)、1L(长整型)。1.1(双精度)、1(整型)

预留特殊符号:

#{ }, ${ }

4、表达式示例

  • 常量与算数表达式
System.out.println(SnEL.eval("1"));
System.out.println(SnEL.eval("-1"));
System.out.println(SnEL.eval("1 + 1"));
System.out.println(SnEL.eval("1 * (1 + 2)"));
System.out.println(SnEL.eval("'solon'"));
System.out.println(SnEL.eval("true"));
System.out.println(SnEL.eval("[1,2,3,-4]"));
  • 变量,字典,集合获取
Map<String, String> map = new HashMap<>();
map.put("code", "world");

List<Integer> list = new ArrayList<>();
list.add(1);

Map<String, Object> context = new HashMap<>();
context.put("name", "solon");
context.put("list", list);
context.put("map", map);

System.out.println(SnEL.eval("name.length()", context)); //顺便调用个函数
System.out.println(SnEL.eval("name.length() > 2 OR true", context)); 
System.out.println(SnEL.eval("name.length() > 2 ? 'A' : 'B'", context)); 
System.out.println(SnEL.eval("map['code']", context));
System.out.println(SnEL.eval("list[0]", context));
System.out.println(SnEL.eval("list[0] == 1", context));
  • 带优化级的复杂逻辑表达式
Map<String, Object> context = new HashMap<>();
context.put("age", 25);
context.put("salary", 4000);
context.put("isMarried", false);
context.put("label", "aa");
context.put("title", "ee");
context.put("vip", "l3");

String expression = "(((age > 18 AND salary < 5000) OR (NOT isMarried)) AND label IN ['aa','bb'] AND title NOT IN ['cc','dd']) OR vip=='l3'";
System.out.println(SnEL.eval(expression, context));
  • 静态函数调用表达式
Map<String, Object> context = new HashMap<>();
context.put("Math", Math.class);
System.out.println(SnEL.eval("Math.abs(-5) > 4 ? 'A' : 'B'", context));

5、嵌入对象(仅为示例)

Map<String, Object> context = new HashMap<>();
context.put("Solon", Solon.class);
context.put("_sysProps", Solon.cfg()); //顺便别的对象(供参考)
context.put("_sysEnv", System.getenv());

//顺便用三元表达式,模拟下 if 语法
String expr = "Solon.cfg().getInt('demo.type', 0) > _sysProps.getInt('') ? Solon.context().getBean('logService').log(1) : 0";
System.out.println(SnEL.eval(expr, context));

6、模板表达式

占位符说明

接口描述
#{...}求职表达式占位符
${..}属性表达式占位符(参考 Solon.cfg() 的 getByExpr 接口,支持默认值表达)

应用示例

Map<String, Object> context = new HashMap<>();
context.put("a", 1);
context.put("b", 1);

SnEL.evalTmpl("sum val is #{a + b},  c prop is ${demo.c:c}");

7、SnEL 快捷方式接口

接口描述
parse(...)解析求职表达式
eval(...)评估求职表达式
parseTmpl(...)解析模板表达式
evalTmpl(...)评估模板表达式
/**
 * Solon 表达式语言引擎快捷方式(简称,SnEL)
 */
public interface SnEL {
    /**
     * 解析(将文本解析为一个可评估的表达式结构树,可反向转换)
     */
    static Expression parse(String expr, boolean cached) {
        return SnelEvaluateParser.getInstance().parse(expr, cached);
    }

    static Expression parse(String expr) {
        return parse(expr, true);
    }


    /// /////////////////


    /**
     * 评估
     *
     * @param expr    表达式
     * @param context 上下文
     * @param cached  是否带编译缓存
     */
    static Object eval(String expr, Function context, boolean cached) {
        return parse(expr, cached).eval(context);
    }

    /**
     * 评估
     *
     * @param expr    表达式
     * @param context 上下文
     * @param cached  是否带编译缓存
     */
    static Object eval(String expr, Map context, boolean cached) {
        return eval(expr, context::get, cached);
    }


    /**
     * 评估(带编译缓存)
     *
     * @param expr    表达式
     * @param context 上下文
     */
    static Object eval(String expr, Function context) {
        return eval(expr, context, true);
    }

    /**
     * 评估(带编译缓存)
     *
     * @param expr    表达式
     * @param context 上下文
     */
    static Object eval(String expr, Map context) {
        return eval(expr, context, true);
    }

    /**
     * 评估(带编译缓存)
     *
     * @param expr 表达式
     */
    static Object eval(String expr) {
        return eval(expr, Collections.EMPTY_MAP, true);
    }

    /// /////////////////////////////

    /**
     * 上下文中的属性键(用于支持属性表达式)
     */
    static final String CONTEXT_PROPS_KEY = "$PROPS";


    /**
     * 解析模板
     */
    static Expression<String> parseTmpl(String expr, boolean cached) {
        return SnelTemplateParser.getInstance().parse(expr, cached);
    }

    static Expression<String> parseTmpl(String expr) {
        return parseTmpl(expr, true);
    }

    /// /////////////////


    /**
     * 评估模板
     *
     * @param expr    表达式
     * @param context 上下文
     * @param cached  是否带编译缓存
     */
    static String evalTmpl(String expr, Function context, boolean cached) {
        return parseTmpl(expr, cached).eval(context);
    }

    /**
     * 评估模板
     *
     * @param expr    表达式
     * @param context 上下文
     * @param cached  是否带编译缓存
     */
    static String evalTmpl(String expr, Map context, boolean cached) {
        return evalTmpl(expr, context::get, cached);
    }


    /**
     * 评估模板(带编译缓存)
     *
     * @param expr    表达式
     * @param context 上下文
     */
    static String evalTmpl(String expr, Function context) {
        return evalTmpl(expr, context, true);
    }

    /**
     * 评估模板(带编译缓存)
     *
     * @param expr    表达式
     * @param context 上下文
     */
    static String evalTmpl(String expr, Map context) {
        return evalTmpl(expr, context, true);
    }

    /**
     * 评估模板(带编译缓存)
     *
     * @param expr 表达式
     */
    static String evalTmpl(String expr) {
        return evalTmpl(expr, Collections.EMPTY_MAP, true);
    }
}