JEXL 入门实战

打印 上一主题 下一主题

主题 840|帖子 840|积分 2520

JEXL 是一个在 Java 中实现动态表达式和脚本功能的库,本文主要介绍其基本概率和使用。
1、背景

在软件开辟中,动态执行表达式是一项非常重要的本领。特殊是在动态规则处理、配置文件剖析以及灵活的业务逻辑实现等场景下,使用一种可以大概在运行时剖析和执行表达式的工具显得尤为重要。JEXL(Java Expression Language)就是这样一种工具,它为 Java 开辟者提供了强盛的表达式和脚本处理本领。
2、简介

JEXL 实现了一种表达式语言,基于对 JSTL 表达式语言的一些扩展,支持在 shell 或 ECMAScript 中看到的大多数使用方法。
它的目标是向技能人员暴露可用于企业平台的脚本功能。在许多使用场景中,JEXL 允许应用步调的终极用户编写自己的脚本或表达式,并确保它们在受控的功能束缚内执行。
该库提供了一个小巧的 API——核心功能仅包含 3 个类和 10 个方法——可以在多种场景下使用:

  • 脚本功能    允许用户评估或定义一些简单的表达式,如盘算公式。
  • 模块或组件配置    A、在配置文件中使用变量和表达式  B、使用 IOC 很方便,但总体复杂性不需要(或不能依赖于)一个成熟的库(Spring、Guice…)
  • 接口和实现松耦合    A、有一些可选类不能作为编译时的依赖项  B、必须集成并调用“遗留”代码或者使用不想猛烈依赖的组件
  • 简单的模板功能    应用有基本的模板需求,而 JSP 或 Velocity 可能会显得过于复杂或摆设不便
JEXL 的名称代表 Java 表达式语言(Java EXpression Language),是一种简单的表达式语言,最初受到 Apache Velocity 和 JavaServer Pages 标准标签库(JSTL)1.1 版以及 JavaServer Pages 2.0 版(JSP)中定义的表达式语言的启发。受 Unified EL 启发,JEXL 2.0 引入了许多特性。其语法现在靠近 ECMAScript 和“shell 脚本”的混淆,便于技能人员掌握。
JEXL的 API 和表达式语言通过反射暴露对象属性的 getter 和 setter 方法。它还将公共类字段视为属性,并允许调用任何可访问的方法。
3、使用

3.1、引入依赖
  1. <dependency>
  2.     <groupId>org.apache.commons</groupId>
  3.     <artifactId>commons-jexl3</artifactId>
  4.     <version>3.4.0</version>
  5. </dependency>
复制代码
3.2、创建 JexlEngine
  1. @Before
  2. public void before() {
  3.     JexlFeatures features = new JexlFeatures()
  4.             .loops(true) //是否允许使用循环语句,如:for、while
  5.             .sideEffectGlobal(true) //是否允许修改全局变量
  6.             .sideEffect(true); //是否允许修改变量
  7.     engine = new JexlBuilder()
  8.             .features(features)
  9.             .strict(true)
  10.             .permissions(JexlPermissions.RESTRICTED)
  11.             .create();
  12. }
复制代码
3.3、表达式

createExpression 方法用于创建单个表达式,盘算并返回一个值。
3.3.1、简单表达式
  1. @Test
  2. public void test01() {
  3.     //都为数字,结果为:true
  4.     String expression = "money > 5000";
  5.     JexlExpression jexlExpression = engine.createExpression(expression);
  6.     JexlContext context = new MapContext();
  7.     context.set("money", 10000);
  8.     Object o = jexlExpression.evaluate(context);
  9.     System.out.println(o);
  10.     //有一个为数字,都会转成数字比较;结果为:true
  11.     expression = "money > '5000'";
  12.     jexlExpression = engine.createExpression(expression);
  13.     context = new MapContext();
  14.     context.set("money", 10000);
  15.     o = jexlExpression.evaluate(context);
  16.     System.out.println(o);
  17.     expression = "money > 5000";
  18.     jexlExpression = engine.createExpression(expression);
  19.     context = new MapContext();
  20.     context.set("money", "10000");
  21.     o = jexlExpression.evaluate(context);
  22.     System.out.println(o);
  23.     //都为字符串,结果为:false
  24.     expression = "money > '5000'";
  25.     jexlExpression = engine.createExpression(expression);
  26.     context = new MapContext();
  27.     context.set("money", "10000");
  28.     o = jexlExpression.evaluate(context);
  29.     System.out.println(o);
  30. }
复制代码
3.3.2、方法使用
  1. @Test
  2. public void test02() {
  3.     String expression = "Math.max(a, b)";
  4.     JexlExpression jexlExpression = engine.createExpression(expression);
  5.     JexlContext context = new MapContext();
  6.     context.set("Math", Math.class);
  7.     context.set("a", 6);
  8.     context.set("b", 7);
  9.     Object o = jexlExpression.evaluate(context);
  10.     System.out.println(o); //7
  11.     expression = "list.contains('a')";
  12.     jexlExpression = engine.createExpression(expression);
  13.     context = new MapContext();
  14.     List<String> list = new ArrayList<>();
  15.     list.add("a");
  16.     context.set("list", list);
  17.     o = jexlExpression.evaluate(context);
  18.     System.out.println(o); //true
  19. }
复制代码
或:
  1. @Test
  2. public void test02_2() {
  3.     Map<String, Object> map = new HashMap<>();
  4.     map.put("Math", Math.class);
  5.     List<String> list = new ArrayList<>();
  6.     list.add("a");
  7.     map.put("list", list);
  8.     JexlEngine jexlEngine = new JexlBuilder()
  9.             .namespaces(map)
  10.             .create();
  11.     String expression = "Math:max(a, b)";
  12.     JexlExpression jexlExpression = jexlEngine.createExpression(expression);
  13.     JexlContext context = new MapContext();
  14.     context.set("a", 6);
  15.     context.set("b", 7);
  16.     Object o = jexlExpression.evaluate(context);
  17.     System.out.println(o); //7
  18.     expression = "list:contains('a')";
  19.     jexlExpression = jexlEngine.createExpression(expression);
  20.     context = new MapContext();
  21.     o = jexlExpression.evaluate(context);
  22.     System.out.println(o); //true
  23. }
复制代码
3.3.3、数组操作
  1. @Test
  2. public void test03() {
  3.     String expression = "text =~ [1, 2, '吧啦吧啦']"; //是否属性数组中的一个
  4.     JexlExpression jexlExpression = engine.createExpression(expression);
  5.     JexlContext context = new MapContext();
  6.     context.set("text", "1");
  7.     Object evaluate = jexlExpression.evaluate(context);
  8.     System.out.println(evaluate); //false
  9.     context.set("text", 1);
  10.     evaluate = jexlExpression.evaluate(context);
  11.     System.out.println(evaluate); //true
  12.     //不属于数组中的任意一个
  13.     expression = "text !~ [1, 2, '吧啦吧啦']";
  14.     jexlExpression = engine.createExpression(expression);
  15.     context.set("text", "2");
  16.     evaluate = jexlExpression.evaluate(context);
  17.     System.out.println(evaluate); //true
  18.     context.set("text", 2);
  19.     evaluate = jexlExpression.evaluate(context);
  20.     System.out.println(evaluate); //false
  21. }
复制代码
3.4、脚本

createScript 方法用于创建多个语句的脚本,可能包含复杂的控制流或多个盘算,返回终极的执行结果;当然 createScript 方法也可用于表达式的盘算,但是 createExpression 方法不能用于脚本的盘算。
  1. @Test
  2. public void test04() {
  3.     String script = "money > 5000";
  4.     JexlScript jexlScript = engine.createScript(script);
  5.     JexlContext context = new MapContext();
  6.     context.set("money", 10000);
  7.     Object o = jexlScript.execute(context);
  8.     System.out.println(o); //true
  9.     script = "for (item : list) { total += item;}\n return 10;";
  10.     jexlScript = engine.createScript(script);
  11.     context = new MapContext();
  12.     context.set("list", Arrays.asList(1, 2, 3, 4, 5));
  13.     context.set("total", 0);
  14.     Object executeResult = jexlScript.execute(context);
  15.     log.info("executeResult={},total={}", executeResult, context.get("total")); //10,15
  16.     script = "for (item : list) { total += item; }\n return 10;";
  17.     jexlScript = engine.createScript(script, "list", "total");
  18.     context = new MapContext();
  19.     executeResult = jexlScript.execute(context, Arrays.asList(1, 2, 3, 4, 5), 0);
  20.     log.info("executeResult={}", executeResult); //10
  21. }
复制代码
3.5、完备代码

  1. package com.abc.demo.jexl;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.apache.commons.jexl3.*;
  4. import org.apache.commons.jexl3.introspection.JexlPermissions;
  5. import org.junit.Before;
  6. import org.junit.Test;
  7. import java.util.*;
  8. @Slf4j
  9. public class JexlCase {
  10.     private JexlEngine engine;
  11.     @Before
  12.     public void before() {
  13.         JexlFeatures features = new JexlFeatures()
  14.                 .loops(true) //是否允许使用循环语句,如:for、while
  15.                 .sideEffectGlobal(true) //是否允许修改全局变量
  16.                 .sideEffect(true); //是否允许修改变量
  17.         engine = new JexlBuilder()
  18.                 .features(features)
  19.                 .strict(true)
  20.                 .permissions(JexlPermissions.RESTRICTED)
  21.                 .create();
  22.     }
  23.     @Test
  24.     public void test01() {
  25.         //都为数字,结果为:true
  26.         String expression = "money > 5000";
  27.         JexlExpression jexlExpression = engine.createExpression(expression);
  28.         JexlContext context = new MapContext();
  29.         context.set("money", 10000);
  30.         Object o = jexlExpression.evaluate(context);
  31.         System.out.println(o);
  32.         //有一个为数字,都会转成数字比较;结果为:true
  33.         expression = "money > '5000'";
  34.         jexlExpression = engine.createExpression(expression);
  35.         context = new MapContext();
  36.         context.set("money", 10000);
  37.         o = jexlExpression.evaluate(context);
  38.         System.out.println(o);
  39.         expression = "money > 5000";
  40.         jexlExpression = engine.createExpression(expression);
  41.         context = new MapContext();
  42.         context.set("money", "10000");
  43.         o = jexlExpression.evaluate(context);
  44.         System.out.println(o);
  45.         //都为字符串,结果为:false
  46.         expression = "money > '5000'";
  47.         jexlExpression = engine.createExpression(expression);
  48.         context = new MapContext();
  49.         context.set("money", "10000");
  50.         o = jexlExpression.evaluate(context);
  51.         System.out.println(o);
  52.     }
  53.     @Test
  54.     public void test02() {
  55.         String expression = "Math.max(a, b)";
  56.         JexlExpression jexlExpression = engine.createExpression(expression);
  57.         JexlContext context = new MapContext();
  58.         context.set("Math", Math.class);
  59.         context.set("a", 6);
  60.         context.set("b", 7);
  61.         Object o = jexlExpression.evaluate(context);
  62.         System.out.println(o); //7
  63.         expression = "list.contains('a')";
  64.         jexlExpression = engine.createExpression(expression);
  65.         context = new MapContext();
  66.         List<String> list = new ArrayList<>();
  67.         list.add("a");
  68.         context.set("list", list);
  69.         o = jexlExpression.evaluate(context);
  70.         System.out.println(o); //true
  71.     }
  72.     @Test
  73.     public void test02_2() {
  74.         Map<String, Object> map = new HashMap<>();
  75.         map.put("Math", Math.class);
  76.         List<String> list = new ArrayList<>();
  77.         list.add("a");
  78.         map.put("list", list);
  79.         JexlEngine jexlEngine = new JexlBuilder()
  80.                 .namespaces(map)
  81.                 .create();
  82.         String expression = "Math:max(a, b)";
  83.         JexlExpression jexlExpression = jexlEngine.createExpression(expression);
  84.         JexlContext context = new MapContext();
  85.         context.set("a", 6);
  86.         context.set("b", 7);
  87.         Object o = jexlExpression.evaluate(context);
  88.         System.out.println(o); //7
  89.         expression = "list:contains('a')";
  90.         jexlExpression = jexlEngine.createExpression(expression);
  91.         context = new MapContext();
  92.         o = jexlExpression.evaluate(context);
  93.         System.out.println(o); //true
  94.     }
  95.     @Test
  96.     public void test03() {
  97.         String expression = "text =~ [1, 2, '吧啦吧啦']"; //是否属性数组中的一个
  98.         JexlExpression jexlExpression = engine.createExpression(expression);
  99.         JexlContext context = new MapContext();
  100.         context.set("text", "1");
  101.         Object evaluate = jexlExpression.evaluate(context);
  102.         System.out.println(evaluate); //false
  103.         context.set("text", 1);
  104.         evaluate = jexlExpression.evaluate(context);
  105.         System.out.println(evaluate); //true
  106.         //不属于数组中的任意一个
  107.         expression = "text !~ [1, 2, '吧啦吧啦']";
  108.         jexlExpression = engine.createExpression(expression);
  109.         context.set("text", "2");
  110.         evaluate = jexlExpression.evaluate(context);
  111.         System.out.println(evaluate); //true
  112.         context.set("text", 2);
  113.         evaluate = jexlExpression.evaluate(context);
  114.         System.out.println(evaluate); //false
  115.     }
  116.     @Test
  117.     public void test04() {
  118.         String script = "money > 5000";
  119.         JexlScript jexlScript = engine.createScript(script);
  120.         JexlContext context = new MapContext();
  121.         context.set("money", 10000);
  122.         Object o = jexlScript.execute(context);
  123.         System.out.println(o); //true
  124.         script = "for (item : list) { total += item;}\n return 10;";
  125.         jexlScript = engine.createScript(script);
  126.         context = new MapContext();
  127.         context.set("list", Arrays.asList(1, 2, 3, 4, 5));
  128.         context.set("total", 0);
  129.         Object executeResult = jexlScript.execute(context);
  130.         log.info("executeResult={},total={}", executeResult, context.get("total")); //10,15
  131.         script = "for (item : list) { total += item; }\n return 10;";
  132.         jexlScript = engine.createScript(script, "list", "total");
  133.         context = new MapContext();
  134.         executeResult = jexlScript.execute(context, Arrays.asList(1, 2, 3, 4, 5), 0);
  135.         log.info("executeResult={}", executeResult); //10
  136.     }
  137. }
复制代码
JexlCase.java 
 
参考:
https://commons.apache.org/proper/commons-jexl/
 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

小小小幸运

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表