【解决方案】 Commons JEXL3、Spel 表达式实现自定义计算规则

1,350 阅读2分钟

Commons JEXL3

Commons JEXL3支持更广泛的表达式语法,包括算术运算、逻辑运算、条件语句等。而SpEL主要关注于简化访问对象属性和方法的操作。

  1. 首先,将 Commons JEXL3 的依赖项添加到项目的构建工具(如 Maven 或 Gradle)中。以下是 Maven 的依赖项示例:
        
xml复制代码运行
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-jexl3</artifactId>
    <version>3.2.0</version>
</dependency>


    

对于 Gradle,添加以下依赖项:

implementation 'org.apache.commons:commons-jexl3:3.2.0'
import org.apache.commons.jexl3.*;

public class JexlExample {
    public static void main(String[] args) {
        JexlEngine jexl = new JexlBuilder().create();
        JexlExpression expression = jexl.createExpression("a + b");
        JexlContext context = new MapContext();
        context.set("a", 5);
        context.set("b", 3);
        Object result = expression.evaluate(context);
        System.out.println("Result: " + result); // 输出:Result: 8
    }
}

自定义的函数支持办法

在 Commons JEXL3 中,JexlEngine 默认不支持幂运算,因为它不包含用于幂运算的内置函数或操作符。然而,你可以通过自定义函数来实现幂运算。 在 Commons JEXL3 中,JexlEngine 也不支持<< 左移


import org.apache.commons.jexl3.*;
public class JexlExample {
    public static void main(String[] args) {
        // 创建一个 JexlEngine 实例
        JexlEngine jexl = new JexlBuilder().create();

        // 注册自定义的幂运算函数
        jexl.getGrammar().registerFunction("power", new CustomPowerFunction());

        // 定义一个表达式,使用自定义的幂运算函数
        String expression = "power(2, 3)";

        // 创建一个 JexlContext
        JexlContext context = new MapContext();

        // 解析表达式
        JexlExpression jexlExpression = jexl.createExpression(expression);

        // 执行表达式并获取结果
        Object result = jexlExpression.evaluate(context);

        // 输出结果
        System.out.println(result); // 输出:8.0
    }

    // 自定义幂运算函数
    static class CustomPowerFunction implements JexlArithmetic {
        @Override
        public Object execute(JexlContext context, JexlInfo info) throws Exception {
            if (info.getArgCount() != 2) {
                throw new IllegalArgumentException("power function requires exactly two arguments");
            }
            double base = info.getArg(0).toNumber().doubleValue();
            double exponent = info.getArg(1).toNumber().doubleValue();
            return Math.pow(base, exponent);
        }
    }
}

Spel

SpEL(Spring Expression Language)的语法包括以下几种基本表达式:

字面量表达式:

支持的字面量类型包括:字符串、数字(int、long、float、double)、布尔类型、null类型。 示例:'Hello World', 42, 3.14, true, null。 算数运算表达式:

支持的运算符包括:加(+)、减(-)、乘(*)、除(/)、求余(%)、幂(^)。 还提供了求余(MOD)和除(DIV)两个额外运算符,它们与“%”和“/”是等价的,且不区分大小写。 示例:4 + 5, 10 - 3, 2 * 7, 14 / 2, 21 % 3, 2 ^ 3。 关系表达式:

支持的关系运算符包括:等于(==)、不等于(!=)、大于(>)、大于等于(>=)、小于(<)、小于等于(<=)。 示例:4 > 3, 2 != 5, 10 >= 10, 1 <= 2。 逻辑表达式:

支持的逻辑运算符包括:AND(&&)、OR(||)、NOT(!)。 示例:(a > b) && (c < d), (x == y) || (z != w), !isTrue。

注意: SpEL 不支持 &位运算符

代码示例

import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

public class SpELExample {
    public static void main(String[] args) {
        // 创建一个对象
        Person person = new Person("张三", 25);

        // 创建SpEL解析器
        ExpressionParser parser = new SpelExpressionParser();

        // 创建评估上下文,并将对象添加到上下文中
        StandardEvaluationContext context = new StandardEvaluationContext();
        context.setVariable("person", person);

        // 解析表达式并计算结果
        String expression = "#person?.name";
        String name = parser.parseExpression(expression).getValue(context, String.class);
        System.out.println("姓名: " + name);

        expression = "#person?.age > 18";
        boolean isAdult = parser.parseExpression(expression).getValue(context, Boolean.class);
        System.out.println("是否成年: " + isAdult);
    }
}

class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}