# magic-script
**Repository Path**: ssssssss-team/magic-script
## Basic Information
- **Project Name**: magic-script
- **Description**: magic-script是一款基于JVM的脚本语言,目前主要是为magic-api项目设计
- **Primary Language**: Java
- **License**: MIT
- **Default Branch**: asm
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 448
- **Forks**: 376
- **Created**: 2020-06-30
- **Last Updated**: 2025-06-14
## Categories & Tags
**Categories**: scripting-language
**Tags**: None
## README
# magic-script
## 介绍
`magic-script`是一款基于JVM的脚本语言,目前主要是为`magic-api`项目设计。
## 应用案例
- [magic-api,接口快速开发框架,通过Web页面配置,自动映射为HTTP接口](https://gitee.com/ssssssss-team/magic-api)
- [spider-flow,新一代爬虫平台,以图形化方式定义爬虫流程,不写代码即可完成爬虫](https://gitee.com/ssssssss-team/spider-flow)
## 脚本语法
### 关键字
关键字 |
含义 |
var |
定义变量 |
if |
用在条件语句中,表明当条件不成立时的分支 |
for |
循环语句 |
in |
与 for 配合使用 |
continue |
执行下一次循环 |
break |
跳出循环 |
return |
终止当前过程的执行并正常退出到上一个执行过程中 |
exit |
终止当前脚本,并退出返回,如exit 200,'执行成功',[1,2,3]; (v0.5.0中新增) |
try |
用于捕获可能发生异常的代码块 |
catch |
与 try 关键字配合使用,当发生异常时执行 |
finally |
与 try 关键字配合使用,finally 块无论发生异常都会执行 |
import |
导入 Java 类或导入已定义好的模块 |
as |
与 import 关键字配合使用,用作将导入的 Java类或模块 命名为一个本地变量名 |
new |
创建对象 |
true |
基础类型之一,表示 Boolean 的:真值 |
false |
基础类型之一,表示 Boolean 的:假值 |
null |
基础类型之一,表示 NULL 值 |
async |
异步调用 |
### 运算符
数学运算 |
比较运算 |
逻辑运算 |
+ |
加法 |
< |
小于 |
&& |
并且 |
- |
减法 |
<= |
小于等于 |
|| |
或者 |
* |
乘法 |
> |
大于 |
|
|
/ |
除法 |
>= |
大于等于 |
|
|
% |
取模 |
== |
等于 |
|
|
++ |
自增 |
!= |
不等于 |
|
|
-- |
自减 |
=== |
等于 |
|
|
|
|
!== |
不等于 |
|
|
### 类型
类型 |
写法 |
byte |
`123b`、`123B` |
short |
`123s`、`123S` |
int |
`123` |
long |
`123l`、`123L` |
float |
`123f`、`123F` |
double |
`123d`、`123D` |
BigDecimal |
`123m`、`123M` |
boolean |
`true`、`false` |
string |
`'hello'` |
string |
`"hello"` |
string |
`"""多行文本块,主要用于编写SQL"""` |
Pattern |
/\d+/g`,`/pattern/gimuy 用于定义正则,v0.5.0中新增 |
lambda |
`()=>expr`、`(param1,param2....)=>{...}` |
list |
`[1,2,3,4,5]` |
map |
{key : value,key1 : value} |
`{[key] : "value"}` `[key]`表示动态从变量中获取key值 |
### 一元运算符
您可以通过一元运算`-`符将数字取反,例如`-234`。要取反布尔表达式,可以使用`!`运算符,例如`!true`。
自增/自减 `i++` 、 `++i`、`i--`、`--i`
### 算术运算符
支持常见的算术运算符,例如`1 + 2 * 3 / 4 % 2`、同样也支持`+=`、`-=`、`*=`、`/=`、`%=`
### 比较运算符
`23 < 34`,`23 <= 34`,`23 > 34`,`23 >= 34`,`true != false`,`23 == 34`
比较运算符结果为`boolean`类型
### 逻辑运算符
除了一元运算`!`符,您还可以使用`&&`和`||`。就像Java中一样,运算符也是一种短路运算符。如果`&&`左边计算为`false`,则不会计算右边。如果`||`左侧为true,则不会计算右边
在1.3.0+版本中增强了`&&` `||` 不在强制两边必须是布尔类型。作用与`JS`一样
### 三元运算符
三元运算符是`if`语句的简写形式,其工作方式类似于Java中,例如`true ? "yes" : "no"`
在1.2.7+版本中,增强了`if` 和三元运算符,不在强制值必须是布尔类型,可以写`if(xxx)`的形式当`xxx`为以下情况时为`fasle`、其它情况为`true`
- `null`
- 空集合
- 空Map
- 空数组
- 数值==0
- 非空字符串
- `false`
### 类型转换
可使用`::type(defaultValue)` 的方式进行类型转换,如
```javascript
var a = "123"::int; // 123
var b = "abc"::int(111); // 111
var c = "2020-01-01"::date('yyyy-MM-dd'); // 转换为date
```
### 可选链操作符
可选链操作符(`?.`)允许读取位于连接对象链深处的属性的值,而不必明确验证链中的每个引用是否有效。`?.`操作符的功能类似于`.`链式操作符,不同之处在于,在引用为空 的情况下不会引起错误,该表达式短路返回值是 `null`。
当尝试访问可能不存在的对象属性时,可选链操作符将会使表达式更短、更简明。在探索一个对象的内容时,如果不能确定哪些属性必定存在,可选链操作符也是很有帮助的。
```javascript
obj?.prop
obj?.method(args)
```
示例:
```javascript
var a = null;
var b = a?.name; // b = null;
var c = a?.getName(); // c = null;
```
### 扩展运算符
扩展运算符,又叫展开语法(Spread syntax), 是用于将list或map在语法层面展开;
语法:
> lambda 调用
```javascript
var sum = (a,b,c) => a + b + c;
System.out.println(sum(...[1,2,3]))
/*
结果:6
*/
```
> list 展开
```javascript
var arr = [3,4,5];
System.out.println([1,2,...arr,6,7])
/*
结果:[1, 2, 3, 4, 5, 6, 7]
*/
```
> list 展开到 map 中
```javascript
var arr = [3,4,5];
System.out.println({key1:1,...arr})
/*
结果:{key1=1, 0=3, 1=4, 2=5}
虽然这些key看起来像数值,但其实是String类型的key,如果把它们转为JSON看起来是这样的:
{"key1":1, "0":3, "1":4, "2":5}
*/
```
> map 展开
```javascript
var map = {key2:2}
System.out.println({key1:1,...map,key3:3})
/*
结果:{key1=1, key2=2, key3=3}
*/
```
### for循环
当前for循环只支持两种,循环集合或Map
#### 循环集合
```javascript
import 'java.lang.System' as System;
var list = [1,2,3];
for(index,item in list){ //如果不需要index,也可以写成for(item in list)
System.out.println(index + ":" + item);
}
/*
结果:
0:1
1:2
2:3
*/
```
#### 循环指定次数
```javascript
var sum = 0;
for(value in range(0,100)){ //包括0包括100
sum = sum + value; //不支持+= -= *= /= ++ -- 这种运算
}
return sum;
/*
结果:5050
*/
```
#### 循环map
```javascript
import 'java.lang.System' as System;
var map = {
key1 : 123,
key2 : 456
};
for(key,value in map){ //如果不需要key,也可以写成for(value in map)
System.out.println(key + ":" + value);
}
/*
结果:
key1:123
key2:456
*/
```
### Import导入
#### 导入Java类
```javascript
import 'java.lang.System' as system;//导入静态类并赋值给system作为变量
import 'javax.sql.DataSource' as ds;//从spring中获取DataSource并将值赋值给ds作为变量
import 'org.apache.commons.lang3.StringUtils' as string;//导入静态类并赋值给ds作为变量
System.out.println('调用System打印');//调用静态方法
System.out.println(ds);
System.out.println(string.isBlank('')); //调用静态方法
```
### new创建对象
#### 创建对象
```javascript
import 'java.util.Date' as Date;//创建之前先导包,不支持.*的操作
return new Date();
```
#### 导入已定义的模块
```javascript
import log; //导入log模块,并定义一个与模块名相同的变量名
//import log as logger; //导入log模块,并赋值给变量 logger
log.info('Hello {}','Magic API!')
```
### 异步调用
#### 异步调用方法
```javascript
var val = async db.select('.....'); // 异步调用,返回Future类型
return val.get(); //调用Future的get方法
```
#### 异步调用lambda
```javascript
var list = [];
for(index in range(1,10)){
list.add(async (index)=>db.selectInt('select #{index}'));
}
return list.map(item=>item.get()); // 循环获取结果
```