# Simply Expression Language
**Repository Path**: fanjr/simplify-el
## Basic Information
- **Project Name**: Simply Expression Language
- **Description**: 简易表达式(simply-el),旨在解决判断、计算、取值、结构转换这些逻辑简单但编码繁复的工作
- **Primary Language**: Java
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 4
- **Forks**: 1
- **Created**: 2023-02-02
- **Last Updated**: 2025-07-14
## Categories & Tags
**Categories**: Uncategorized
**Tags**: 表达式, el, expression-language
## README
# Simply Expression Language
##### [📖 English Documentation](README_en.md) | 📖 中文文档
[](https://openjdk.java.net/)
[](https://github.com/FanJiaRui/Simply-Expression-Language/releases)
[](https://search.maven.org/artifact/net.fanjr.simplify/simplify-el)
[](https://www.apache.org/licenses/LICENSE-2.0.html)
## 介绍
简易表达式,旨在解决判断、计算、取值、结构转换这些逻辑简单但编码繁复的工作
主要应用场景:动态规则的计算场景、类型适配(报文转换),可以配合调度类、流程类引擎的动态计算
## 环境&依赖
* JDK 1.8
* fastjson2 2.0.56
* slf4j 1.7.30
## 特性
- 支持层级结构:快速操作、转换JSON或各类POJO等
- 安全取值:告别频繁繁琐的空判断
- 分支逻辑:支持复杂的复合语句,支持if else/for等相关分支语法
- 方法调用:可以直接调用对象方法,支持自定义工具方法
- 使用便捷:无需额外构建上下文对象进行运算,直接通过API计算原生对象
## 引入配置
由于org域名国内不大好续期,后续版本均更换为net域名
#### 新版本依赖(1.1.1之后)
```xml
net.fanjr.simplify
simplify-el
1.3.1
```
#### 老版本依赖(1.1.0之前)
```xml
org.fanjr.simplify
simplify-el
1.1.0
```
## 文档
**↓↓↓↓↓**
[**点这里**](docs/document.md)查看详细文档
**↑↑↑↑↑**
## 功能点介绍
- 简单表达式计算、占位符计算、四则运算、正则匹配
- 支持赋值运算、类型转换,可支撑JSON格式转换等场景
- 支持复杂语句,多语句复合混用
- 支持java对象方法调用、自定义函数方法调用
- 支持条件分支、三元表达式、循环
## 表达式调用样例
``` java
// 基本调用样例
boolean result = ELExecutor.eval(
// 表达式字符串,复合语句用;隔开,返回最后执行的语句结果
"a==100",
// 预期计算的上下文或者对象,主要支持javabean、Map、字符串等等
"{'a':100}",
// 预期返回类型,支持泛型
boolean.class);
Assertions.assertTrue(result);
// 四则运算样例
int result = ELExecutor.eval("2 * a - (b + c) * d", "{'a':1,'b':2,'c':3,'d':4}", int.class);
// 2*1-(2+3)*4 = -18
Assertions.assertEquals(-18, result);
// 赋值&计算样例
Map context = new HashMap<>();
context.put("val", 10);
ELExecutor.eval("a=10;val=val+1;val++;result=a+val;", context);
// a=10;
Assertions.assertEquals(10, ElUtils.cast(context.get("a"), int.class));
// val=val+1;val++;
Assertions.assertEquals(12, ElUtils.cast(context.get("val"), int.class));
// result=a+val;
Assertions.assertEquals(22, ElUtils.cast(context.get("result"), int.class));
// 通过表达式给POJO中子对象属性赋值
TestReq req = new TestReq();
ELExecutor.eval("head.serialId='123456'", req);
System.out.println(req.getHead().getSerialId());
// 调用java方法
Map context = new HashMap<>();
context.put("val", "010");
// 将字符串"010"转换为int类型,调用toString()方法,再调用length()方法,预期返回值为2
Assertions.assertEquals(2, ELExecutor.eval("((int)val).toString().length()", context, int.class));
```
## 三元表达式
``` java
Map context = new HashMap<>();
context.put("flag", 100);
context.put("val", 10);
// flag满足大于等于100,返回val*10,这里结果是100
Assertions.assertEquals(100, ELExecutor.eval("flag>=100?val*10:val/10", context, int.class));
// flag不满足小于100,返回val/10,这里结果是1
Assertions.assertEquals(1, ELExecutor.eval("flag<100?val*10:val/10", context, int.class));
```
## 正则匹配
``` java
Assertions.assertTrue(ELExecutor.eval("18888888888 ~= '^[0-9]{11}$'", null, boolean.class));
Assertions.assertTrue(ELExecutor.eval("phone ~= '^[0-9]{11}$'", JSONObject.of("phone","18888888888"), boolean.class));
Assertions.assertFalse(ELExecutor.eval("phone ~= '^[0-9]{11}$'", JSONObject.of("phone","18888xx8888"), boolean.class));
```
## if-else分支语法
``` java
// 创建计算用的上下文
Map context = new HashMap<>();
// 分支1(IF) a=1
context.put("flag", 1);
ELExecutor.eval("if(flag==1){\n a=1;\n }", context);
Assertions.assertEquals(ElUtils.cast(context.get("a"), int.class), 1);
context.clear();
// 分支2(IF-ELSE-IF) a=3
context.put("flag", 2);
ELExecutor.eval("if(flag==1){a=1; }else if(flag==2){ a=2;a++; }", context);
Assertions.assertEquals(ElUtils.cast(context.get("a"), int.class), 3);
context.clear();
// 分支3(IF-ELSE-IF-ELSE) a=0
context.put("flag", 3);
ELExecutor.eval("if(flag==1){\n a=1;\n }else if(flag==2){ a=2;a++; }else{ a=0; }", context);
Assertions.assertEquals(ElUtils.cast(context.get("a"), int.class), 0);
context.clear();
```
## for循环语法
``` java
// 对照组:java代码循环
int[] arr = new int[10];
for (int i = 0; i < 10; i++) {
arr[i] = 3 * (i + 1234) - i;
}
// 创建计算用的上下文
Map context = new HashMap<>();
// 类C模式
ELExecutor.eval("for(i=0;i<10;i++){arr[i]=3 * (i + 1234) - i}", context);
// 计算结果正确性断言
Assertions.assertArrayEquals(arr, ElUtils.cast(context.get("arr"), int[].class));
context.clear();
// 迭代器模式,可以遍历数组、List、Map等等
context.put("num", new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9});
ELExecutor.eval("for(i:num){arr[i]=3 * (i + 1234) - i}", context);
// 计算结果正确性断言
Assertions.assertArrayEquals(arr, ElUtils.cast(context.get("arr"), int[].class));
context.clear();
// 数字模式 等价于i=0;i<10;i++
ELExecutor.eval("for(i:10){arr[i]=3 * (i + 1234) - i}", context);
// 计算结果正确性断言
Assertions.assertArrayEquals(arr, ElUtils.cast(context.get("arr"), int[].class));
context.clear();
// 嵌套循环将结果输出到控制台,输出九九乘法表
ELExecutor.eval(" " +
"for(i=1;i<=9;i++){" +
" for(j=1;j<=9;j++){" +
" $.printf(i+'*'+j+'='+(i*j)+'\t');" +
" }" +
" $.printf('\n')" +
"}" ,
new HashMap<>());
```
## 自定义函数&内置函数
### 自定义函数扩展
```properties
# 在META-INF目录下新建simplify-el.functions,添加Function挂载
# 工具名=类全限定名,多个类用','隔开,会将这些类中所有public static方法收集并挂载到工具名下
# 同一个工具名下方法名+参数表相同的方法根据@ELMethod中的order属性进行排序生效,order数字小的优先级高
$=net.fanjr.simplify.el.InnerFunctions
```
以下为`InnerFunctions`内容,表达式中通过工具名+方法名对其调用。
例如:`$.println('hello world')`
```java
public class InnerFunctions {
// 省略了一些不重要的内容
/**
* 控制台输出
* $.println(xxxxx)
*/
@ELMethod(order = Integer.MAX_VALUE)
public static void println(Object object) {
System.out.println(object);
}
}
```
### 内置函数
- `$.println(xxxx)` 将传入对象输出到控制台
- `$.printf(xxxx)` 将传入对象输出到控制台(结尾不换行)
- `$.log(xxxx)` 将传入对象用日志框架输出到控制台和日志文件
- `$.max(a,b)` 比较a,b的大小,返回更大的
- `$.min(a,b)` 比较a,b的大小,返回更小的
- `$.merge([map1,map2,map3...])` 深度合并多个map
- `$.getEnumMap(xx)` 获取枚举映射MAP
## 后续规划
- 分析JAVA自带库方法,考虑部分可能经常使用的方法集成到内置函数中
- 持续优化使用方式,考虑添加部分工具类