From 8c6bec031b678a47c1839cee4b12b1ee98266eaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=BE=99=E9=BE=99?= Date: Mon, 11 May 2026 15:35:27 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20Magic-API=20=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E5=BF=AB=E9=80=9F=E5=BC=80=E5=8F=91=E6=A1=86=E6=9E=B6?= =?UTF-8?q?=E7=9A=84=E8=84=9A=E6=9C=AC=E7=BC=96=E5=86=99=E5=8A=A9=E6=89=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- magic-script-skill/.gitignore | 18 ++ magic-script-skill/LICENSE | 21 ++ magic-script-skill/SKILL.md | 154 +++++++++ magic-script-skill/references/aggregation.md | 63 ++++ .../references/api-integration.md | 128 ++++++++ .../references/array-functions.md | 75 +++++ .../references/class-extensions.md | 25 ++ .../references/collection-extensions.md | 304 ++++++++++++++++++ .../references/date-extensions.md | 11 + .../references/date-functions.md | 36 +++ magic-script-skill/references/db-cache.md | 22 ++ magic-script-skill/references/db-query.md | 63 ++++ .../references/db-transaction.md | 23 ++ magic-script-skill/references/db-update.md | 49 +++ magic-script-skill/references/env-module.md | 18 ++ magic-script-skill/references/faq.md | 177 ++++++++++ magic-script-skill/references/http-module.md | 97 ++++++ .../references/java-integration.md | 42 +++ magic-script-skill/references/keywords.md | 108 +++++++ magic-script-skill/references/lambda-async.md | 102 ++++++ magic-script-skill/references/linq.md | 76 +++++ magic-script-skill/references/log-module.md | 15 + magic-script-skill/references/magic-module.md | 45 +++ .../references/math-functions.md | 39 +++ .../references/number-extensions.md | 51 +++ .../references/object-extensions.md | 129 ++++++++ .../references/other-functions.md | 55 ++++ magic-script-skill/references/page.md | 32 ++ .../references/pattern-extensions.md | 13 + magic-script-skill/references/quick-crud.md | 125 +++++++ magic-script-skill/references/quick-param.md | 47 +++ magic-script-skill/references/quick-start.md | 66 ++++ .../references/request-module.md | 64 ++++ .../references/response-module.md | 141 ++++++++ .../references/script-syntax.md | 163 ++++++++++ magic-script-skill/references/single-table.md | 104 ++++++ magic-script-skill/references/sql-param.md | 125 +++++++ .../references/string-functions.md | 26 ++ magic-script-skill/references/validate.md | 22 ++ 39 files changed, 2874 insertions(+) create mode 100644 magic-script-skill/.gitignore create mode 100644 magic-script-skill/LICENSE create mode 100644 magic-script-skill/SKILL.md create mode 100644 magic-script-skill/references/aggregation.md create mode 100644 magic-script-skill/references/api-integration.md create mode 100644 magic-script-skill/references/array-functions.md create mode 100644 magic-script-skill/references/class-extensions.md create mode 100644 magic-script-skill/references/collection-extensions.md create mode 100644 magic-script-skill/references/date-extensions.md create mode 100644 magic-script-skill/references/date-functions.md create mode 100644 magic-script-skill/references/db-cache.md create mode 100644 magic-script-skill/references/db-query.md create mode 100644 magic-script-skill/references/db-transaction.md create mode 100644 magic-script-skill/references/db-update.md create mode 100644 magic-script-skill/references/env-module.md create mode 100644 magic-script-skill/references/faq.md create mode 100644 magic-script-skill/references/http-module.md create mode 100644 magic-script-skill/references/java-integration.md create mode 100644 magic-script-skill/references/keywords.md create mode 100644 magic-script-skill/references/lambda-async.md create mode 100644 magic-script-skill/references/linq.md create mode 100644 magic-script-skill/references/log-module.md create mode 100644 magic-script-skill/references/magic-module.md create mode 100644 magic-script-skill/references/math-functions.md create mode 100644 magic-script-skill/references/number-extensions.md create mode 100644 magic-script-skill/references/object-extensions.md create mode 100644 magic-script-skill/references/other-functions.md create mode 100644 magic-script-skill/references/page.md create mode 100644 magic-script-skill/references/pattern-extensions.md create mode 100644 magic-script-skill/references/quick-crud.md create mode 100644 magic-script-skill/references/quick-param.md create mode 100644 magic-script-skill/references/quick-start.md create mode 100644 magic-script-skill/references/request-module.md create mode 100644 magic-script-skill/references/response-module.md create mode 100644 magic-script-skill/references/script-syntax.md create mode 100644 magic-script-skill/references/single-table.md create mode 100644 magic-script-skill/references/sql-param.md create mode 100644 magic-script-skill/references/string-functions.md create mode 100644 magic-script-skill/references/validate.md diff --git a/magic-script-skill/.gitignore b/magic-script-skill/.gitignore new file mode 100644 index 0000000..5d947ca --- /dev/null +++ b/magic-script-skill/.gitignore @@ -0,0 +1,18 @@ +# Build and Release Folders +bin-debug/ +bin-release/ +[Oo]bj/ +[Bb]in/ + +# Other files and folders +.settings/ + +# Executables +*.swf +*.air +*.ipa +*.apk + +# Project files, i.e. `.project`, `.actionScriptProperties` and `.flexProperties` +# should NOT be excluded as they contain compiler settings and other important +# information for Eclipse / Flash Builder. diff --git a/magic-script-skill/LICENSE b/magic-script-skill/LICENSE new file mode 100644 index 0000000..647b5fb --- /dev/null +++ b/magic-script-skill/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Assassin-Q + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/magic-script-skill/SKILL.md b/magic-script-skill/SKILL.md new file mode 100644 index 0000000..9b2990d --- /dev/null +++ b/magic-script-skill/SKILL.md @@ -0,0 +1,154 @@ +--- +name: magic-script +description: magic-api 框架接口开发助手,提供 magic-script 脚本编写指导、DB/HTTP 模块使用及语法纠错;当用户需要在 magic-api 中编写接口脚本、调试脚本或排查脚本错误时使用 +--- + +# Magic-Script 脚本开发助手 + +Magic-API 是一个基于 Java 的接口快速开发框架,支持通过 magic-script 脚本语言编写接口。magic-script 是一种基于 Mozilla Rhino 的脚本语言,语法类似 JavaScript,专为接口开发优化。 + +> **说明**:本 Skill 同时兼容以下称呼方式: +> - magic-api / magicapi(框架名称) +> - magic-script / MagicScript / magicscript(脚本语言名称) +> 无论用户使用哪种称呼,都指代同一套技术栈。 + +## 任务目标 +- 本 Skill 用于:为 magic-api/magicapi 框架提供 magic-script/MagicScript 脚本编写的完整指导 +- 能力包含:magic-script 语法参考、内置模块(db、http 等)使用方法、接口开发示例和脚本故障排查 +- 触发条件:用户需要在 magic-api/magicapi 中编写接口脚本、调试 magic-script/MagicScript 代码或解决脚本执行错误时使用 + +## 操作步骤 +- 标准流程:确认场景 → 阅读 SKILL.md → 查阅 references/ 文档 → 编写脚本 +- 可选分支:遇到脚本错误 → 查阅 faq 相关文档 + +## 使用示例 + +**示例1:快速查询接口** +```javascript +// GET /api/user/list 分页查询 +return db.table('sys_user') + .column('id', 'userId') + .column('name', 'userName') + .where() + .eq('status', 1) + .page(page, size); +``` + +**示例2:带参数的增删改查** +```javascript +// POST /api/user/save 新增用户 +assert not_blank(body.name) : 400, '用户名不能为空'; +var userId = db.table('sys_user') + .column('name', body.name) + .column('create_time', now()) + .insert(); +return {code: 200, data: {id: userId}}; +``` + +**示例3:调用外部接口** +```javascript +import http; +var result = http.connect('https://api.example.com/data') + .param({key: 'value'}) + .header('Authorization', 'Bearer xxx') + .post() + .getBody(); +return result; +``` + +## 资源索引 + +### 语法类 +| 文件 | 说明 | +|------|------| +| `references/keywords.md` | 关键字、运算符、数据类型 | +| `references/script-syntax.md` | 脚本语法详解 | +| `references/lambda-async.md` | Lambda表达式与异步调用 | + +### 函数扩展 +| 文件 | 说明 | +|------|------| +| `references/aggregation.md` | 聚合函数(count/sum/max/min/avg/group_concat) | +| `references/string-functions.md` | 字符串函数(uuid/is_blank/not_blank) | +| `references/date-functions.md` | 日期函数(date_format/now/current_timestamp_millis/current_timestamp) | +| `references/number-extensions.md` | Number扩展与数学函数 | +| `references/collection-extensions.md` | 列表与Map扩展 | +| `references/date-extensions.md` | 日期扩展 | +| `references/array-functions.md` | 数组创建函数 | +| `references/math-functions.md` | 数学函数(round/floor/ceil/percent) | +| `references/other-functions.md` | 其它函数(print/println/ifnull/is_null/not_null) | +| `references/object-extensions.md` | Object扩展方法 | +| `references/class-extensions.md` | Class扩展方法 | +| `references/pattern-extensions.md` | Pattern扩展方法 | + +### 数据库 +| 文件 | 说明 | +|------|------| +| `references/db-query.md` | 数据库查询(select/selectOne/selectInt/selectValue) | +| `references/db-update.md` | 数据库增删改(insert/update/batchUpdate/call) | +| `references/db-transaction.md` | 事务操作 | +| `references/db-cache.md` | 缓存操作(cache/deleteCache) | +| `references/single-table.md` | 单表操作(db.table链式API) | +| `references/sql-param.md` | SQL参数(#{}、${}、动态SQL、Mybatis语法) | +| `references/page.md` | 分页查询 | + +### 模块 +| 文件 | 说明 | +|------|------| +| `references/http-module.md` | HTTP模块调用外部接口 | +| `references/request-module.md` | Request模块获取请求信息 | +| `references/response-module.md` | Response模块设置响应 | +| `references/log-module.md` | 日志模块 | +| `references/env-module.md` | 环境配置模块 | +| `references/magic-module.md` | Magic模块(调用其他接口) | + +### 集成 +| 文件 | 说明 | +|------|------| +| `references/java-integration.md` | 脚本调用Java | +| `references/api-integration.md` | Java调用接口 | + +### 示例 +| 文件 | 说明 | +|------|------| +| `references/quick-start.md` | 快速入门(工程创建、三分钟写接口) | +| `references/quick-param.md` | 请求参数获取 | +| `references/quick-crud.md` | CRUD操作示例 | +| `references/linq.md` | Lambda/LINQ操作示例 | + +### FAQ +| 文件 | 说明 | +|------|------| +| `references/faq.md` | 常见问题 | +| `references/validate.md` | 参数校验 | + +## 注意事项 + +1. **语法限制**:magic-script 不支持 ES6 默认参数语法 `excludeValue = null`,需用 `if (excludeValue === undefined)` 判断;不支持 `new Set()`,需用数组替代 + +2. **数组方法**:不支持传统 `for` 循环,需用 `for (value in list)` 或 `for (index, value in list)`;**注意** Collection 扩展提供了 `reduce` 方法用于归约操作 + +3. **方法命名**:遍历集合用 `each` 而不是 `forEach`;获取长度用 `size()` 而不是 `length`;判断Map键用 `containsKey()` 而不是 `hasOwnProperty()` + +4. **SQL参数**:`#{}` 防注入占位符用于普通参数,`${}` 字符串拼接用于动态表名/列名/排序字段(存在注入风险) + +5. **类型转换**:`::type` 语法用于类型转换,如 `'123'::int`,转换失败可指定默认值 `'abc'::int(0)` + +6. **获取请求参数**: + - URL参数:直接使用变量名 `name` + - 表单参数:直接使用变量名 `name` + - Header参数:`header.xxx` + - Body参数:`body.xxx` + - Path参数:`path.xxx` 或直接使用变量名 + - Cookie参数:`cookie.xxx` + - Session参数:`session.xxx` + +7. **循环拼接参数**:`in (#{ids})` 语法会自动对集合参数展开 + +8. **多数据源**:使用 `db.slave.select(...)` 格式切换数据源 + +9. **SQL缓存**:`db.cache("cacheName", ttl).select(...)` 使用缓存 + +10. **事务操作**: + - 自动事务:`db.transaction(()=>{...})` + - 手动事务:`var tx = db.transaction(); tx.commit(); tx.rollback();` diff --git a/magic-script-skill/references/aggregation.md b/magic-script-skill/references/aggregation.md new file mode 100644 index 0000000..f6b43f7 --- /dev/null +++ b/magic-script-skill/references/aggregation.md @@ -0,0 +1,63 @@ +# 聚合函数 + +## count +- 入参:`target`:`Object` +- 返回值:`int` +- 函数说明:计算集合大小 + +```javascript +var list = [1,2,3,4,5] +return count(list); // 5 +``` + +## sum +- 入参:`target`:`Object` +- 返回值:`Number` +- 函数说明:对集合进行求和 + +```javascript +var list = [1,2,3,4,5] +return sum(list); // 15 +``` + +## max +- 入参:`target`:`Object` +- 返回值:`Object` +- 函数说明:求集合最大值 + +```javascript +var list = [1,2,3,4,5] +return max(list); // 5 +``` + +## min +- 入参:`target`:`Object` +- 返回值:`Object` +- 函数说明:求集合最小值 + +```javascript +var list = [1,2,3,4,5] +return min(list); // 1 +``` + +## avg +- 入参:`target`:`Object` +- 返回值:`Object` +- 函数说明:求集合平均值 + +```javascript +var list = [1,2,3,4,5] +return avg(list); // 3 +``` + +## group_concat +- 入参:`target`:`Object` +- 入参:`separator`:`String` 分隔符,可省略 +- 返回值:`Object` +- 函数说明:将集合拼接起来 + +```javascript +var list = [1,2,3,4,5] +return group_concat(list); // "1,2,3,4,5" +// return group_concat(list,'|'); // "1|2|3|4|5" +``` diff --git a/magic-script-skill/references/api-integration.md b/magic-script-skill/references/api-integration.md new file mode 100644 index 0000000..956773f --- /dev/null +++ b/magic-script-skill/references/api-integration.md @@ -0,0 +1,128 @@ +# Java调用接口 + +## 调用接口 +```java +@Autowired +MagicAPIService service; +Map params = new HashMap<>(); +// 注入变量信息 +params.put("id", 123); +// 内部调用接口不包含code以及message信息,同时也不走拦截器。 +Object value = service.execute("GET", "/hello", params); +// 内部调用接口包含code以及message信息,同时也不走拦截器。 +// Object value = service.call("GET", "/hello", params); +``` + +## 调用函数 +```java +@Autowired +MagicAPIService service; + +Map params = new HashMap<>(); +// 注入变量信息 +params.put("a", 1); +params.put("b", 1); +// 调用函数 +Object value = service.invoke("/test/add", params); +``` + +## 保存资源 +```java +@Autowired +MagicResourceService service; +// 保存分组信息 +service.saveGroup(group); +// 保存接口(ApiInfo)、函数(FunctionInfo)、数据源(DataSourceInfo) +service.saveFile(apiInfo); +``` + +## 删除资源 +```java +@Autowired +MagicResourceService service; +// 删除分组或文件 +service.delete(id); +``` + +## 资源列表 +```java +@Autowired +MagicResourceService service; +// 获取分组下的所有文件 +service.listFiles(groupId); +// 获取接口(api)、函数(function)、数据源(datasource)列表 +service.files(type); +// 获取接口(api)、函数(function)、数据源(datasource)树结构 +service.tree(type); +// 获取全部资源的树结构 +service.tree(); +``` + +## 其它API + +除了以上列举的`API`以外 `MagicAPIService`还有: + +```java +/** + * 上传 + */ +boolean upload(InputStream inputStream, String mode) throws IOException; + +/** + * 下载 + */ +void download(String groupId, List resources, OutputStream os) throws IOException; + +/** + * 推送 + */ +JsonBean push(String target, String secretKey, String mode, List resources); + +/** + * 处理刷新通知 + */ +boolean processNotify(MagicNotify magicNotify); +``` + +`MagicResourceService` 还有以下方法: + +```java +/** + * 刷新缓存 + */ +void refresh(); + +/** + * 移动 + * @param src 源ID + * @param groupId 目标分组 + */ +boolean move(String src, String groupId); + +/** + * 复制分组 + * @param src 源ID + * @param target 目标分组 + */ +String copyGroup(String src, String target); + +/** + * 获取文件详情 + */ + T file(String id); + +/** + * 获取分组详情 + */ +Group getGroup(String id); + +/** + * 获取完整分组路径 + */ +String getGroupPath(String groupId); + +/** + * 获取完整分组名称 + */ +String getGroupName(String groupId); +``` diff --git a/magic-script-skill/references/array-functions.md b/magic-script-skill/references/array-functions.md new file mode 100644 index 0000000..f8646f3 --- /dev/null +++ b/magic-script-skill/references/array-functions.md @@ -0,0 +1,75 @@ +# 数组函数 + +## new_int_array +- 入参:`size`:`int` 数组长度 +- 函数说明,创建`int`类型的数组 + +```javascript +return new_int_array(1); // [0] +``` + +## new_long_array +- 入参:`size`:`int` 数组长度 +- 函数说明,创建`long`类型的数组 + +```javascript +return new_long_array(1); // [0] +``` + +## new_double_array +- 入参:`size`:`int` 数组长度 +- 函数说明,创建`double`类型的数组 + +```javascript +return new_double_array(1); // [0.0] +``` + +## new_float_array +- 入参:`size`:`int` 数组长度 +- 函数说明,创建`float`类型的数组 + +```javascript +return new_float_array(1); // [0.0] +``` + +## new_short_array +- 入参:`size`:`int` 数组长度 +- 函数说明,创建`short`类型的数组 + +```javascript +return new_short_array(1); // [0] +``` + +## new_byte_array +- 入参:`size`:`int` 数组长度 +- 函数说明,创建`byte`类型的数组 + +```javascript +return new_byte_array(1); // [0] +``` + +## new_boolean_array +- 入参:`size`:`int` 数组长度 +- 函数说明,创建`boolean`类型的数组 + +```javascript +return new_boolean_array(1); // [false] +``` + +## new_char_array +- 入参:`size`:`int` 数组长度 +- 函数说明,创建`char`类型的数组 + +```javascript +return new_char_array(1); // ['\0'] +``` + +## new_array +- 入参:`Class`:类型 +- 入参:`size`:`int` 数组长度 +- 函数说明,创建`Object`类型的数组 + +```javascript +return new_array(1); // [null] // Object 类型的数组 +return new_array(String.class, 1); // [null] String类型的数组 +``` diff --git a/magic-script-skill/references/class-extensions.md b/magic-script-skill/references/class-extensions.md new file mode 100644 index 0000000..e9f4dbe --- /dev/null +++ b/magic-script-skill/references/class-extensions.md @@ -0,0 +1,25 @@ +# Class扩展方法 + +## newInstance +- 入参:`values`:`Object` 可变参数,构造函数的参数 +- 返回值:`Object` +- 函数说明:将`Class`实例化 + +```javascript +import 'java.text.SimpleDateFormat' as SimpleDateFormat; +return SimpleDateFormat.newInstance('yyyy-MM-dd HH:mm:ss'); +//其实可以简写成 new SimpleDateFormat('yyyy-MM-dd HH:mm:ss'); //这是一个语法糖 +``` + +## 获取类名称 +支持以下方法 +- `getName` - 获取完整类名 +- `getSimpleName` - 获取简单类名 +- `getCanonicalName` - 获取规范类名 + +```javascript +import 'java.text.SimpleDateFormat' as SimpleDateFormat; +println(SimpleDateFormat.getName()); // java.text.SimpleDateFormat +println(SimpleDateFormat.getSimpleName()); // SimpleDateFormat +println(SimpleDateFormat.getCanonicalName()); // java.text.SimpleDateFormat +``` diff --git a/magic-script-skill/references/collection-extensions.md b/magic-script-skill/references/collection-extensions.md new file mode 100644 index 0000000..6ec6d02 --- /dev/null +++ b/magic-script-skill/references/collection-extensions.md @@ -0,0 +1,304 @@ +# 数组&集合扩展方法 + +为`Collection`,`Iterator`,`Enumeration`,`Object[]` 添加的扩展方法 + +## map +- 入参:`function`:`Function` 接收一个`Lambda`表达式 +- 返回值:`Object` +- 函数说明:将集合进行循环转换 + +```javascript +var list = [1,2,3,4,5]; +return list.map(e=>e+1); //返回[2,3,4,5,6] +``` + +## filter +- 入参:`function`:`Function` 接收一个`Lambda`表达式 +- 返回值:`Object` +- 函数说明:将集合进行过滤 + +```javascript +var list = [1,2,3,4,5]; +return list.filter(e=>e>3); //返回[4,5] +return list.filter((item,index)=>index>1); //返回[3,4,5] +``` + +## each +- 入参:`function`:`Function` 接收一个`Lambda`表达式 +- 返回值:`Object` +- 函数说明:循环处理 + +```javascript +var list = [{name : '小明'},{name : '小花'}]; +return list.each(item=>item.put('age',18)); //循环添加age属性 +``` + +## sort +- 入参:`function`:`Function` 接收一个`Lambda`表达式 +- 返回值:`Object` +- 函数说明:对集合进行排序 + +```javascript +var list = [1,5,2,3,6]; +return list.sort((a,b)=>a-b); +``` + +## first +- 返回值:`Object` +- 函数说明:返回集合的第一项,集合为空时返回`null` + +```javascript +var list = [1,2,3,4,5] +return list.first(); // 1 +``` + +## last +- 返回值:`Object` +- 函数说明:返回集合的最后一项,集合为空时返回`null` + +```javascript +var list = [1,2,3,4,5] +return list.last(); // 5 +``` + +## reserve +- 返回值:`Object` +- 函数说明:对集合进行反转操作 + +```javascript +var list = [1,5,2,3,6]; +return list.reserve(); +``` + +## join(拼接) +- 入参:`separator` : `String` 分隔符 +- 返回值:`String` +- 函数说明:对集合进行拼接操作 + +```javascript +var list = [1,5,2,3,6]; +return list.join('-'); // 1-5-2-3-6 +``` + +## shuffle +- 返回值:`Object` +- 函数说明:对集合进行打乱处理 + +```javascript +var list = [1,5,2,3,6]; +return list.shuffle(); +``` + +## max +- 返回值:`Object` +- 函数说明:取出集合最大值,如果找不到返回null + +```javascript +var list = [1,6,8,9,18,12]; +return list.max(); // 18 +``` + +## min +- 返回值:`Object` +- 函数说明:取出集合最小值,如果找不到返回null + +```javascript +var list = [6,1,8,9,18,12]; +return list.min(); // 1 +``` + +## sum +- 返回值:`Object` +- 函数说明:累加求和,计算不出返回0.0 + +```javascript +var list = [1,2,3,4]; +return list.sum(); // 10 +``` + +## avg +- 返回值:`Object` +- 函数说明:计算平均值,计算不出返回null + +```javascript +var list = [1,2,3,4]; +return list.avg(); // 2.5 +``` + +## group +- 入参:`condition` : `Function` 分组条件 +- 入参:`mapping` : `Function` 结果映射(省略时不做映射返回List) +- 返回值:`Map>`或`Map` +- 函数说明:分组 + +```javascript +var result = [ + { xxx : 1, yyy : 2, value : 11}, + { xxx : 1, yyy : 2, value : 22}, + { xxx : 2, yyy : 2, value : 33} +]; + +return result.group(item=>item.xxx + '_' + item.yyy) +// 结果:{"1_2": [{...}, {...}], "2_2": [{...}]} +``` + +## join(关联) +- 入参:`target` : `Object` 关联的集合 +- 入参:`condition` : `Function` 关联条件 +- 入参:`mapping` : `Function` 结果映射 +- 返回值:`List` +- 函数说明:将两个集合关联起来 + +```javascript +var year2019 = [ + { "pt":2019, "item_code":"code_1", "sum_price":2234 }, + { "pt":2019, "item_code":"code_2", "sum_price":234 } +]; +var year2018 = [ + { "pt":2018, "item_code":"code_1", "sum_price":1234.0 } +]; +return year2019.join(year2018, (left, right) => left.item_code == right.item_code, (left, right) => { + '年份' : left.pt, + '编号' : left.item_code, + '今年' : left.sum_price, + '去年' : right == null ? 'unknow' : right.sum_price +}); +``` + +## asBean(转为Java对象) +- 入参:`target` : `Class` 目标类型 +- 返回值:`List` +- 函数说明:将`List` 转为目标`List` + +```javascript +import 'org.ssssssss.script.functions.User' as User; +var userList = [{ + age : 18, + weight : 121, + money : 123456789L, + name : '法外狂徒' +}] +return userList.asBean(User.class); +``` + +## every +- 入参:`condition` : `Function` 判断条件 +- 返回值:`boolean` +- 函数说明:判断集合是否都符合条件 + +```javascript +var vals = [1, 2, 3, 4, 5, 6, 7]; +return vals.every(e => e > 0); // true +``` + +## some +- 入参:`condition` : `Function` 判断条件 +- 返回值:`boolean` +- 函数说明:判断集合是否有符合条件的 + +```javascript +var vals = [1, 2, 3, 4, 5, 6, 7]; +return vals.some(e => e == 0); // false +``` + +## reduce +- 入参:`function` : `Function` 计算函数 +- 返回值:`Object` +- 函数说明:循环集合通过给定的计算函数返回一个新值 + +```javascript +var vals = [1, 2, 3]; +return vals.reduce((sum, val) => sum + val); // 6 +``` + +## find +- 入参:`function`:`Function` 查找函数 +- 返回值:`Object` +- 函数说明:循环集合查找符合条件的对象 + +```javascript +var list = [{name: 'A'}, {name:'B'}] +return list.find(it => it.name == 'A'); // {name: 'A'} +``` + +## findIndex +- 入参:`function`:`Function` 查找函数 +- 返回值:`Object` +- 函数说明:循环集合查找符合条件的对象位置 + +```javascript +var list = [{name: 'A'}, {name: 'B'}] +return list.findIndex(it => it.name == 'A'); // 0 +``` + +## concat +- 入参:`Object`,要连接的集合对象,可写多个 +- 返回值:`Object` +- 函数说明:拼接一个或多个集合,返回新的集合 + +```javascript +var list = [1]; +return [1].concat([2]); // [1,2] list不变 +return [1].concat([2],[3, 4]); // [1, 2, 3, 4] list不变 +``` + +## toMap +- 入参:`mappingKey`:`Function`,key映射方法 +- 入参:`mappingValue`:`Function`,value映射方法,可省略,默认为本身 + +```javascript +var list = [ + {id : 1, name: 'A'}, + {id : 2, name: 'B'}, + {id : 3, name: 'C'}, +] +return list.toMap(k => k.id, v => v.name) // {1: 'A', 2: 'B', 3: 'C'} +``` + +## skip +- 入参:`value` : `int` 跳过的数量 +- 返回值:`Object` +- 函数说明:跳过指定个数截取集合 + +```javascript +var vals = [1, 2, 3, 4]; +return vals.skip(2); // [3, 4] +``` + +## limit +- 入参:`value` : `int` 限制的数量 +- 返回值:`Object` +- 函数说明:取指定个数的集合 + +```javascript +var vals = [1, 2, 3, 4]; +return vals.limit(3); // [1, 2, 3] +``` + +## findNotNull +- 返回值:`Object` +- 函数说明:找到第一个不为`null`的值 + +```javascript +var vals = [null, null, 3, null]; +return vals.findNotNull(); // 3 +``` + +## distinct +- 返回值:`Object` +- 函数说明:去掉重复元素 + +```javascript +var arr = [1, 2, 2, 3]; +return arr.distinct(); // [1, 2, 3] +``` + +## distinct(func) +- 入参: 映射函数, 形如`e -> e.id` +- 返回值:`Object` +- 函数说明:根据函数返回值去重,去掉重复元素 + +```javascript +var arr = [{id: 1, name: "xiaodong"}, {id:1, name: "magic-api"}]; +return arr.distinct(e => e.id); // [{id: 1, name: "xiaodong"}] +``` diff --git a/magic-script-skill/references/date-extensions.md b/magic-script-skill/references/date-extensions.md new file mode 100644 index 0000000..60a3767 --- /dev/null +++ b/magic-script-skill/references/date-extensions.md @@ -0,0 +1,11 @@ +# Date扩展方法 + +## format +- 入参:`pattern`:`String` 格式 +- 返回值:`String` +- 函数说明:将日期格式化 + +```javascript +var date = new Date(); +return date.format('yyyy-MM-dd'); // 2020-01-01 +``` diff --git a/magic-script-skill/references/date-functions.md b/magic-script-skill/references/date-functions.md new file mode 100644 index 0000000..06fd829 --- /dev/null +++ b/magic-script-skill/references/date-functions.md @@ -0,0 +1,36 @@ +# 日期函数 + +## date_format +- 入参:`target`:`Date` 日期 +- 入参:`pattern`:`String` 格式 +- 返回值:`String` +- 函数说明:日期格式化 + +```javascript +return date_format(new Date()); // 2020-01-01 20:30:30 +// return date_format(new Date(),'yyyy-MM-dd'); // 2020-01-01 +``` + +## now +- 返回值:`Date` +- 函数说明:返回当前日期 + +```javascript +return now(); // 等同于 new Date(); +``` + +## current_timestamp_millis +- 返回值:`long` +- 函数说明:取当前时间戳(毫秒) + +```javascript +return current_timestamp_millis(); // 等同于 System.currentTimeMillis(); +``` + +## current_timestamp +- 返回值:`long` +- 函数说明:取当前时间戳(秒) + +```javascript +return current_timestamp(); // 等同于 current_timestamp_millis() / 1000; +``` diff --git a/magic-script-skill/references/db-cache.md b/magic-script-skill/references/db-cache.md new file mode 100644 index 0000000..b323e75 --- /dev/null +++ b/magic-script-skill/references/db-cache.md @@ -0,0 +1,22 @@ +# 缓存操作 + +## cache +- 入参:`cacheName`:`String` +- 入参:`ttl`:`long` 缓存有效期,单位毫秒,可省略,默认为配置的值 +- 返回值:`db` //返回当前实例,即可以链式调用 +- 函数说明:使用缓存 + +```javascript +// 使用缓存名为user的查询 +return db.cache('user').select('select * from sys_user'); +``` + +## deleteCache +- 入参:`cacheName`:`String` +- 返回值:`db` //返回当前实例,即可以链式调用 +- 函数说明:删除名为`cacheName`的缓存 + +```javascript +// 删除名为user的缓存 +db.deleteCache('user'); +``` diff --git a/magic-script-skill/references/db-query.md b/magic-script-skill/references/db-query.md new file mode 100644 index 0000000..0325db8 --- /dev/null +++ b/magic-script-skill/references/db-query.md @@ -0,0 +1,63 @@ +# 数据库查询 + +db模块是默认引入的模块,无需import。 + +## select +- 入参:`sql`:`String` +- 返回值:`List>` +- 函数说明:查询`List`结果 + +```javascript +return db.select('select * from sys_user'); +``` + +## selectInt +- 入参:`sql`:`String` +- 返回值:`Integer` +- 函数说明:查询`int`结果 + +```javascript +// 需要保证结果返回一行一列 +return db.selectInt('select count(*) from sys_user'); +``` + +## selectOne +- 入参:`sql`:`String` +- 返回值:`Map` +- 函数说明:查询单个对象 + +```javascript +return db.selectOne('select * from sys_user limit 1'); +``` + +## selectValue +- 入参:`sql`:`String` +- 返回值:`Object` +- 函数说明:查询单个值 + +```javascript +//需要保证结果返回一行一列 +return db.selectValue('select user_name from sys_user limit 1'); +``` + +## page +- 入参:`sql`:`String` +- 入参:`limit` : `long` 可省略 +- 入参:`offset` : `long` 可省略 +- 返回值:`Object` 默认返回为Object,如果自定义了分页结果,则返回自定义结果 +- 函数说明:分页查询 + +```javascript +return db.page('select * from sys_user'); +``` + +## 列名转换 +- normal 列名保持原样 +- camel 列名使用驼峰命名 +- pascal 列名使用帕斯卡命名 +- upper 列名保持全大写 +- lower 列名保持全小写 + +```javascript +return db.camel().select('select * from sys_user'); +``` diff --git a/magic-script-skill/references/db-transaction.md b/magic-script-skill/references/db-transaction.md new file mode 100644 index 0000000..d7736a4 --- /dev/null +++ b/magic-script-skill/references/db-transaction.md @@ -0,0 +1,23 @@ +# 事务操作 + +## 自动事务 +```javascript +var val = db.transaction(()=>{ + var v1 = db.update('...'); + var v2 = db.update('....'); + return v2; +}); +return val; +``` + +## 手动事务 +```javascript +var tx = db.transaction(); //开启事务 +try{ + var value = db.update('...'); + tx.commit(); // 提交事务 + return value; +}catch(e){ + tx.rollback(); // 回滚事务 +} +``` diff --git a/magic-script-skill/references/db-update.md b/magic-script-skill/references/db-update.md new file mode 100644 index 0000000..7820682 --- /dev/null +++ b/magic-script-skill/references/db-update.md @@ -0,0 +1,49 @@ +# 数据库增删改 + +## update +- 入参:`sql`:`String` +- 返回值:`Integer` +- 函数说明:执行增删改操作 + +```javascript +return db.update('delete from sys_user'); +``` + +## insert +- 入参:`sql`:`String` +- 入参:`id`:`String`,主键列,可空,如无特殊情况不需要传入 +- 返回值: `Object` + +```javascript +return db.insert("insert into sys_user(username,password) values('admin','admin)"); +``` + +## call +- 入参:`sql`: `String` +- 返回值:`Map` +- 函数说明:调用存储过程 + +```javascript +// 入参格式: #{参数名} +// 出参格式: @{参数名, java.sql.Types的类型字符串} +// 出入参格式:@{参数名(值、变量、表达式), java.sql.Types的类型字符串} +var cs1 = body.cs1; +var cs2 = body.cs2; +return db.call(""" + call test(#{cs1}, @{height(cs2), INTEGER}, @{v_area, VARCHAR}) +""") +// 返回:{height: 10, v_area: "16.85"} +``` + +## batchUpdate +- 入参:`sql`:`String` +- 入参:`batchArgs`:`List`数据,占位符和数组下标对应 +- 返回值: `int` + +```javascript +return db.batchUpdate(""" + update sys_dict set is_del = ? where is_del = ? +""", [ + ["1", "0"].toArray() +]) +``` diff --git a/magic-script-skill/references/env-module.md b/magic-script-skill/references/env-module.md new file mode 100644 index 0000000..2a92182 --- /dev/null +++ b/magic-script-skill/references/env-module.md @@ -0,0 +1,18 @@ +# 环境配置模块 + +## 引用模块 +```javascript +import env; +``` + +## 使用 +```javascript +import env; +return env.get('server.port') +``` + +## get +- 入参:`key`:`String` 配置项 +- 入参:`defaultValue`:`String` 默认值,可省略 +- 返回值:`String` +- 函数说明:获取`Spring`配置项 diff --git a/magic-script-skill/references/faq.md b/magic-script-skill/references/faq.md new file mode 100644 index 0000000..19a5e2e --- /dev/null +++ b/magic-script-skill/references/faq.md @@ -0,0 +1,177 @@ +# 常见问题 + +## 如何配置JSON日期的格式 +使用`Jackson`的配置如下(`Spring Boot`默认使用`Jackson`): +```yaml +spring: + jackson: + time-zone: GMT+8 + date-format: yyyy-MM-dd HH:mm:ss +``` + +## 出现找不到db模块的错误 +目前已知两种情况: +- 未配置数据源 +- 未引用`spring-boot-starter-jdbc` + +## 如何获取RequestBody中的参数 +脚本中使用`body.xxx`获取`RequestBody`中的参数 +SQL中使用`#{body.xxx}`或`${body.xxx}`获取`RequestBody`中的参数 + +## 如何获取Header中的参数 +脚本中使用`header.xxx`获取`Header`中的参数 +SQL中使用`#{header.xxx}`或`${header.xxx}`获取`Header`中的参数 + +## 如何获取Cookie中的参数 +脚本使用`cookie.xxx`获取`Cookie`中的参数 +SQL中使用`#{cookie.xxx}`或`${cookie.xxx}`获取`Cookie`中的参数 + +## 如何获取Session中的参数 +脚本中使用`session.xxx`获取`Session`中的参数 +SQL中使用`#{session.xxx}`获取`Session`中的参数 + +## 如何获取PathVariable中的参数 +脚本中使用`PathVariableName`或`path.xxxx`获取`PathVariable`中的参数 +SQL中使用`#{PathVariableName}`或`#{path.xxx}`获取`PathVariable`中的参数 + +## 如何获取上传的文件 +利用Request模块 +```javascript +import request; +request.getFile('name'); +``` + +## 如何获取提交的数组参数 +利用Request模块 +```javascript +import request; +return request.getValues('name'); +``` + +## 如何给接口添加权限 + +一般情况采用`拦截器`实现。在`接口选项`中配置`permisson`或`role`或自定义选项,随后在拦截器中实现: + +```java +@Component +@Order(1) +public class PermissionInterceptor implements RequestInterceptor { + + @Override + public Object preHandle(ApiInfo info, MagicScriptContext context, MagicHttpServletRequest request, MagicHttpServletResponse response) { + String permissionCode = info.getOptionValue(Options.PERMISSION); + // 执行自己的代码逻辑判断是否有权限 + if(无权限){ + return new JsonBean<>(403,"无权访问"); + } + return null; + } +} +``` + +## 如何给UI添加权限 + +请参考[自定义UI鉴权](https://www.ssssssss.org/magic-api/pages/security/operation/) + +## ${}和#{}的区别 +主要区别在于`${}`用于拼接SQL(会产生SQL注入问题),`#{}`会替换成占位符(不会产生SQL注入问题),这里的区别与`Mybatis`一致 + +## 如何循环拼接参数 + +两种办法: +- `in (#{ids})`的语法会自动对集合参数展开 +```javascript +var ids = [1,2,3,4,5,6]; +return db.select('select * from sys_user where id in(#{ids})'); +//会自动变成select * from sys_user where id in(?,?,?,?,?,?) +``` +- 循环拼接SQL +```javascript +var list = [1,2,3,4,5]; +var sql = "select * from sys_user where "; +for(index,item in list){ + sql = sql + 'id = #{list['+index+']}'; + if(index + 1 < list.size()){ + sql = sql + ' or '; + } +} +return db.select(sql); +``` + +## 多数据源如何配置 +编写java代码如下: +```java +@Bean +public MagicDynamicDataSource magicDynamicDataSource(){ + MagicDynamicDataSource dynamicDataSource = new MagicDynamicDataSource(); + dynamicDataSource.setDefault(ds1); + dynamicDataSource.add("slave",ds2); + return dynamicDataSource; +} +``` + +脚本中使用: +```javascript +db.select('select * from sys_user'); //使用默认数据源 +db.slave.select('select * from sys_user'); //使用slave数据源 +``` + +## SQL执行报错java.sql.SQLFeatureNotSupportedException: null + +原因:druid版本过低,升级至最新版后即可。 + +## 如何自定义返回结果 +- 通过配置文件进行配置,具体参考[spring-boot配置](https://www.ssssssss.org/magic-api/pages/config/spring-boot/) +- 通过`自定义JSON结果`,具体定义方法查看[自定义JSON结果](https://www.ssssssss.org/magic-api/pages/base/response/) +- 通过`自定义拦截器`拦截返回自己想要的格式,具体定义方法查看[自定义拦截器](https://www.ssssssss.org/magic-api/pages/senior/interceptor/) +- 通过`spring`的拦截器返回想要的格式,如`ResponseBodyAdvice`,`HandlerMethodReturnValueHandler`(这种方式目前会影响到UI,故不推荐使用) + +## 页面加载缓慢 + +由于`monaco-editor`编辑器比较大,建议开启压缩静态资源 +```yaml +server.compression.enabled=true #启用压缩 +server.compression.min-response-size=256 #大于256kb时压缩 +``` + +## 脚本内容被转义 + +出现这种情况,请检查自身项目是否有`XSS`一类的过滤器,需要把`UI`界面对应的后台接口排除掉即可。 + +## 执行测试无响应 + +目前已知有两种情况: +- 使用了Spring Boot 2.3.5版本,升级至2.3.6解决 +- 使用了`nginx`代理,加一条配置`proxy_buffering off;`解决 + +## 访问UI404 + +- 请检查访问路径是否正确 +- 请检查`magic-editor`包是否被引入 +- 如果是拉源码运行,则需要编译一下前端 +- 如果以上确定没问题,请检查应用中是否有关于`mvc`的配置,如果有请检查是否是`extends WebMvcConfigurationSupport`的形式,是的话,改成`implements WebMvcConfigurer`的形式 +- 如以上问题均不存在,请提[ISSUE](https://gitee.com/ssssssss-team/magic-api/issues) 或加群700818216反馈 + +## 无法DEBUG或无法查看日志 + +由于`DEBUG`和日志是依赖于`WebSocket`实现的,所以需要`WebSocket`支持。 +- 请检查`Web`容器是否支持`WebSocket`,如果不支持需要引入对应依赖或更换支持`WebSocket`的`Web`容器 +- 请检查是否使用了`nginx`之类的代理,如果使用了,需要对配置其支持`WebSocket`,样例如下: +```nginx +location /magic/web/console { + proxy_pass http://localhost:9999; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_read_timeout 900s; +} +``` + +## 保存图片(Blob)数据到数据库 +假设将图片的二进制数据传输到body.img中, sql可以这么写 +```javascript +var sql = """ + insert into img_table(img) + values(#{img::sql('blob')}) +"""; +``` diff --git a/magic-script-skill/references/http-module.md b/magic-script-skill/references/http-module.md new file mode 100644 index 0000000..5d00c2b --- /dev/null +++ b/magic-script-skill/references/http-module.md @@ -0,0 +1,97 @@ +# HTTP模块 + +## 模块说明 +`http`模块是基于`RestTemplate`封装而来,目前只做了少量的封装。对于一些通用的配置可以使用自定义`RestTemplate`来实现 + +```java +@Bean +public HttpModule magicHttpModule() { + RestTemplate template = new RestTemplate(); + // 对RestTemplate进行配置. + return new HttpModule(template); +} +``` + +## 引用模块 +```javascript +import http; +``` + +## connect +- 入参:`url`:`string` +- 返回值:`HttpModule` +- 函数说明:创建新的http请求对象 + +```javascript +import http; +http.connect("http://localhost:9999/sql/select") +``` + +## 设置URL参数、表单参数、Header +```javascript +import http; +http.param('url_param1','url_param_value1') // 设置URL参数 + .param({ // 批量设置URL参数 + url_param_2 : 2, + url_param_3 : 3, + }) + .data('form_param1','form_param_value1') // 设置表单参数 + .data({ // 批量设置表单参数 + form_param_2 : 2, + form_param_3 : 3, + }) + .header('header_param1','header_param_value1') // 设置header参数 + .header({ // 批量设置header参数 + header_param_2 : 2, + header_param_3 : 3, + }) +``` + +## body +- 入参:`body`:`Object` +- 函数说明:设置请求Body + +```javascript +import http; +http.connect('..').body({ + id: 1, + name: 'magic-api' +}); +``` + +## entity +- 入参: `entity`: `HttpEntity` +- 函数说明:自定义`HttpEntity` + +```javascript +import http; +http.connect('..').entity(entity) +``` + +## contentType +- 入参: `contentType`: `String`或`MediaType` +- 函数说明:定义请求内容类型 + +```javascript +import http; +http.connect('..').contentType('application/json') +``` + +## 请求方法 +- `post()` - POST请求 +- `get()` - GET请求 +- `delete()` - DELETE请求 +- `put()` - PUT请求 +- `head()` - HEAD请求 +- `patch()` - PATCH请求 +- `options()` - OPTIONS请求 +- `trace()` - TRACE请求 + +## execute +- 返回值:`ResponseEntity` +- 函数说明:执行对应的请求 + +```javascript +import http; +return http.connect('http://localhost:9999/sql/select').post().getBody() +``` diff --git a/magic-script-skill/references/java-integration.md b/magic-script-skill/references/java-integration.md new file mode 100644 index 0000000..d8add96 --- /dev/null +++ b/magic-script-skill/references/java-integration.md @@ -0,0 +1,42 @@ +# 脚本调用Java + +## 注入Spring Bean +```javascript +// 第一种方式 +import xx.xxx.xxx.xxx.UserService; // 使用类名 +return UserService.selectUserList(); + +// 第二种方式 +import "userUservice" as userService; // 使用Bean名 +return userService.selectUserList(); +``` + +## 调用静态方法 +```javascript +import xxx.xxx.xx.xx.xx.StringUtils; +return StringUtils.isBlank(""); +``` + +## 调用普通方法 +```javascript +// 对于java.util、java.lang 包下的类,可以直接使用。 +return new ArrayList(); + +// 对于其他类需要import +import "java.text.SimpleDateFormat"; +return new SimpleDateFormat("yyyy-MM-dd").format(new Date()); +``` + +## 调用magic-api的接口 +```javascript +// 可以在脚本中直接调用,非http方式 +import "@get:/api/sys/user/list" as userList; // 导入定义的GET请求的 /api/sys/user/list 接口。 +// 脚本中变量是共享给调用者的。所以无需指定参数传入。只需要在本脚本中定义该变量即可。 +return userList(); +``` + +## 调用magic-api的函数 +```javascript +import "@/common/encode/md5" as md5; // 导入页面上定义的函数信息 +return md5('123456'); +``` diff --git a/magic-script-skill/references/keywords.md b/magic-script-skill/references/keywords.md new file mode 100644 index 0000000..52b3ffe --- /dev/null +++ b/magic-script-skill/references/keywords.md @@ -0,0 +1,108 @@ +# 关键字、运算符、数据类型 + +## 关键字 + +| 关键字 | 含义 | +|--------|------| +| var | 定义变量 | +| if | 条件语句的引导词 | +| else | 用在条件语句中,表明当条件不成立时的分支 | +| for | for循环语句 | +| in | 与for配合使用 | +| while | while循环语句 | +| continue | 执行下一次循环 | +| break | 跳出循环 | +| return | 终止当前过程的执行并正常退出到上一个执行过程中 | +| exit | 终止当前脚本,并退出返回,如`exit 200,'执行成功',[1,2,3];` | +| assert | 断言 | +| instanceof | 判断一个对象是否为一个类的实例 | +| 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'` 或 `"hello"` | +| string | `"""多行文本块,主要用于编写SQL"""` | +| Pattern | `/\d+/g`,`/pattern/gimuy` 用于定义正则 | +| lambda | `()=>expr`、`(param1,param2....)=>{...}` | +| list | `[1,2,3,4,5]` | +| map | `{key : value,key1 : value}` 或 `{[key] : "value"}` | + +## 三元运算符 + +三元运算符是`if`语句的简写形式,其工作方式类似于Java中,例如`true ? "yes" : "no"` + +增强的`if`和三元运算符,不再强制值必须是布尔类型,可以写`if(xxx)`的形式当`xxx`为以下情况时为`false`、其它情况为`true`: +- `null` +- 空集合 +- 空Map +- 空数组 +- 数值==0 +- 空字符串 +- `false` diff --git a/magic-script-skill/references/lambda-async.md b/magic-script-skill/references/lambda-async.md new file mode 100644 index 0000000..6c4e39c --- /dev/null +++ b/magic-script-skill/references/lambda-async.md @@ -0,0 +1,102 @@ +# Lambda表达式与异步调用 + +## Lambda表达式 + +### 映射(map) +```javascript +var list = [ + {sex : 0,name : '小明',age : 19}, + {sex : 1,name : '小花',age : 18} +]; +var getAge = (age) => age > 18 ? '成人' : '未成年' +return list.map(item => { + age : getAge(item.age), + sex : item.sex == 0 ? '男' : '女', + name : item.name +}); +// 结果:[{sex: "男", name: "小明", age: "成人"}, {sex: "女", name: "小花", age: "未成年"}] +``` + +### 过滤(filter) +```javascript +var list = [ + {sex : 0,name : '小明'}, + {sex : 1,name : '小花'} +] +return list.filter(item => item.sex == 0); +// 结果:[{sex: 0, name: "小明"}] +``` + +### 过滤+映射(filter + map) +```javascript +var list = [ + {sex : 0,name : '小明'}, + {sex : 1,name : '小花'} +] +return list.filter(item => item.sex == 0).map(item => { + sex : item.sex == 0 ? '男' : '女', + name : item.name +}); +// 结果:[{sex: "男", name: "小明"}] +``` + +### 分组(group) +默认聚合为List +```javascript +var result = [ + { xxx : 1, yyy : 2, value : 11}, + { xxx : 1, yyy : 2, value : 22}, + { xxx : 2, yyy : 2, value : 33} +]; + +return result.group(item => item.xxx + '_' + item.yyy) +// 结果:{"1_2": [{...}, {...}], "2_2": [{...}]} +``` + +自定义聚合对象 +```javascript +return result.group(item => item.xxx + '_' + item.yyy,list => { + count : list.size(), + sum : list.map(v=>v.value).sum(), + avg : list.map(v=>v.value).avg() +}) +// 结果:{"1_2": {"avg": 16.5, "count": 2, "sum": 33}, "2_2": {"avg": 33, "count": 1, "sum": 33}} +``` + +### 关联(join) +```javascript +var year2019 = [ + { "pt":2019, "item_code":"code_1", "sum_price":2234 }, + { "pt":2019, "item_code":"code_2", "sum_price":234 } +]; +var year2018 = [ + { "pt":2018, "item_code":"code_1", "sum_price":1234.0 } +]; +return year2019.join(year2018, (left, right) => left.item_code == right.item_code, (left, right) => { + '年份' : left.pt, + '编号' : left.item_code, + '今年' : left.sum_price, + '去年' : right == null ? 'unknow' : right.sum_price +}); +``` + +## 异步调用 + +### 普通方法 +```javascript +// 使用async关键字,会启动一个线程去执行,返回Future +var user1 = async db.select("select * from sys_user where id = 1"); +var user2 = async db.select("select * from sys_user where id = 2"); +// 调用get方法表示阻塞等待获取结果 +return [user1.get(),user2.get()]; +``` + +### lambda +```javascript +var list = []; +for(index in range(1,10)){ + // 当异步中使用外部变量时,为了确保线程安全的变量,可以将其放在形参中 + list.add(async (index)=>db.select("select * from sys_user where id = #{index}")); +} +return list.map(item=>item.get()); +``` diff --git a/magic-script-skill/references/linq.md b/magic-script-skill/references/linq.md new file mode 100644 index 0000000..5709f0d --- /dev/null +++ b/magic-script-skill/references/linq.md @@ -0,0 +1,76 @@ +# Linq + +## 基本语法 +```sql + select + tableAlias.*|[tableAlias.]field[ columnAlias] + [,tableAlias.field2[ columnAlias2][,…]] + from expr[,…] tableAlias + [[left ]join expr tableAlias2 on condition] + [where condition] + [group by tableAlias.field[,...]] + [having condition] + [order by tableAlias.field[asc|desc][,tableAlias.field[asc|desc]]] + [limit expr [offset expr]] +``` + +## 执行步骤 +- 先从`from`子句创建虚拟表VT1 +- 处理`join`,创建虚拟表VT2,筛选符合条件`condition`的行加入到虚拟表VT2中 +- 处理`where` 将符合`condition`的行加入虚拟表VT1中 +- 处理`group by` 对虚拟表VT1、VT2进行分组操作,将符合`having condition`的值加入虚拟表VT3中 +- 处理`select` 从VT3中选择指定的列,加入虚拟表VT4中 +- 处理`order by` 对虚拟表VT4进行排序 +- 处理`limit` + +## select子句 +```sql +select t.name,sum(t.score) score,t.* +``` +> select 中带有聚合函数的,应该有group by语句,否则不会进行聚合处理 + +## from子句 +```sql +-- 以下三种方式均可(别名是必须的) +from [{name: 'Gitee'},[name:'Github']] t +from results t +from {name:'Gitee'} t +``` +> from 跟着的必须是`List`或者`Map` + +## join子句 +```sql +-- 以下三种方式均可(别名是必须的) +[left] join [{name: 'Gitee'},[name:'Github']] t1 on t1.name = t.name +[left] join results t1 on 1 = 1 +[left] join {name:'Gitee'} t1 on t1.name = 'Gitee' and 1=1 +``` + +## where子句 +```sql +-- or 等价于|| and 等价于 && 可以混合使用。 +where t.name = 'Gitee' or t.name = 'Github' and 1=1 && 2=2 +``` + +## group by子句 +```sql +group by t.name, t1.xxx +``` + +## having 子句 +```sql +having count(t.name) > 1 +``` + +## order by子句 +```sql +-- asc可以不写,默认是asc +order by t.name desc,t.xxx +``` + +## limit 子句 +```sql +limit 1 -- 固定取第一项,返回值会是对象,而非List +limit pageSize offset (page - 1) * pageSize +limit pageSize +``` diff --git a/magic-script-skill/references/log-module.md b/magic-script-skill/references/log-module.md new file mode 100644 index 0000000..4fd0204 --- /dev/null +++ b/magic-script-skill/references/log-module.md @@ -0,0 +1,15 @@ +# 日志模块 + +## 引用模块 +```javascript +import log; +``` + +## 使用 +```javascript +import log; //org.slf4j.Logger +// 使用方法与SLF4J完全一致 +log.info('Hello'); +log.info('Hello {}','MagicAPI'); +log.debug('test'); +``` diff --git a/magic-script-skill/references/magic-module.md b/magic-script-skill/references/magic-module.md new file mode 100644 index 0000000..a201251 --- /dev/null +++ b/magic-script-skill/references/magic-module.md @@ -0,0 +1,45 @@ +# Magic模块 + +## 引用模块 +```javascript +import magic; +``` + +## call +- 入参:`method`:`String` 定义的请求方法 +- 入参:`path`:`String` 定义的路径 +- 入参:`parameters`:`Map` 变量信息 +- 返回值:`Object` +- 函数说明:执行MagicAPI中的接口,返回值带code和message信息 + +```javascript +return magic.call('get','execute/sql',{ + message : 'Hello,Magic API!' //传入参数 +}) +``` + +## execute +- 入参:`method`:`String` 定义的请求方法 +- 入参:`path`:`String` 定义的请求路径 +- 入参:`parameters`:`Map` 变量信息 +- 返回值:`Object` +- 函数说明:执行MagicAPI中的接口,返回原始内容,不包含code以及message信息 + +```javascript +return magic.execute('get','execute/sql',{ + message : 'Hello,Magic API!' //传入参数 +}) +``` + +## invoke +- 入参:`path`:`String` 函数路径 +- 入参:`parameters`:`Map` 变量信息 +- 返回值:`Object` +- 函数说明:执行MagicAPI中的函数 + +```javascript +return magic.invoke('/test/add',{ + a: 1, + b: 2 +}) +``` diff --git a/magic-script-skill/references/math-functions.md b/magic-script-skill/references/math-functions.md new file mode 100644 index 0000000..5209f65 --- /dev/null +++ b/magic-script-skill/references/math-functions.md @@ -0,0 +1,39 @@ +# 数学函数 + +## round +- 入参:`number`:`Number` 目标值 +- 入参:`len`:`int` 要保留的小数位数 可省略,默认0 +- 返回值:`Number` +- 函数说明:四舍五入保留N位小数 + +```javascript +return round(123.456d,2); //123.46 +``` + +## floor +- 入参:`number`:`Number` 目标值 +- 返回值:`Number` +- 函数说明:向下取整 + +```javascript +return floor(123.456d); // 123; +``` + +## ceil +- 入参:`number`:`Number` 目标值 +- 返回值:`Number` +- 函数说明:向上取整 + +```javascript +return ceil(123.456d); // 124; +``` + +## percent +- 入参:`number`:`Number` 目标值 +- 入参:`len`:`int` 要保留的小数 可省略,默认0 +- 返回值:`String` +- 函数说明:将数值转为百分比 + +```javascript +return percent(0.1289999999,2); // "12.90%" +``` diff --git a/magic-script-skill/references/number-extensions.md b/magic-script-skill/references/number-extensions.md new file mode 100644 index 0000000..988f094 --- /dev/null +++ b/magic-script-skill/references/number-extensions.md @@ -0,0 +1,51 @@ +# Number扩展方法 + +`java.lang.Number`的扩展方法,用于数值类型的扩展 + +## round +- 入参:`number`:`int` 要保留的小数 +- 返回值:`Number` +- 函数说明:四舍五入保留N位小数 + +```javascript +var value = 123.456d; +return value.round(2); //123.46 +``` + +## toFixed +- 入参:`number`:`int` 要保留的小数 +- 返回值:`String` +- 函数说明:四舍五入保留N位小数(和JS一样,强制限制位数) + +```javascript +var value = 123.456d; +return value.toFixed(10); // "123.4560000000" +``` + +## floor +- 返回值:`Number` +- 函数说明:向下取整 + +```javascript +var value = 123.456d; +return value.floor(); // 123; +``` + +## ceil +- 返回值:`Number` +- 函数说明:向上取整 + +```javascript +var value = 123.456d; +return value.ceil(); // 124; +``` + +## asPercent +- 入参:`number`:`int` 要保留的小数 +- 返回值:`String` +- 函数说明:将数值转为百分比 + +```javascript +var value = 0.1289999999; +return value.asPercent(2); // "12.90%" +``` diff --git a/magic-script-skill/references/object-extensions.md b/magic-script-skill/references/object-extensions.md new file mode 100644 index 0000000..5c4270a --- /dev/null +++ b/magic-script-skill/references/object-extensions.md @@ -0,0 +1,129 @@ +# Object扩展方法 + +## asInt +- 入参:`defaultValue`:`int` 选填,当转换失败时返回默认值,默认为`0` +- 返回值:`int` +- 函数说明:转对象为int类型 + +```javascript +var obj = '123'; +return obj.asInt(); +//return obj.asInt(1); //转换失败时,返回1 +``` + +## asDouble +- 入参:`defaultValue`:`double` 选填,当转换失败时返回默认值,默认为`0.0` +- 返回值:`double` +- 函数说明:转对象为`double`类型 + +```javascript +var obj = '123'; +return obj.asDouble(); +//return obj.asDouble(1.0d); //转换失败时,返回1.0d +``` + +## asDecimal +- 入参:`defaultValue`:`BigDecimal` 选填,当转换失败时返回默认值,默认为`null` +- 返回值:`BigDecimal` +- 函数说明:转对象为`BigDecimal`类型 + +```javascript +var obj = '123.456'; +return obj.asDecimal(); +//return obj.asDecimal(1.5m); //转换失败时,返回1.5m +``` + +## asFloat +- 入参:`defaultValue`:`float` 选填,当转换失败时返回默认值,默认为`0.0f` +- 返回值:`float` +- 函数说明:转对象为`float`类型 + +```javascript +var obj = '123'; +return obj.asFloat(); +//return obj.asFloat(1.0f); //转换失败时,返回1.0f +``` + +## asLong +- 入参:`defaultValue`:`long` 选填,当转换失败时返回默认值,默认为`0L` +- 返回值:`long` +- 函数说明:转对象为`long`类型 + +```javascript +var obj = '123'; +return obj.asLong(); +//return obj.asLong(1L); //转换失败时,返回1L +``` + +## asByte +- 入参:`defaultValue`:`byte` 选填,当转换失败时返回默认值,默认为`0b` +- 返回值:`byte` +- 函数说明:转对象为`byte`类型 + +```javascript +var obj = '123'; +return obj.asByte(); +//return obj.asByte(1b); //转换失败时,返回1b +``` + +## asShort +- 入参:`defaultValue`:`short` 选填,当转换失败时返回默认值,默认为`0s` +- 返回值:`short` +- 函数说明:转对象为`short`类型 + +```javascript +var obj = '123'; +return obj.asShort(); +//return obj.asShort(1s); //转换失败时,返回1s +``` + +## asDate +- 入参:`formats`:`String` 可变参数,日期格式 +- 返回值:`Date` +- 函数说明:转对象为`Date`类型 + +```javascript +var obj = '2020-01-01 08:00:00'; +return obj.asDate('yyyy-MM-dd HH:mm:ss','yyyy-MM-dd HH:mm'); +``` + +## asString +- 入参:`defaultValue`:`String` 选填,当转换失败时返回默认值,默认为`null` +- 返回值:`String` +- 函数说明:转对象为`String`类型 + +```javascript +var obj = 123; +return obj.asString(); +//return obj.asString("empty"); //转换失败时,返回"empty" +``` + +## is +- 入参:`type`:`String/Class` 判断是否该类型 +- 返回值:`boolean` +- 函数说明:判断是否是指定类型 + +```javascript +import 'java.util.Date' as Date; +var str = 'hello,MagicAPI'; +return str.is('string'); // true +return str.is('java.lang.String'); // true +return str.is('java.lang.Integer'); // false +return str.is(Date); // false +``` + +## 类型判断方法 +- `isString()` - 判断是否是String类型 +- `isInt()` - 判断是否是int类型 +- `isLong()` - 判断是否是long类型 +- `isDouble()` - 判断是否是double类型 +- `isFloat()` - 判断是否是float类型 +- `isByte()` - 判断是否是byte类型 +- `isBoolean()` - 判断是否是boolean类型 +- `isShort()` - 判断是否是short类型 +- `isDecimal()` - 判断是否是decimal类型 +- `isDate()` - 判断是否是Date类型 +- `isArray()` - 判断是否是数组 +- `isList()` - 判断是否是List +- `isMap()` - 判断是否是Map +- `isCollection()` - 判断是否是集合 diff --git a/magic-script-skill/references/other-functions.md b/magic-script-skill/references/other-functions.md new file mode 100644 index 0000000..5f24315 --- /dev/null +++ b/magic-script-skill/references/other-functions.md @@ -0,0 +1,55 @@ +# 其它函数 + +## print +- 入参:`target`:`Object` 要打印的对象 +- 函数说明:打印 + +```javascript +print('abc'); // 等同于 System.out.print("abc"); +``` + +## println +- 入参:`target`:`Object` 要打印的对象 +- 函数说明:打印并换行 + +```javascript +println('abc'); // 等同于 System.out.println("abc"); +``` + +## printf +- 入参:`format`:`String` 要打印的对象 +- 入参:`target`: `Object` 参数值,可以写多个 +- 函数说明:按照格式打印并换行 + +```javascript +printf('%s:%s', 'a','b'); // 等同于 System.out.printf("%s:%S", "a", "b"); +``` + +## not_null +- 入参:`target` : `Object` 判断的模板 +- 返回值:`boolean` +- 函数说明:判断值不是`null` + +```javascript +return not_null(target); // 等同于 target != null +``` + +## is_null +- 入参:`target` : `Object` 判断的模板 +- 返回值:`boolean` +- 函数说明:判断值是`null` + +```javascript +return is_null(target); // 等同于 target == null +``` + +## ifnull +- 入参:`target`:`Object` 判断的目标 +- 入参:`trueValue`:`Object` 为空时的值 +- 返回值:`Object` +- 函数说明:对空值进行判断,返回特定值 + +```javascript +return ifnull(null,1) // 1 +// return ifnull(0,1) // 0 +``` diff --git a/magic-script-skill/references/page.md b/magic-script-skill/references/page.md new file mode 100644 index 0000000..47fef04 --- /dev/null +++ b/magic-script-skill/references/page.md @@ -0,0 +1,32 @@ +# 分页查询 + +## 自动分页 +`db.page`可从形如`xxx?page=1&size=10`的url中获取分页参数。 + +```javascript +// 自动从请求参数中获取页码(默认为page)、页大小(默认为size) +return db.page(""" + select * from sys_user +""") +``` + +## 手动分页 +可手动传入分页参数。 + +```javascript +return db.page(""" + select * from sys_user +""", 10, 20) // 跳过前20条查10条(limit, offset) +``` + +## 自定义分页参数 +可根据需要在自己的项目中,调整以下分页参数。 + +```yaml +magic-api: + page: + size: size # 页大小的请求参数名称 缺省时为size + page: page # 页码的请求参数名称 缺省时为page + default-page: 1 # 自定义默认首页 缺省时为1 + default-size: 10 # 自定义为默认页大小 缺省时为10 +``` diff --git a/magic-script-skill/references/pattern-extensions.md b/magic-script-skill/references/pattern-extensions.md new file mode 100644 index 0000000..d74cc5d --- /dev/null +++ b/magic-script-skill/references/pattern-extensions.md @@ -0,0 +1,13 @@ +# Pattern扩展方法 + +`java.util.regex.Pattern`的扩展方法 + +## test +- 入参:`source`:`String` 目标字符串 +- 返回值:`boolean` +- 函数说明:校验文本是否符合正则 + +```javascript +var regx = /^\d+$/; +return regx.test('123456') // true +``` diff --git a/magic-script-skill/references/quick-crud.md b/magic-script-skill/references/quick-crud.md new file mode 100644 index 0000000..44d3cd3 --- /dev/null +++ b/magic-script-skill/references/quick-crud.md @@ -0,0 +1,125 @@ +# 增删改查 + +## SQL参数 + +### #{} 注入参数 +作用和`mybatis`一致,都是将`#{}`区域替换为占位符`?` +```javascript +var id = 123; +return db.select(""" + select * from sys_user where id = #{id} +"""); +// 运行时生成的SQL为:select * from sys_user where id = ? +``` + +### ${} 拼接参数 +作用和`mybatis`一致,都是将`${}`区域替换为对应的字符串 +```javascript +var id = 123; +return db.select(""" + select * from sys_user where id = ${id} +"""); +// 运行时生成的SQL为:select * from sys_user where id = 123 +``` + +## 动态SQL参数 +通过`?{condition,expression}`来实现动态拼接`SQL` +```javascript +return db.select("select * from sys_user ?{id,where id = #{id}}"); +// 当id有值时,生成SQL:select * from sys_user where id = ? +// 当id无值时,生成SQL:select * from sys_user +``` + +## 切换数据源 +```javascript +// 从数据源key定义为slave的库中查询 +return db.slave.select(""" + select * from sys_user +""") +``` + +## SQL缓存 +```javascript +// 将查询结果缓存到名为user_cache的缓存中,有效期1小时 +return db.cache("user_cache", 3600 * 1000).select(""" + select * from sys_user +""") +``` + +## 使用事务 + +### 自动事务 +```javascript +var val = db.transaction(()=>{ + var v1 = db.update('...'); + var v2 = db.update('....'); + return v2; +}); +return val; +``` + +### 手动事务 +```javascript +var tx = db.transaction(); //开启事务 +try{ + var value = db.update('...'); + tx.commit(); // 提交事务 + return value; +}catch(e){ + tx.rollback(); // 回滚事务 +} +``` + +## Mybatis语法支持 + +### if +```javascript +var sql = """ +select * from test_data + where 1 = 1 + + and id = #{id} + +""" +return db.select(sql) +``` + +### where +```javascript +var sql = """ +select * from test_data + + + and id = #{id} + + +""" +return db.select(sql) +``` + +### set、trim +```javascript +var sql = """ +update test_data + + + name = #{name} + + + where `id` = #{id} +""" +return db.update(sql) +``` + +### foreach +```javascript +var sql = """ +select * from test_data +where id in + + #{item} + +""" +return db.select(sql) +``` diff --git a/magic-script-skill/references/quick-param.md b/magic-script-skill/references/quick-param.md new file mode 100644 index 0000000..4d4950b --- /dev/null +++ b/magic-script-skill/references/quick-param.md @@ -0,0 +1,47 @@ +# 请求参数获取 + +## RequestParam +``` +GET http://localhost:9999/xxx/xxx?name=abc&age=49 +``` +这样的`URL`参数`magic-api` 会自动将`name`和`age`映射为同名变量。 + +## 表单参数 +``` +POST http://localhost:9999/xxx/xxx +name=abc&age=49 +``` +这样的表单参数`magic-api` 也会自动将`name`和`age`映射为同名变量。 + +## Request Header参数获取 +`magic-api` 会对所有`RequestHeader`统一封装为一个名为`header`的变量 +如要获取 `token` 可以通过`header.token` 来获取 + +## Request Body参数获取 +对于`RequestBody` `magic-api`会将整个请求体映射为`body`变量,如: +```json +{ + "name": "magic-api", + "version": "9.9.9" +} +``` +如要获取`name`属性 则可通过 `body.name` 来获取 + +如果提交的body为数组或者List, `body`为数组。 + +## Path参数获取 +主要是针对`URL`定义为`http://localhost:9999/user/{id}` 的类似接口 +如要获取path路径上的id可通过`path.id` 或 `id`来获取。 + +对于请求时使用了`http://localhost:9999/user/1?id=2`的请求, `id`变量的值将是`RequestParam`中的值,此时可以通过`path.id` 来避免冲突。 + +## Cookie参数获取 +`magic-api` 会对所有`Cookie`统一封装为一个名为`cookie`的对象。 +如要获取 `JSESSIONID` 可以通过`cookie.JSESSIONID` 来获取。 + +## Session参数获取 +`magic-api` 会将`HttpSession`封装为一个名为`session`的变量 +要获取`session`中的值,可以通过`session.xxx`来获取 + +## 注意事项 +如果脚本自定义变量和参数变量冲突,自定义变量优先。 diff --git a/magic-script-skill/references/quick-start.md b/magic-script-skill/references/quick-start.md new file mode 100644 index 0000000..73c7c8a --- /dev/null +++ b/magic-script-skill/references/quick-start.md @@ -0,0 +1,66 @@ +# 快速入门 + +## 初始化工程 +创建一个空的`Spring Boot`工程, 以`mysql`作为默认数据库进行演示。 + +## 添加依赖 +引入`Spring Boot Starter`父工程: +```xml + + org.springframework.boot + spring-boot-starter-parent + spring-boot-latest-version + + +``` + +引入`magic-api-spring-boot-starter`依赖: +```xml + + org.ssssssss + magic-api-spring-boot-starter + magic-api-lastest-version + +``` + +## 配置 +`application.yml` +```yaml +server: + port: 9999 +magic-api: + web: /magic/web + resource: + location: D:/data/magic-api + +spring: + datasource: + driver-class-name: com.mysql.jdbc.Driver + url: jdbc:mysql://localhost:3306/magic-api-test?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8 + username: root + password: test +``` + +## 访问api管理界面 +启动项目之后,访问`http://localhost:9999/magic/web` 即可看到Web页面 + +## 三分钟写出查询接口 +**1. 创建分组** +点击创建分组按钮后,输入分组信息,点击创建。 + +**2. 新建接口** +右键分组,点击新建接口。在编辑器输入内容后,填写接口名称和及其路径。 + +```javascript +var sql = """ +select * from test_data +""" +return db.select(sql) +``` + +`ctrl+s`保存后,即可访问接口。 + +**3.访问接口** +``` +> curl http://localhost:9999/test/test +``` diff --git a/magic-script-skill/references/request-module.md b/magic-script-skill/references/request-module.md new file mode 100644 index 0000000..c9b9e68 --- /dev/null +++ b/magic-script-skill/references/request-module.md @@ -0,0 +1,64 @@ +# Request模块 + +## 引用模块 +```javascript +import request; +``` + +## getFile +- 入参:`name`:`string` +- 返回值:`MultipartFile` +- 函数说明:获取上传的文件 + +```javascript +import request; +request.getFile('image'); +``` + +## getFiles +- 入参:`name`:`String` +- 返回值:`List` +- 函数说明:获取上传的文件集合 + +```javascript +import request; +request.getFiles('image'); +``` + +## getValues +- 入参:`name`:`String` +- 返回值:`List` +- 函数说明:获取提交的数组参数 + +```javascript +import request; +return request.getValues('name'); +``` + +## getHeaders +- 入参:`name`:`String` +- 返回值:`List` +- 函数说明:获取请求的header数组 + +```javascript +import request; +return request.getHeaders('xxx'); +``` + +## get +- 返回值:`MagicHttpServletRequest` +- 函数说明:获取`Request`对象 + +```javascript +import request; +request.get(); +``` + +## getClientIP +- 返回值:`String` +- 函数说明:获取客户端`IP` + +```javascript +import request; +return request.getClientIP(); +``` diff --git a/magic-script-skill/references/response-module.md b/magic-script-skill/references/response-module.md new file mode 100644 index 0000000..0128f13 --- /dev/null +++ b/magic-script-skill/references/response-module.md @@ -0,0 +1,141 @@ +# Response模块 + +## 引用模块 +```javascript +import response; +``` + +## page +- 入参:`total`:`long` +- 入参:`values`:`list` +- 返回值:`Object` +- 函数说明:构建分页结果 + +```javascript +import response; +//返回: 共计10条,第一页的5条数据 +return response.page(10,[1,2,3,4,5]); +``` + +## json +- 入参:`value`:`Object` +- 返回值:`ResponseEntity` +- 函数说明:构建Json结果 + +```javascript +import response; +//直接返回该json,不会被包装处理 +return response.json({ + success : true, + message : '执行成功' +}); +``` + +## text +- 入参:`value`:`String` 文本内容 +- 返回值:`ResponseEntity` +- 函数说明:输出文本 + +```javascript +import response; +//直接返回该text,不会被包装处理 +return response.text('ok'); +``` + +## redirect +- 入参:`url`:`String` 目标网址 +- 返回值:`ResponseEntity` +- 函数说明:重定向 + +```javascript +import response; +//重定向到该地址,内部利用HttpServletResponse的sendRedirect方法 +return response.redirect('/xxx/xx'); +``` + +## download +- 入参:`value`:`Object` +- 入参:`filename`:`文件名` +- 返回值:`ResponseEntity` +- 函数说明:下载文件 + +```javascript +import response; +return response.download('文件内容','test.txt'); +``` + +## image +- 入参:`value`:`Object` +- 入参:`mine`:`String` +- 返回值:`ResponseEntity` +- 函数说明:主要用于输出图片 + +```javascript +import response; +// 输出图片 +return response.image(bytes,'image/png'); +``` + +## addHeader +- 入参:`key`:`string` +- 入参:`value`:`String` +- 返回值:无返回值 +- 函数说明:添加Response Header + +```javascript +import response; +response.addHeader('AccessToken','123'); +``` + +## setHeader +- 入参:`key`:`string` +- 入参:`value`:`String` +- 返回值:无返回值 +- 函数说明:设置Response Header + +```javascript +import response; +response.setHeader('AccessToken','123'); +``` + +## addCookie +- 入参:`key`:`string` +- 入参:`value`:`String` +- 入参:`options`:`Map` cookie参数,可选 +- 返回值:无返回值 +- 函数说明:添加Cookie + +```javascript +import response; +response.addCookie('cookieKey','cookieValue'); +response.addCookie('cookieKey','cookieValue',{ + path : '/', + httpOnly : true, + domain : 'ssssssss.org', + maxAge : 3600 +}); +``` + +## addCookies +- 入参:`cookies`:`Map` cookie Map,必填 +- 入参:`options`:`Map` cookie参数,可选 +- 返回值:无返回值 +- 函数说明:批量添加Cookie + +```javascript +import response; +response.addCookies({ + cookieKey1 : 'cookieValue1', + cookieKey2 : 'cookieValue2', +}); +``` + +## getOutputStream +- 返回值:`OutputStream` +- 函数说明:获取`ServletOutputStream` + +注意:在调用`getOutputStream`后 返回值应为`response.end()` 告诉框架无需处理返回值。 + +## end +- 返回值:无返回值 +- 函数说明:取消返回默认的json结构,通过其他方式的输出结果(如:调用outputstream输出) diff --git a/magic-script-skill/references/script-syntax.md b/magic-script-skill/references/script-syntax.md new file mode 100644 index 0000000..d6b5418 --- /dev/null +++ b/magic-script-skill/references/script-syntax.md @@ -0,0 +1,163 @@ +# 脚本语法详解 + +## for循环 + +### 循环集合 +```javascript +var list = [1,2,3]; +for(index,item in list){ //如果不需要index,也可以写成for(item in list) + 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 +``` + +## while循环 +```javascript +var count = 100; +var sum = 0; +while(count){ + sum = sum + count; + count = count - 1; +} +return sum; // 5050 +``` + +## 循环map +```javascript +var map = { + key1 : 123, + key2 : 456 +}; +for(key,value in map){ //如果不需要key,也可以写成for(value in map) + println(key + ":" + value); +} +// 结果:key1:123, key2:456 +``` + +## Import导入 + +### 导入Java类 +```javascript +import 'java.lang.System' as System; +import 'javax.sql.DataSource' as ds; +import 'org.apache.commons.lang3.StringUtils' as string; +import 'java.text.*' // 此写法跟Java一致 + +System.out.println('调用System打印'); +System.out.println(ds); +System.out.println(string.isBlank('')); +System.out.println(new SimpleDateFormat('yyyy-MM-dd').format(new Date())); +``` + +### 导入已定义的模块 +```javascript +import log; //导入log模块,并定义一个与模块名相同的变量名 +//import log as logger; //导入log模块,并赋值给变量 logger +log.info('Hello {}','Magic API!') +``` + +## new创建对象 +```javascript +import 'java.util.Date' as Date;//创建之前先导包,不支持.*的操作 +return new Date(); +``` + +## 异步调用 + +### 异步调用方法 +```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()); // 循环获取结果 +``` + +## exit +语法格式为 `exit expr[,expr][,expr]....` + +在`magic-api`中只取前三个值,分别对应`code`、`message`、`data` + +如:`exit 400,'参数填写有误'` + +## assert +语法格式为 `assert expr : expr[,expr][,expr]....` + +如:`assert a == 1 : 400, 'a的值应为1'` 相当于 +```javascript +if(a != 1){ + exit 400, 'a的值应为1' +} +``` + +## 类型转换 +通过`::`进行类型转换,如`xxx::int`、`xxx::double`等,当前支持转换类型有`int`、`double`、`long`、`byte`、`short`、`float`、`date` + +```javascript +var a = "1"; +return { + v1: a::int, + v2: a::int(0), //转换失败时,值为0 + v3: "2020-01-01"::date('yyyy-MM-dd') //转为Date +} +``` + +`::sql`支持将数据转换为对应的sql类型,比如: +```javascript +img::sql('blob') +``` +可传入的参数请参考`java.sql.Types`中定义的常量,不区分大小写。 + +## 嵌入其它脚本语言 +```javascript +var name = "hello"; +var test = ```javascript + name + ' ~ world' +```; +return test(); +``` + +## 可选链操作符 +可选链操作符(`?.`)允许读取位于连接对象链深处的属性的值,而不必明确验证链中的每个引用是否有效。 + +```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] +``` + +### map 展开 +```javascript +var map = {key2:2} +System.out.println({key1:1,...map,key3:3}) // 结果:{key1=1, key2=2, key3=3} +``` diff --git a/magic-script-skill/references/single-table.md b/magic-script-skill/references/single-table.md new file mode 100644 index 0000000..2ea28ae --- /dev/null +++ b/magic-script-skill/references/single-table.md @@ -0,0 +1,104 @@ +# 单表操作 + +操作入口:`db.table('table_name')` + +## logic +- 作用:设置本查询是带有逻辑删除的,在执行`delete`方法时,会转换为`update`语句,在执行`select`相关方法时,会拼接`logic_field <> logic_value` + +## withBlank +- 作用:设置后续插入或修改时,不过滤空值。 + +## column +- 入参:`column`: `String` 列名 +- 作用:设置要查询列,`select`语句中有效 + +## column +- 入参:`column`: `String` 列名 +- 入参:`value` : `Object` 值 +- 作用:设置要操作的列的值,非`select`语句中有效 + +## primary +- 入参:`primary`: `String` 主键 +- 入参:`defaultValue`: `Object` 插入时使用的默认值,可省略 +- 作用:设置主键列,在`update`中语句有效,或`save`方法判断标准 + +## insert +- 入参: `data` : `Map` `insert`的列和值,可省略(通过`column`设置) + +```javascript +// insert into sys_user(user_name,role) values('李富贵','admin') +return db.table('sys_user').insert({ user_name : '李富贵', role : 'admin'}) +``` + +## batchInsert +- 入参: `collection` : `Collection` `insert`的列和值的集合 +- 入参: `batchSize` : `int` batchSize + +```javascript +return db.table('sys_user').batchInsert([ + { user_name : '李富贵', role : 'admin'}, + { user_name : '王二狗', role : 'admin'}, + { user_name : '管理员', role : 'super-admin'}, +]) +``` + +## update +- 入参: `data` : `Map` `insert`的列和值,可省略(通过`column`设置) +- 入参:`isUpdateBlank`: `boolean` 是否更新空值字段(可省略,默认为`false`) + +```javascript +// update sys_user set user_name = '王二狗' where id = 1 +return db.table('sys_user').primary('id').update({ id: 1, user_name : '王二狗'}) +``` + +## save +- 入参: `data` : `Map` `insert`或`update`的列和值,可省略(通过`column`设置) +- 入参:`beforeQuery` : `boolean` 是否根据id查询有没有数据,可省略(默认`false`) + +```javascript +// insert into sys_user(id,user_name) values('xxx','王二狗'); +return db.table('sys_user').primary('id', uuid()).save({user_name: '王二狗'}); +// insert into sys_user(user_name) values('王二狗'); +return db.table('sys_user').primary('id').save({user_name: '王二狗'}); +// update sys_user set user_name = '王二狗' where id = 1 +return db.table('sys_user').primary('id').save({id: 1,user_name: '王二狗'}); +``` + +## select +查询list(与db.select 作用相同) + +```javascript +// select * from sys_user +return db.table('sys_user').select() +``` + +## page +分页查询(与db.page 作用相同) + +```javascript +// select * from sys_user +return db.table('sys_user').page() +``` + +## where +设置查询条件 + +- eq --> `==` +- ne --> `<>` +- lt --> `<` +- gt --> `>` +- lte --> `<=` +- gte --> `>=` +- in --> `in` +- notIn --> `not in` +- like --> `like` +- notLike --> `not like` + +```javascript +// select * from sys_user where user_name like '%李富贵%' and role = 'admin' +return db.table('sys_user') + .where() + .like('user_name','%李富贵%') + .eq('role','admin') + .select() +``` diff --git a/magic-script-skill/references/sql-param.md b/magic-script-skill/references/sql-param.md new file mode 100644 index 0000000..dae1f73 --- /dev/null +++ b/magic-script-skill/references/sql-param.md @@ -0,0 +1,125 @@ +# SQL参数 + +## #{} 注入参数 +作用和`mybatis`一致,都是将`#{}`区域替换为占位符`?` + +```javascript +var id = 123; +return db.select(""" + select * from sys_user where id = #{id} +"""); +// 运行时生成的SQL为:select * from sys_user where id = ? +``` + +此方法可以避免`sql`注入。 + +## ${} 拼接参数 +作用和`mybatis`一致,都是将`${}`区域替换为对应的字符串 + +```javascript +var id = 123; +return db.select(""" + select * from sys_user where id = ${id} +"""); +// 运行时生成的SQL为:select * from sys_user where id = 123 +``` + +## 动态SQL参数 +通过`?{condition,expression}`来实现动态拼接`SQL` + +```javascript +return db.select("select * from sys_user ?{id,where id = #{id}}"); +// 当id有值时,生成SQL:select * from sys_user where id = ? +// 当id无值时,生成SQL:select * from sys_user + +return db.select("select * from sys_user ?{id!=null&&id.length() > 3,where id = #{id}}"); +``` + +## 循环拼接参数 +两种办法: + +### in语法自动展开 +```javascript +var ids = [1,2,3,4,5,6]; +//会自动变成select * from sys_user where id in(?,?,?,?,?,?) +return db.select('select * from sys_user where id in(#{ids})'); +``` + +### 循环拼接SQL +```javascript +var list = [1,2,3,4,5]; +var sql = "select * from sys_user where "; +for(index,item in list){ + sql = sql + 'id = #{list['+index+']}'; + if(index + 1 < list.size()){ + sql = sql + ' or '; + } +} +return db.select(sql); +``` + +## Mybatis语法支持 + +### 支持的关键字 +- `` +- `` +- `` +- `` +- `` +- `` +- `` + +### if +```javascript +var sql = """ +select * from test_data + where 1 = 1 + + and id = #{id} + +""" +return db.select(sql) +``` + +### where +```javascript +var sql = """ +select * from test_data + + + and id = #{id} + + +""" +return db.select(sql) +``` + +### set、trim +```javascript +var sql = """ +update test_data + + + name = #{name} + + + content = #{content} + + + where `id` = #{id} +""" +return db.update(sql) +``` + +### foreach +```javascript +var sql = """ +select * from test_data +where id in + + #{item} + +""" +return db.select(sql) +``` diff --git a/magic-script-skill/references/string-functions.md b/magic-script-skill/references/string-functions.md new file mode 100644 index 0000000..f50b960 --- /dev/null +++ b/magic-script-skill/references/string-functions.md @@ -0,0 +1,26 @@ +# 字符串函数 + +## uuid +- 返回值: `String` `32`位无`-`的`UUID` + +```javascript +return uuid(); // 等同于 UUID.randomUUID().toString().replace("-", ""); +``` + +## is_blank +- 入参:`target`:`String` 判断的目标 +- 返回值:`boolean` +- 函数说明:判断字符串是否为空 + +```javascript +return is_blank(''); // true 等同于 StringUtils.isBlank 一致 +``` + +## not_blank +- 入参:`target`:`String` 判断的目标 +- 返回值:`boolean` +- 函数说明:判断字符串是否不为空 + +```javascript +return not_blank(''); // false 等同于 !is_blank('') +``` diff --git a/magic-script-skill/references/validate.md b/magic-script-skill/references/validate.md new file mode 100644 index 0000000..c9ee5b8 --- /dev/null +++ b/magic-script-skill/references/validate.md @@ -0,0 +1,22 @@ +# 参数校验 + +## 自动验证 +在magic-api的Web界面中,可配置: +- 必填验证 +- 表达式验证 +- 正则验证 + +## 手动验证 +对于表达式和正则无法实现的可以通过脚本来实现。 + +```javascript +var count = db.selectInt(""" + select count(*) from sys_user where phone = #{phone} +""") +// count 值应该为0,如果不为0则验证不予通过。 +assert count == 0 : 400, '手机号已存在'; +// 上述写法可以转换为 +if(count != 0){ + exit 400, '手机号已存在' +} +```