Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 52d110a

Browse files
Merge pull request #30 from cloudAndMonkey/master
apijson function支持脚本引擎,比如JavaScript、lua等
2 parents e323cce + b9a3883 commit 52d110a

File tree

13 files changed

+881
-0
lines changed

13 files changed

+881
-0
lines changed
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
1、目前支持脚步引擎 <br/>
2+
jdk默认实现 Nashorn 引擎<br/>
3+
Nashorn(--global-per-engine)<br/>
4+
graalvm<br/>
5+
lua<br/>
6+
其他脚步引擎,业务侧可以扩展<br/>
7+
2、扩展脚步引擎,支持更多脚步执行器<br/>
8+
![image](https://user-images.githubusercontent.com/12228225/212584805-12f7c2d0-4b67-4c9e-b4c7-4259e2c7cb04.png)
9+
![image](https://user-images.githubusercontent.com/12228225/212584868-3893f192-8f7c-4612-ac72-d022ff0550ed.png)
10+
3、脚本 线程安全问题<br/>
11+
业务侧按照需求,进行锁颗粒度控制<br/>
12+
目前测试, lua Bindings无法保证线程安全 需要通过外部锁,比如 lock、synchronized、redis 分布式锁,防止并发问题<br/>
13+
建议锁颗粒度: 脚本名.<br/>
14+
举例:<br/>
15+
脚本: length, testArray_lua<br/>
16+
锁: length<br/>
17+
锁: testArray_lua<br/>
18+
ConcurrentHashMap 写key实现原理差不多<br/>
19+
![image](https://user-images.githubusercontent.com/12228225/212581538-a68d677b-bb3f-487b-8e4a-b7415e03666a.png)
20+
21+
![image](https://user-images.githubusercontent.com/12228225/212581560-5304baf4-fd80-4809-80cc-168767199986.png)
22+
4、支持传递 apijson元数据 参数:<br/>
23+
version、tag、args<br/>
24+
5、支持业务侧扩展参数<br/>
25+
extParam<br/>
26+
![image](https://user-images.githubusercontent.com/12228225/212581889-edbe0d99-1a0e-401f-ba14-73d81e244382.png)
27+
![image](https://user-images.githubusercontent.com/12228225/212582389-f5de9267-893e-4db1-beae-39f5a3cbdcc7.png)
28+
6、脚本编写规范<br/>
29+
案例一:<br/>
30+
31+
```
32+
function getType() {
33+
var curObj = _meta.args[0];
34+
var val = _meta.args[1];
35+
var index = _meta.args[2];
36+
return curObj[val] instanceof Array ? 'array' : typeof curObj[val];
37+
}
38+
getType()
39+
40+
```
41+
案例二:<br/>
42+
43+
```
44+
function getType(curObj, val, index) {
45+
return curObj[val] instanceof Array ? 'array' : typeof curObj[val];
46+
}
47+
getType(_meta.args[0], _meta.args[1], _meta.args[2])
48+
49+
```
50+
7、支持二次处理脚步<br/>
51+
格式化等<br/>
52+
![image](https://user-images.githubusercontent.com/12228225/212583376-52081fee-7c1a-40c2-8a40-3ec04cb6c5f9.png)
53+
8、数据库测试脚本<br/>
54+
55+
```
56+
DROP TABLE IF EXISTS `function`;
57+
CREATE TABLE `function` (
58+
`id` bigint(20) NOT NULL AUTO_INCREMENT,
59+
`debug` tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否为 DEBUG 调试数据,只允许在开发环境使用,测试和线上环境禁用:0-否,1-是。',
60+
`userId` varchar(36) NOT NULL COMMENT '管理员用户Id',
61+
`type` tinyint(4) NOT NULL DEFAULT '0' COMMENT '''0'' COMMENT ''类型:0-远程函数;1- SQL 函数''',
62+
`name` varchar(50) NOT NULL COMMENT '方法名',
63+
`returnType` varchar(50) NOT NULL DEFAULT 'Object' COMMENT '返回值类型。TODO RemoteFunction 校验 type 和 back',
64+
`arguments` varchar(100) DEFAULT NULL COMMENT '参数列表,每个参数的类型都是 String。\n用 , 分割的字符串 比 [JSONArray] 更好,例如 array,item ,更直观,还方便拼接函数。',
65+
`demo` json NOT NULL COMMENT '可用的示例。\nTODO 改成 call,和返回值示例 back 对应。',
66+
`detail` varchar(1000) NOT NULL COMMENT '详细描述',
67+
`version` tinyint(4) NOT NULL DEFAULT '0' COMMENT '允许的最低版本号,只限于GET,HEAD外的操作方法。\nTODO 使用 requestIdList 替代 version,tag,methods',
68+
`tag` varchar(20) DEFAULT NULL COMMENT '允许的标签.\nnull - 允许全部\nTODO 使用 requestIdList 替代 version,tag,methods',
69+
`methods` varchar(50) DEFAULT NULL COMMENT '允许的操作方法。\nnull - 允许全部\nTODO 使用 requestIdList 替代 version,tag,methods',
70+
`date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
71+
`appId` varchar(36) DEFAULT NULL COMMENT '应用编号',
72+
`return` varchar(45) DEFAULT NULL COMMENT '返回值示例',
73+
`language` varchar(255) DEFAULT NULL COMMENT '语言:Java(java), JavaScript(js), Lua(lua), Python(py), Ruby(ruby), PHP(php) 等,NULL 默认为 Java,JDK 1.6-11 默认支持 JavaScript,JDK 12+ 需要额外依赖 Nashron/Rhiro 等 js 引擎库,其它的语言需要依赖对应的引擎库,并在 ScriptEngineManager 中注册',
74+
PRIMARY KEY (`id`) USING BTREE,
75+
UNIQUE KEY `name_UNIQUE` (`name`) USING BTREE
76+
) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8 COMMENT='远程函数。强制在启动时校验所有demo是否能正常运行通过';
77+
78+
-- ----------------------------
79+
-- Records of function
80+
-- ----------------------------
81+
BEGIN;
82+
INSERT INTO `function` (`id`, `debug`, `userId`, `type`, `name`, `returnType`, `arguments`, `demo`, `detail`, `version`, `tag`, `methods`, `date`, `appId`, `return`, `language`) VALUES (18, 0, '0', 1, 'getType', 'String', 'var,index', '{\"var\": [1, 2, 3], \"index\": 0}', '系统', 0, NULL, NULL, '2022年12月13日 14:17:43', NULL, NULL, 'js');
83+
INSERT INTO `function` (`id`, `debug`, `userId`, `type`, `name`, `returnType`, `arguments`, `demo`, `detail`, `version`, `tag`, `methods`, `date`, `appId`, `return`, `language`) VALUES (28, 0, '0', 0, 'testArray', 'Object', 'var,index', '{\"var\": [1, 2, 3], \"index\": 0}', '测试', 0, NULL, NULL, '2022年12月20日 18:42:39', NULL, NULL, 'js');
84+
INSERT INTO `function` (`id`, `debug`, `userId`, `type`, `name`, `returnType`, `arguments`, `demo`, `detail`, `version`, `tag`, `methods`, `date`, `appId`, `return`, `language`) VALUES (31, 0, '0', 0, 'isContainJs', 'Object', 'var,valKey', '{\"var\": \"a, b,c\", \"valKey\": \"1\"}', '测试', 0, NULL, NULL, '2023年01月12日 14:29:11', NULL, NULL, 'nashornJS');
85+
INSERT INTO `function` (`id`, `debug`, `userId`, `type`, `name`, `returnType`, `arguments`, `demo`, `detail`, `version`, `tag`, `methods`, `date`, `appId`, `return`, `language`) VALUES (32, 0, '0', 0, 'length', 'Object', 'var', '{\"var\": [1, 2, 3]}', '测试', 0, NULL, NULL, '2023年01月12日 17:28:47', NULL, NULL, 'js');
86+
INSERT INTO `function` (`id`, `debug`, `userId`, `type`, `name`, `returnType`, `arguments`, `demo`, `detail`, `version`, `tag`, `methods`, `date`, `appId`, `return`, `language`) VALUES (33, 0, '0', 0, 'lengthExtendParameter', 'Object', 'var', '{\"var\": [1, 2, 3]}', '测试', 0, NULL, NULL, '2023年01月12日 18:18:31', NULL, NULL, 'nashornJS');
87+
INSERT INTO `function` (`id`, `debug`, `userId`, `type`, `name`, `returnType`, `arguments`, `demo`, `detail`, `version`, `tag`, `methods`, `date`, `appId`, `return`, `language`) VALUES (34, 0, '0', 0, 'length_lua', 'Object', 'var', '{\"var\": [1, 2, 3]}', '测试', 0, NULL, NULL, '2023年01月13日 15:59:47', NULL, NULL, 'luaj');
88+
INSERT INTO `function` (`id`, `debug`, `userId`, `type`, `name`, `returnType`, `arguments`, `demo`, `detail`, `version`, `tag`, `methods`, `date`, `appId`, `return`, `language`) VALUES (35, 0, '0', 0, 'testArray_lua', 'Object', 'var,index', '{\"var\": [1, 2, 3], \"index\": 0}', '测试', 0, NULL, NULL, '2023年01月13日 16:02:00', NULL, NULL, 'luaj');
89+
INSERT INTO `function` (`id`, `debug`, `userId`, `type`, `name`, `returnType`, `arguments`, `demo`, `detail`, `version`, `tag`, `methods`, `date`, `appId`, `return`, `language`) VALUES (36, 0, '0', 0, 'length_graalJS', 'Object', 'var', '{\"var\": [1, 2, 3]}', '测试', 0, NULL, NULL, '2023年01月13日 18:03:25', NULL, NULL, 'graalJS');
90+
COMMIT;
91+
92+
SET FOREIGN_KEY_CHECKS = 1;
93+
94+
```
95+
```
96+
SET NAMES utf8mb4;
97+
SET FOREIGN_KEY_CHECKS = 0;
98+
99+
-- ----------------------------
100+
-- Table structure for script
101+
-- ----------------------------
102+
DROP TABLE IF EXISTS `script`;
103+
CREATE TABLE `script` (
104+
`id` bigint(20) NOT NULL AUTO_INCREMENT,
105+
`documentId` bigint(20) NOT NULL,
106+
`randomId` bigint(20) NOT NULL,
107+
`simple` tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否为可直接执行的简单代码段:0-否 1-是',
108+
`name` varchar(100) NOT NULL,
109+
`script` text NOT NULL,
110+
`date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
111+
`ahead` tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否为前置脚本',
112+
PRIMARY KEY (`id`) USING BTREE,
113+
UNIQUE KEY `id_UNIQUE` (`id`) USING BTREE
114+
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8 COMMENT='脚本,前置预处理脚本、后置断言和恢复脚本等';
115+
116+
-- ----------------------------
117+
-- Records of script
118+
-- ----------------------------
119+
BEGIN;
120+
INSERT INTO `script` (`id`, `documentId`, `randomId`, `simple`, `name`, `script`, `date`, `ahead`) VALUES (1, 0, 0, 0, 'getType', 'function getType() {\n var curObj = _meta.args[0];\n var val = _meta.args[1];\n var index = _meta.args[2];\n return curObj[val] instanceof Array ? \'array\' : typeof curObj[val];\n}\ngetType()', '2022年11月16日 16:01:23', 0);
121+
INSERT INTO `script` (`id`, `documentId`, `randomId`, `simple`, `name`, `script`, `date`, `ahead`) VALUES (2, 0, 0, 0, 'isContainJs', 'function isContainJs() {\n var curObj = _meta.args[0];\n var key = _meta.args[1];\n var valKey = _meta.args[2];\n var arr = curObj == null ? null : curObj[key];\n var val = curObj == null ? null : curObj[valKey];\n return arr != null && arr.indexOf(val) >=0;\n}\nisContainJs()\n', '2022年11月16日 16:02:48', 0);
122+
INSERT INTO `script` (`id`, `documentId`, `randomId`, `simple`, `name`, `script`, `date`, `ahead`) VALUES (3, 0, 0, 1, 'init', 'var i = 1;\n\"init done \" + i;', '2022年11月16日 16:41:35', 0);
123+
INSERT INTO `script` (`id`, `documentId`, `randomId`, `simple`, `name`, `script`, `date`, `ahead`) VALUES (4, 0, 0, 0, 'length', 'function length() {\n var curObj = _meta.args[0];\n var key = _meta.args[1];\n var val = curObj == null ? null : curObj[key];\n return val == null ? 0 : val.length;\n}\nlength()', '2022年11月16日 17:18:43', 0);
124+
INSERT INTO `script` (`id`, `documentId`, `randomId`, `simple`, `name`, `script`, `date`, `ahead`) VALUES (5, 0, 0, 0, 'testArray', 'function testArray() {\n var curObj = _meta.args[0];\n var key = _meta.args[1];\n var index = _meta.args[2];\n var val = curObj == null ? null : curObj[key][curObj[index]];\n return val;\n}\ntestArray()', '2022年12月20日 18:44:09', 0);
125+
INSERT INTO `script` (`id`, `documentId`, `randomId`, `simple`, `name`, `script`, `date`, `ahead`) VALUES (6, 0, 0, 0, 'lengthExtendParameter', 'function lengthExtendParameter() {\n var data = extParam.data;\n print(\'data:\'+data);\n var curObj = _meta.args[0];\n var key = _meta.args[1];\n var val = curObj == null ? null : curObj[key];\n return val == null ? 0 : val.length;\n}\nlengthExtendParameter()', '2023年01月12日 18:23:45', 0);
126+
INSERT INTO `script` (`id`, `documentId`, `randomId`, `simple`, `name`, `script`, `date`, `ahead`) VALUES (7, 0, 0, 0, 'length_lua', 'function length_lua()\n local extParam = extParam:getUsername()\n local version = _meta:get(\'version\')\n local args = _meta:get(\'args\')\n local curObj = args[1];\n local key = args[2]\n print(\'curObj:get(key):\'..tostring(curObj:get(key)))\n print(\'ret type:\'..type(curObj:get(key)))\n print(\'ret:\'..tostring(curObj:get(key):size()))\n return curObj:get(key):size()\nend\nreturn length_lua()', '2023年01月13日 16:00:34', 0);
127+
INSERT INTO `script` (`id`, `documentId`, `randomId`, `simple`, `name`, `script`, `date`, `ahead`) VALUES (8, 0, 0, 0, 'testArray_lua', 'function testArray_lua()\n local args = _meta:get(\'args\')\n local curObj = args[1];\n print(\'curObj:\'..tostring(curObj)) \n local key = args[2];\n local index = args[3];\n local valIndex = curObj:get(index)\n print(\'valIndex:\'..tostring(valIndex)) \n print(\'ret:\'..tostring(curObj:get(key)))\n return curObj:get(key):get(valIndex)\nend\nreturn testArray_lua()', '2023年01月13日 16:01:35', 0);
128+
INSERT INTO `script` (`id`, `documentId`, `randomId`, `simple`, `name`, `script`, `date`, `ahead`) VALUES (9, 0, 0, 0, 'length_graalJS', 'function length() {\n var curObj = _meta.args[0];\n var key = _meta.args[1];\n var val = curObj == null ? null : curObj[key];\n return val == null ? 0 : val.length;\n}\nlength()', '2023年01月13日 18:04:25', 0);
129+
COMMIT;
130+
131+
SET FOREIGN_KEY_CHECKS = 1;
132+
133+
```
134+
9、apijson 测试json<br/>
135+
```
136+
#js
137+
{
138+
"func": {
139+
"var": [1,2,3],
140+
"index": 0,
141+
"id()": "getType(var,index)"
142+
}
143+
}
144+
145+
{
146+
"func": {
147+
"var": "a,b,c",
148+
"valKey": "a1",
149+
"id()": "isContainJs(var,valKey)"
150+
}
151+
}
152+
153+
{
154+
"func": {
155+
"var": [1,2,3],
156+
"length()": "length(var)"
157+
}
158+
}
159+
160+
{
161+
"func": {
162+
"var": [1,2,3],
163+
"index": 1,
164+
"testArray()": "testArray(var,index)"
165+
}
166+
}
167+
#lua
168+
{
169+
"func": {
170+
"var": [1,2,3,'dd'],
171+
"length_lua()": "length_lua(var)"
172+
}
173+
}
174+
175+
{
176+
"func": {
177+
"var": [1,2,3],
178+
"index": 2,
179+
"testArray_lua()": "testArray_lua(var,index)"
180+
}
181+
}
182+
183+
# graalJS
184+
{
185+
"func": {
186+
"var": [1,2,3],
187+
"length_graalJS()": "length_graalJS(var)"
188+
}
189+
}
190+
```
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
<groupId>apijson.demo</groupId>
6+
<artifactId>apijson-demo-script</artifactId>
7+
<version>6.0.0</version>
8+
<packaging>jar</packaging>
9+
10+
<name>APIJSONDemo-Druid</name>
11+
<description>Demo project for Testing APIJSON Server based on SpringBoot</description>
12+
13+
<properties>
14+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
15+
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
16+
<java.version>1.8</java.version>
17+
<graalvm.version>21.3.3.1</graalvm.version>
18+
<lombok.version>1.18.4</lombok.version>
19+
</properties>
20+
21+
<dependencies>
22+
<!-- JDK 11+ 需要,否则启动报错 NoClassDefFoundError: javax/activation/UnsupportedDataTypeException -->
23+
<dependency>
24+
<groupId>javax.activation</groupId>
25+
<artifactId>activation</artifactId>
26+
<version>1.1.1</version>
27+
</dependency>
28+
<!-- 需要的 APIJSON 相关依赖 -->
29+
<dependency>
30+
<groupId>com.github.APIJSON</groupId>
31+
<artifactId>apijson-framework</artifactId>
32+
<version>6.0.0</version>
33+
</dependency>
34+
35+
<!-- 需要用的数据库 JDBC 驱动 -->
36+
<dependency>
37+
<groupId>mysql</groupId>
38+
<artifactId>mysql-connector-java</artifactId>
39+
<version>8.0.29</version>
40+
</dependency>
41+
<dependency>
42+
<groupId>org.postgresql</groupId>
43+
<artifactId>postgresql</artifactId>
44+
<version>42.3.4</version>
45+
</dependency>
46+
<!-- Oracle, SQLServer 等其它数据库的 JDBC 驱动,可以在这里加上 Maven 依赖或 libs 目录放 Jar 包并依赖 -->
47+
48+
<!-- 需要用的 SpringBoot 框架,1.4.0 以上 -->
49+
<dependency>
50+
<groupId>org.springframework.boot</groupId>
51+
<artifactId>spring-boot-starter-web</artifactId>
52+
<version>2.5.13</version>
53+
</dependency>
54+
55+
<!-- 需要用的 Druid 数据库连接池库,1.0.29 以上 -->
56+
<dependency>
57+
<groupId>com.alibaba</groupId>
58+
<artifactId>druid</artifactId>
59+
<version>1.2.9</version>
60+
</dependency>
61+
<dependency>
62+
<groupId>org.graalvm.js</groupId>
63+
<artifactId>js</artifactId>
64+
<version>${graalvm.version}</version>
65+
</dependency>
66+
<dependency>
67+
<groupId>org.projectlombok</groupId>
68+
<artifactId>lombok</artifactId>
69+
<version>${lombok.version}</version>
70+
</dependency>
71+
</dependencies>
72+
73+
<build>
74+
<plugins>
75+
<plugin>
76+
<groupId>org.springframework.boot</groupId>
77+
<artifactId>spring-boot-maven-plugin</artifactId>
78+
<configuration>
79+
<fork>true</fork>
80+
<mainClass>apijson.demo.DemoApplication</mainClass>
81+
</configuration>
82+
<executions>
83+
<execution>
84+
<goals>
85+
<goal>repackage</goal>
86+
</goals>
87+
</execution>
88+
</executions>
89+
</plugin>
90+
<plugin>
91+
<groupId>org.apache.maven.plugins</groupId>
92+
<artifactId>maven-compiler-plugin</artifactId>
93+
<configuration>
94+
<source>1.8</source>
95+
<target>1.8</target>
96+
</configuration>
97+
</plugin>
98+
</plugins>
99+
</build>
100+
101+
<repositories>
102+
<!-- APIJSON 必须用到的托管平台 -->
103+
<repository>
104+
<id>jitpack.io</id>
105+
<url>https://jitpack.io</url>
106+
<snapshots>
107+
<enabled>true</enabled>
108+
</snapshots>
109+
</repository>
110+
111+
<repository>
112+
<id>spring-snapshots</id>
113+
<url>https://repo.spring.io/snapshot</url>
114+
<snapshots>
115+
<enabled>true</enabled>
116+
</snapshots>
117+
</repository>
118+
<repository>
119+
<id>spring-milestones</id>
120+
<url>https://repo.spring.io/milestone</url>
121+
</repository>
122+
</repositories>
123+
124+
</project>

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /