lrf há 1 ano atrás
commit
d36ed597f4
94 ficheiros alterados com 3042 adições e 0 exclusões
  1. 43 0
      .gitignore
  2. 21 0
      LICENSE
  3. 23 0
      README.md
  4. 73 0
      pom.xml
  5. 16 0
      src/main/java/org/ssssssss/example/MagicAPIExampleApplication.java
  6. 37 0
      src/main/java/org/ssssssss/example/components/JsonUtil.java
  7. 23 0
      src/main/java/org/ssssssss/example/components/TestFunctions.java
  8. 128 0
      src/main/java/org/ssssssss/example/configuration/MagicAPIConfiguration.java
  9. 61 0
      src/main/java/org/ssssssss/example/interceptor/CustomRequestInterceptor.java
  10. 28 0
      src/main/java/org/ssssssss/example/interceptor/CustomSqlInterceptor.java
  11. 63 0
      src/main/java/org/ssssssss/example/interceptor/CustomUIAuthorizationInterceptor.java
  12. 139 0
      src/main/java/org/ssssssss/example/interceptor/SimpleAuthorizationInterceptor.java
  13. 31 0
      src/main/java/org/ssssssss/example/provider/CustomApiServiceProvider.java
  14. 38 0
      src/main/java/org/ssssssss/example/provider/CustomJsonValueProvider.java
  15. 36 0
      src/main/java/org/ssssssss/example/provider/CustomLanguageProvider.java
  16. 29 0
      src/main/java/org/ssssssss/example/provider/CustomMapperProvider.java
  17. 23 0
      src/main/java/org/ssssssss/example/provider/CustomPageProvider.java
  18. 145 0
      src/main/java/org/ssssssss/example/provider/CustomSqlCache.java
  19. 44 0
      src/main/java/org/ssssssss/example/scripts/CustomFunction.java
  20. 35 0
      src/main/java/org/ssssssss/example/scripts/CustomFunctionExtension.java
  21. 34 0
      src/main/java/org/ssssssss/example/scripts/CustomModule.java
  22. 53 0
      src/main/resources/application.yml
  23. 7 0
      src/main/resources/magic-api/api/1SQL相关/group.json
  24. 34 0
      src/main/resources/magic-api/api/1SQL相关/事务.ms
  25. 21 0
      src/main/resources/magic-api/api/1SQL相关/使用缓存.ms
  26. 44 0
      src/main/resources/magic-api/api/1SQL相关/分页查询.ms
  27. 32 0
      src/main/resources/magic-api/api/1SQL相关/动态参数判断.ms
  28. 46 0
      src/main/resources/magic-api/api/1SQL相关/单表操作_保存.ms
  29. 34 0
      src/main/resources/magic-api/api/1SQL相关/单表操作_查询.ms
  30. 22 0
      src/main/resources/magic-api/api/1SQL相关/查询List.ms
  31. 30 0
      src/main/resources/magic-api/api/1SQL相关/驼峰命名转换.ms
  32. 7 0
      src/main/resources/magic-api/api/2操作案例/group.json
  33. 29 0
      src/main/resources/magic-api/api/2操作案例/http请求.ms
  34. 28 0
      src/main/resources/magic-api/api/2操作案例/json转换.ms
  35. 20 0
      src/main/resources/magic-api/api/2操作案例/使用Spring中的Bean.ms
  36. 26 0
      src/main/resources/magic-api/api/2操作案例/数值转换.ms
  37. 22 0
      src/main/resources/magic-api/api/2操作案例/调用其他接口.ms
  38. 24 0
      src/main/resources/magic-api/api/2操作案例/调用函数.ms
  39. 7 0
      src/main/resources/magic-api/api/3LINQ相关/group.json
  40. 23 0
      src/main/resources/magic-api/api/3LINQ相关/list转tree.ms
  41. 24 0
      src/main/resources/magic-api/api/3LINQ相关/关联.ms
  42. 25 0
      src/main/resources/magic-api/api/3LINQ相关/分组.ms
  43. 33 0
      src/main/resources/magic-api/api/3LINQ相关/字段转换.ms
  44. 28 0
      src/main/resources/magic-api/api/3LINQ相关/空值转换.ms
  45. 40 0
      src/main/resources/magic-api/api/3LINQ相关/行转列.ms
  46. 26 0
      src/main/resources/magic-api/api/3LINQ相关/过滤.ms
  47. 7 0
      src/main/resources/magic-api/api/4lambda相关/group.json
  48. 28 0
      src/main/resources/magic-api/api/4lambda相关/list转tree.ms
  49. 27 0
      src/main/resources/magic-api/api/4lambda相关/关联.ms
  50. 24 0
      src/main/resources/magic-api/api/4lambda相关/分组.ms
  51. 40 0
      src/main/resources/magic-api/api/4lambda相关/动态行转列.ms
  52. 37 0
      src/main/resources/magic-api/api/4lambda相关/字段转换.ms
  53. 27 0
      src/main/resources/magic-api/api/4lambda相关/过滤.ms
  54. 30 0
      src/main/resources/magic-api/api/4lambda相关/过滤和转换.ms
  55. 7 0
      src/main/resources/magic-api/api/5自定义结果/group.json
  56. 20 0
      src/main/resources/magic-api/api/5自定义结果/文件下载.ms
  57. 22 0
      src/main/resources/magic-api/api/5自定义结果/模拟分页.ms
  58. 66 0
      src/main/resources/magic-api/api/5自定义结果/生成验证码.ms
  59. 24 0
      src/main/resources/magic-api/api/5自定义结果/自定义json.ms
  60. 7 0
      src/main/resources/magic-api/api/6基本语法/group.json
  61. 23 0
      src/main/resources/magic-api/api/6基本语法/脚本语法/exit语句.ms
  62. 7 0
      src/main/resources/magic-api/api/6基本语法/脚本语法/group.json
  63. 45 0
      src/main/resources/magic-api/api/6基本语法/脚本语法/if判断.ms
  64. 27 0
      src/main/resources/magic-api/api/6基本语法/脚本语法/try_catch.ms
  65. 23 0
      src/main/resources/magic-api/api/6基本语法/脚本语法/与Java交互.ms
  66. 26 0
      src/main/resources/magic-api/api/6基本语法/脚本语法/可选连.ms
  67. 41 0
      src/main/resources/magic-api/api/6基本语法/脚本语法/各类运算符.ms
  68. 35 0
      src/main/resources/magic-api/api/6基本语法/脚本语法/定义lambda.ms
  69. 25 0
      src/main/resources/magic-api/api/6基本语法/脚本语法/异步执行.ms
  70. 28 0
      src/main/resources/magic-api/api/6基本语法/脚本语法/扩展运算符.ms
  71. 31 0
      src/main/resources/magic-api/api/6基本语法/脚本语法/类型转换.ms
  72. 7 0
      src/main/resources/magic-api/api/Web相关/group.json
  73. 20 0
      src/main/resources/magic-api/api/Web相关/下载文件.ms
  74. 52 0
      src/main/resources/magic-api/api/Web相关/参数自动验证.ms
  75. 66 0
      src/main/resources/magic-api/api/Web相关/生成图片.ms
  76. 48 0
      src/main/resources/magic-api/api/Web相关/获取请求参数.ms
  77. 21 0
      src/main/resources/magic-api/api/Web相关/设置Cookie.ms
  78. 21 0
      src/main/resources/magic-api/api/Web相关/设置Header.ms
  79. 32 0
      src/main/resources/magic-api/api/循环/for循环.ms
  80. 7 0
      src/main/resources/magic-api/api/循环/group.json
  81. 22 0
      src/main/resources/magic-api/api/循环/lambda循环list.ms
  82. 31 0
      src/main/resources/magic-api/api/循环/lambda循环map.ms
  83. 24 0
      src/main/resources/magic-api/api/循环/while.ms
  84. 27 0
      src/main/resources/magic-api/api/循环/循环list.ms
  85. 33 0
      src/main/resources/magic-api/api/循环/循环map.ms
  86. 7 0
      src/main/resources/magic-api/api/模块相关/group.json
  87. 25 0
      src/main/resources/magic-api/api/模块相关/mongo.ms
  88. 25 0
      src/main/resources/magic-api/api/模块相关/redis.ms
  89. 22 0
      src/main/resources/magic-api/api/模块相关/手动验证参数.ms
  90. 39 0
      src/main/resources/magic-api/api/模块相关/打印日志.ms
  91. 21 0
      src/main/resources/magic-api/api/模块相关/读取配置.ms
  92. 37 0
      src/main/resources/magic-api/function/测试函数/add.ms
  93. 7 0
      src/main/resources/magic-api/function/测试函数/group.json
  94. 16 0
      src/main/resources/magic-api/function/测试函数/函数嵌套.ms

+ 43 - 0
.gitignore

@@ -0,0 +1,43 @@
+# Compiled class file
+*.class
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
+*.iml
+*.flattened-pom.xml
+
+# ide files #
+.classpath
+.project
+.mymetadata
+/.idea/
+/captures/
+.DS_Store
+.idea/
+
+# setting folders #
+.settings/
+.svn/
+.bin/
+.git/
+target/
+lib/

+ 21 - 0
LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2021 小东
+
+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.

+ 23 - 0
README.md

@@ -0,0 +1,23 @@
+## mysql 建表语句
+```sql
+CREATE TABLE `magic_api_file` (
+  `file_path` varchar(512) NOT NULL,
+  `file_content` mediumtext,
+  PRIMARY KEY (`file_path`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
+```
+## 备份表建表语句
+```sql
+CREATE TABLE `magic_api_backup` (
+  `id` varchar(32) NOT NULL COMMENT '原对象ID',
+  `create_date` bigint(13) NOT NULL COMMENT '备份时间',
+  `tag` varchar(32) DEFAULT NULL COMMENT '标签',
+  `type` varchar(32) DEFAULT NULL COMMENT '类型',
+  `name` varchar(64) DEFAULT NULL COMMENT '原名称',
+  `content` mediumtext COMMENT '备份内容',
+  `create_by` varchar(64) DEFAULT NULL COMMENT '操作人',
+  PRIMARY KEY (`id`,`create_date`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
+```
+具体查询提供的函数在:
+magic-api/org/ssssssss/magicapi/modules/table where.class中

+ 73 - 0
pom.xml

@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>2.4.5</version>
+        <relativePath/>
+    </parent>
+    <groupId>org.ssssssss</groupId>
+    <artifactId>dbServer</artifactId>
+    <version>1.0.0</version>
+    <packaging>jar</packaging>
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-jdbc</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+        </dependency>
+        <dependency>
+		    <groupId>com.oracle</groupId>
+		    <artifactId>ojdbc6</artifactId>
+		    <version>12.1.0.1-atlassian-hosted</version>
+		</dependency>
+        <dependency>
+            <groupId>org.ssssssss</groupId>
+            <artifactId>magic-api-spring-boot-starter</artifactId>
+            <version>1.4.0</version>
+        </dependency>
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger2</artifactId>
+            <version>2.9.2</version>
+        </dependency>
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger-ui</artifactId>
+            <version>2.9.2</version>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>druid</artifactId>
+            <version>1.2.1</version>
+        </dependency>
+    </dependencies>
+    
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <configuration>
+                    <mainClass>org.ssssssss.example.MagicAPIExampleApplication</mainClass>
+                    <finalName>dbServer</finalName>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 16 - 0
src/main/java/org/ssssssss/example/MagicAPIExampleApplication.java

@@ -0,0 +1,16 @@
+package org.ssssssss.example;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+
+@SpringBootApplication
+@EnableSwagger2	// 配置swagger 文档
+public class MagicAPIExampleApplication {
+
+	public static void main(String[] args) {
+		SpringApplication.run(MagicAPIExampleApplication.class, args);
+	}
+}
+

+ 37 - 0
src/main/java/org/ssssssss/example/components/JsonUtil.java

@@ -0,0 +1,37 @@
+package org.ssssssss.example.components;
+import java.util.Map;
+
+import org.springframework.stereotype.Component;
+import org.ssssssss.magicapi.config.MagicModule;
+import org.ssssssss.script.annotation.Comment;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+@Component
+public class JsonUtil implements MagicModule{
+
+	@Override
+	public String getModuleName() {
+		// TODO Auto-generated method stub
+		return "JsonUtil";
+	}
+	
+	@Comment("将json转换成Map")
+	public Map getQuery(String str) {
+		System.out.println(str);
+		ObjectMapper mapper = new ObjectMapper();
+		Map map = null;
+		try {
+			map = mapper.readValue(str, Map.class);
+		} catch (JsonMappingException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		} catch (JsonProcessingException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		return map;
+	}
+
+}

+ 23 - 0
src/main/java/org/ssssssss/example/components/TestFunctions.java

@@ -0,0 +1,23 @@
+package org.ssssssss.example.components;
+import org.springframework.stereotype.Component;
+import org.ssssssss.magicapi.config.MagicModule;
+import org.ssssssss.script.annotation.Comment;
+@Component  //注入到Spring容器中
+public class TestFunctions implements MagicModule {
+
+    /**
+    * 返回模块名,使用时通过import指令导入之后使用
+    */
+	@Override
+	public String getModuleName() {
+		return "test";    // 模块名称
+	}
+    
+    /**
+    *   调用打印方法
+    */
+    @Comment("方法名的注释(用于提示)")
+	public void println(@Comment("参数名的提示(用于提示)")String value) {
+		System.out.println(value);
+	}
+}

+ 128 - 0
src/main/java/org/ssssssss/example/configuration/MagicAPIConfiguration.java

@@ -0,0 +1,128 @@
+package org.ssssssss.example.configuration;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.ssssssss.example.interceptor.CustomRequestInterceptor;
+import org.ssssssss.example.interceptor.CustomUIAuthorizationInterceptor;
+import org.ssssssss.example.provider.*;
+import org.ssssssss.example.scripts.CustomFunction;
+import org.ssssssss.example.scripts.CustomFunctionExtension;
+import org.ssssssss.example.scripts.CustomModule;
+import org.ssssssss.magicapi.adapter.Resource;
+import org.ssssssss.magicapi.config.MagicDynamicDataSource;
+import org.ssssssss.magicapi.provider.GroupServiceProvider;
+import org.ssssssss.magicapi.provider.PageProvider;
+
+import javax.sql.DataSource;
+
+/**
+ * magic-api 配置类
+ * 以下只配置了多数据源
+ * 其它如果有需要可以自行放开 // @Bean 注释查看效果
+ */
+@Configuration
+public class MagicAPIConfiguration {
+
+	/**
+	 * 配置多数据源
+	 *
+	 * @see MagicDynamicDataSource
+	 */
+	@Bean
+	public MagicDynamicDataSource magicDynamicDataSource(DataSource dataSource) {
+		MagicDynamicDataSource dynamicDataSource = new MagicDynamicDataSource();
+		dynamicDataSource.setDefault(dataSource); // 设置默认数据源
+		dynamicDataSource.add("slave", dataSource);
+		return dynamicDataSource;
+	}
+
+
+	/**
+	 * 配置自定义JSON结果
+	 */
+	// @Bean
+	public CustomJsonValueProvider customJsonValueProvider() {
+		return new CustomJsonValueProvider();
+	}
+
+	/**
+	 * 配置分页获取方式
+	 */
+	// @Bean
+	public PageProvider pageProvider() {
+		return new CustomPageProvider();
+	}
+
+	/**
+	 * 自定义UI界面鉴权
+	 */
+	// @Bean
+	public CustomUIAuthorizationInterceptor customUIAuthorizationInterceptor() {
+		return new CustomUIAuthorizationInterceptor();
+	}
+
+	/**
+	 * 自定义请求拦截器(鉴权)
+	 */
+	// @Bean
+	public CustomRequestInterceptor customRequestInterceptor() {
+		return new CustomRequestInterceptor();
+	}
+
+	/**
+	 * 自定义SQL缓存
+	 */
+	// @Bean
+	public CustomSqlCache customSqlCache() {
+		return new CustomSqlCache();
+	}
+
+	/**
+	 * 自定义函数
+	 */
+	// @Bean
+	public CustomFunction customFunction() {
+		return new CustomFunction();
+	}
+
+	/**
+	 * 自定义方法扩展
+	 */
+	// @Bean
+	public CustomFunctionExtension customFunctionExtension() {
+		return new CustomFunctionExtension();
+	}
+
+	/**
+	 * 自定义模块
+	 */
+	// @Bean
+	public CustomModule customModule() {
+		return new CustomModule();
+	}
+
+	/**
+	 * 自定义脚本语言
+	 */
+	// @Bean
+	public CustomLanguageProvider customLanguageProvider() {
+		return new CustomLanguageProvider();
+	}
+
+	/**
+	 * 自定义列名转换
+	 */
+	// @Bean
+	public CustomMapperProvider customMapperProvider() {
+		return new CustomMapperProvider();
+	}
+
+	/**
+	 * 自定义接口脚本加解密
+	 */
+	// @Bean
+	public CustomApiServiceProvider customApiServiceProvider(Resource resource, GroupServiceProvider groupServiceProvider) {
+		return new CustomApiServiceProvider(resource, groupServiceProvider);
+	}
+
+}

+ 61 - 0
src/main/java/org/ssssssss/example/interceptor/CustomRequestInterceptor.java

@@ -0,0 +1,61 @@
+package org.ssssssss.example.interceptor;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.ssssssss.magicapi.interceptor.RequestInterceptor;
+import org.ssssssss.magicapi.model.ApiInfo;
+import org.ssssssss.magicapi.model.JsonBean;
+import org.ssssssss.magicapi.model.Options;
+import org.ssssssss.script.MagicScriptContext;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * 自定义请求拦截器,可实现鉴权
+ * https://ssssssss.org/guide/custom/interceptor.html
+ * @see org.ssssssss.magicapi.interceptor.RequestInterceptor
+ */
+public class CustomRequestInterceptor implements RequestInterceptor {
+
+	private static final Logger logger = LoggerFactory.getLogger(CustomRequestInterceptor.class);
+
+	/**
+	 * 接口请求之前
+	 * @param info	接口信息
+	 * @param context	脚本变量信息
+	 */
+	@Override
+	public Object preHandle(ApiInfo info, MagicScriptContext context, HttpServletRequest request, HttpServletResponse response) throws Exception {
+		Object user = null; // = XXXUtils.getUser(request);
+		logger.info("{} 请求接口:{}", user, info.getName());
+		// 接口选项配置了需要登录
+		if ("true".equals(info.getOptionValue(Options.REQUIRE_LOGIN))) {
+			if (user == null) {
+				return new JsonBean<>(401, "用户未登录");
+			}
+		}
+		String role = info.getOptionValue(Options.ROLE);
+		if (StringUtils.isNotBlank(role)/* && user.hasRole(role)*/) {
+			return new JsonBean<>(403, "用户权限不足");
+		}
+		String permission = info.getOptionValue(Options.PERMISSION);
+		if (StringUtils.isNotBlank(permission)/* && user.hasPermission(permission)*/) {
+			return new JsonBean<>(403, "用户权限不足");
+		}
+		return null;
+	}
+
+	/**
+	 * 接口执行之后
+	 * @param info	接口信息
+	 * @param context	变量信息
+	 * @param value 即将要返回到页面的值
+	 */
+	@Override
+	public Object postHandle(ApiInfo info, MagicScriptContext context, Object value, HttpServletRequest request, HttpServletResponse response) throws Exception {
+		logger.info("{} 执行完毕,返回结果:{}", info.getName(), value);
+		return null;
+	}
+}

+ 28 - 0
src/main/java/org/ssssssss/example/interceptor/CustomSqlInterceptor.java

@@ -0,0 +1,28 @@
+package org.ssssssss.example.interceptor;
+
+import org.ssssssss.magicapi.interceptor.SQLInterceptor;
+import org.ssssssss.magicapi.model.RequestEntity;
+import org.ssssssss.magicapi.modules.BoundSql;
+
+import java.util.Arrays;
+
+
+/**
+ * 自定义SQL拦截器
+ * https://ssssssss.org/guide/custom/sql.html
+ * @see org.ssssssss.magicapi.interceptor.SQLInterceptor
+ */
+public class CustomSqlInterceptor implements SQLInterceptor {
+
+	/**
+	 * 执行SQL之前
+	 */
+	@Override
+	public void preHandle(BoundSql boundSql, RequestEntity requestEntity) {
+		// 改写SQL
+		boundSql.setSql(boundSql.getSql());
+		// 改写参数
+		boundSql.setParameters(Arrays.asList(boundSql.getParameters()));
+	}
+
+}

+ 63 - 0
src/main/java/org/ssssssss/example/interceptor/CustomUIAuthorizationInterceptor.java

@@ -0,0 +1,63 @@
+package org.ssssssss.example.interceptor;
+
+import org.ssssssss.magicapi.exception.MagicLoginException;
+import org.ssssssss.magicapi.interceptor.Authorization;
+import org.ssssssss.magicapi.interceptor.AuthorizationInterceptor;
+import org.ssssssss.magicapi.interceptor.MagicUser;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * 自定义UI界面鉴权
+ * https://ssssssss.org/guide/custom/authorization.html
+ * @see org.ssssssss.magicapi.interceptor.AuthorizationInterceptor
+ */
+public class CustomUIAuthorizationInterceptor implements AuthorizationInterceptor {
+
+	/**
+	 * 配置UI是否需要登录
+	 */
+	@Override
+	public boolean requireLogin() {
+		return true;
+	}
+
+	/**
+	 * 自定义登录方法
+	 *
+	 * @param username 用户名
+	 * @param password 密码
+	 */
+	@Override
+	public MagicUser login(String username, String password) throws MagicLoginException {
+		if (!"123456".equals(password) && !"admin".equals(username)) {
+			throw new MagicLoginException("密码不正确");
+		}
+		return new MagicUser("1", username, "token..123456");
+	}
+
+	/**
+	 * 根据Token获取用户信息
+	 */
+	@Override
+	public MagicUser getUserByToken(String token) throws MagicLoginException {
+		if ("token..123456".equals(token)) {
+			return new MagicUser("1", "admin", "token..123456");
+		}
+		throw new MagicLoginException("token无效");
+	}
+
+	/**
+	 * 是否允许访问
+	 * @param magicUser	用户信息
+	 * @return
+	 */
+	@Override
+	public boolean allowVisit(MagicUser magicUser, HttpServletRequest request, Authorization authorization) {
+		if(authorization == Authorization.DELETE || authorization == Authorization.UPLOAD){
+			// 禁止上传和删除
+			return false;
+		}
+		return true;
+	}
+}

+ 139 - 0
src/main/java/org/ssssssss/example/interceptor/SimpleAuthorizationInterceptor.java

@@ -0,0 +1,139 @@
+package org.ssssssss.example.interceptor;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+import org.ssssssss.magicapi.exception.MagicLoginException;
+import org.ssssssss.magicapi.interceptor.Authorization;
+import org.ssssssss.magicapi.interceptor.AuthorizationInterceptor;
+import org.ssssssss.magicapi.interceptor.MagicUser;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.UnsupportedEncodingException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 自定义多用户名密码登录,以及权限控制
+ * 使用方式在项目工程中@import 或者 @Bean注解使spring管理。
+ * magic-api.ext.auth.enable=true #启用
+ * #magic-api.ext.auth.users.用户名=123456  #配置用户信息
+ * #magic-api.ext.auth.denyOptions.用户名=DELETE #配置用户禁用的权限 {@linkplain Authorization}
+ * #magic-api.ext.auth.users.xx=password
+ * #magic-api.ext.auth.denyOptions.xx=DELETE
+ * @author 冰点
+ * @date 2021-5-11 17:17:52
+ */
+
+@Configuration
+@ConditionalOnProperty(prefix = "magic-api.ext.auth", name = "enable", havingValue = "true", matchIfMissing = false)
+@ConfigurationProperties(prefix = "magic-api.ext.auth")
+public class SimpleAuthorizationInterceptor implements AuthorizationInterceptor {
+    private static final Logger log = LoggerFactory.getLogger(SimpleAuthorizationInterceptor.class);
+    /**
+     * 加密因子
+     */
+    @Value("${magic-api.ext.auth.encryIndex:1}")
+    private int encryIndex;
+    /**
+     * 用户信息
+     */
+    private Map<String, String> users;
+    /**
+     * 用户权限
+     */
+    private Map<String, String> denyOptions;
+
+
+    public SimpleAuthorizationInterceptor() {
+        log.info("已启用多用户登录扩展,如需关闭请magic-api.ext.auth.enable=false");
+    }
+
+    /**
+     * 配置是否需要登录
+     */
+    @Override
+    public boolean requireLogin() {
+        return true;
+    }
+
+    /**
+     * 根据Token获取User
+     */
+    @Override
+    public MagicUser getUserByToken(String token) throws MagicLoginException {
+        try {
+            String[] userInfo = getUserInfoByToken(token);
+            MagicUser magicUser = new MagicUser(userInfo[0], userInfo[0], getToken(userInfo[0], userInfo[1]));
+            if (users.containsKey(magicUser.getUsername()) && users.get(magicUser.getUsername()).equals(userInfo[1])) {
+                return magicUser;
+            }
+        } catch (Exception e) {
+            log.error("token无效,请重新登录,如果还有问题,可手动清除localStorage中magic-token");
+        }
+        throw new MagicLoginException("token无效");
+    }
+
+    @Override
+    public MagicUser login(String username, String password) throws MagicLoginException {
+        // 根据实际情况进行修改。。
+        if (users.containsKey(username) && users.get(username).equals(password)) {
+            return new MagicUser(username, username, getToken(username, password));
+        }
+        throw new MagicLoginException("用户名或密码不正确");
+    }
+
+    /**
+     * 验证是否有权限访问功能
+     */
+    @Override
+    public boolean allowVisit(MagicUser magicUser, HttpServletRequest request, Authorization authorization) {
+        if(denyOptions==null){
+            return true;
+        }
+        String[] denyOption = denyOptions.get(magicUser.getUsername()).split(",");
+        List<String> list = Arrays.asList(denyOption);
+        return !list.contains(authorization.name());
+    }
+
+    public String getToken(String username, String password) throws MagicLoginException {
+        String token = null;
+        try {
+            byte[] b = (username + ";" + password).getBytes("utf-8");
+            for (int i = 0; i < b.length; i++) {
+                b[i] += encryIndex;
+            }
+            token = new String(b);
+            log.debug("本次登录token:[{}]", token);
+        } catch (UnsupportedEncodingException e) {
+            log.info("生成token失败,可能字符集不合法。[{}={}]",username,password);
+            throw new MagicLoginException("用户名或密码配置不合法");
+        }
+        return token;
+    }
+
+    public String[] getUserInfoByToken(String token) throws MagicLoginException {
+        try {
+            byte[] b = token.getBytes();
+            for (int i = 0; i < b.length; i++) {
+                b[i] -= encryIndex;
+            }
+            return new String(b).split(";");
+        } catch (Exception e) {
+            log.error("根据token:[{}]获取用户信息失败", token, e);
+            throw new MagicLoginException("用户名或密码不正确");
+        }
+    }
+
+    public void setUsers(Map<String, String> users) {
+        this.users = users;
+    }
+
+    public void setDenyOptions(Map<String, String> denyOptions) {
+        this.denyOptions = denyOptions;
+    }
+}

+ 31 - 0
src/main/java/org/ssssssss/example/provider/CustomApiServiceProvider.java

@@ -0,0 +1,31 @@
+package org.ssssssss.example.provider;
+
+import org.ssssssss.magicapi.adapter.Resource;
+import org.ssssssss.magicapi.model.ApiInfo;
+import org.ssssssss.magicapi.provider.ApiServiceProvider;
+import org.ssssssss.magicapi.provider.GroupServiceProvider;
+
+/**
+ * 自定义脚本加解密、同理 FunctionServiceProvider 也是类似
+ * @see ApiServiceProvider
+ */
+public class CustomApiServiceProvider extends ApiServiceProvider {
+
+	public CustomApiServiceProvider(Resource workspace, GroupServiceProvider groupServiceProvider) {
+		super(workspace, groupServiceProvider);
+	}
+
+	@Override
+	public void unwrap(ApiInfo info) {
+		String script = info.getScript();
+		// 自行将script解密处理
+		info.setScript(script);
+	}
+
+	@Override
+	public void wrap(ApiInfo info) {
+		String script = info.getScript();
+		// 自行将script加密处理
+		info.setScript(script);
+	}
+}

+ 38 - 0
src/main/java/org/ssssssss/example/provider/CustomJsonValueProvider.java

@@ -0,0 +1,38 @@
+package org.ssssssss.example.provider;
+
+import org.ssssssss.magicapi.model.JsonBean;
+import org.ssssssss.magicapi.model.JsonCodeConstants;
+import org.ssssssss.magicapi.model.RequestEntity;
+import org.ssssssss.magicapi.provider.ResultProvider;
+
+/**
+ * 自定义JSON结果
+ * https://ssssssss.org/guide/custom/json.html
+ * @see org.ssssssss.magicapi.provider.ResultProvider
+ * @see org.ssssssss.magicapi.provider.impl.DefaultResultProvider
+ */
+public class CustomJsonValueProvider implements ResultProvider {
+
+
+	/**
+	 * 构建请求结果
+	 * @param requestEntity 请求相关信息
+	 * @param code          状态码
+	 * @param message       状态说明
+	 * @param data          数据内容,可以通过data的类型判断是否是分页结果进行区分普通结果集和分页结果集
+	 * @return
+	 */
+	@Override
+	public Object buildResult(RequestEntity requestEntity, int code, String message, Object data) {
+		// 分页结果
+//		if (data instanceof PageResult) {
+//			PageResult<?> pageResult = (PageResult<?>) data;
+//			long total = pageResult.getTotal();
+//			return new PageJsonBean(total, pageResult.getList());
+//		}
+		if (code == JsonCodeConstants.SUCCESS.getCode()) {
+			return new JsonBean<>(200, message, data);
+		}
+		return new JsonBean<>(code, message, data);
+	}
+}

+ 36 - 0
src/main/java/org/ssssssss/example/provider/CustomLanguageProvider.java

@@ -0,0 +1,36 @@
+package org.ssssssss.example.provider;
+
+import org.ssssssss.magicapi.provider.LanguageProvider;
+
+import java.util.Map;
+
+/**
+ * 自定义脚本语言
+ * https://ssssssss.org/guide/custom/language.html
+ * @see org.ssssssss.magicapi.provider.LanguageProvider
+ */
+public class CustomLanguageProvider implements LanguageProvider {
+
+	@Override
+	public boolean support(String languageName) {
+		return "custom".equalsIgnoreCase(languageName);
+	}
+
+	/**
+	 * 执行脚本
+	 * @param languageName 语言类型
+	 * @param script	脚本内容
+	 * @param context	当前环境中的变量信息
+	 *
+	 *  var name = "test variable"
+	 *  var func = ```custom
+	 *  // 任意代码
+	 *  ```;
+	 *  return func();
+	 *  //返回结果:hello test variable
+	 */
+	@Override
+	public Object execute(String languageName, String script, Map<String, Object> context) throws Exception {
+		return "hello " + context.get("name");
+	}
+}

+ 29 - 0
src/main/java/org/ssssssss/example/provider/CustomMapperProvider.java

@@ -0,0 +1,29 @@
+package org.ssssssss.example.provider;
+
+import org.ssssssss.magicapi.provider.ColumnMapperProvider;
+
+/**
+ * 自定义列名转换
+ * https://ssssssss.org/guide/custom/column.html
+ * @see org.ssssssss.magicapi.provider.ColumnMapperProvider
+ */
+public class CustomMapperProvider implements ColumnMapperProvider {
+
+	@Override
+	public String name() {
+		return "custom";
+	}
+
+	@Override
+	public String mapping(String columnName) {
+		// 自定义逻辑
+		// 列名转小写。
+		return columnName.toLowerCase();
+	}
+
+	@Override
+	public String unmapping(String name) {
+		// 自定义逻辑实现将转换后的列名还原为转换前的列名
+		return name;
+	}
+}

+ 23 - 0
src/main/java/org/ssssssss/example/provider/CustomPageProvider.java

@@ -0,0 +1,23 @@
+package org.ssssssss.example.provider;
+
+import org.apache.commons.lang3.math.NumberUtils;
+import org.ssssssss.magicapi.model.Page;
+import org.ssssssss.magicapi.provider.PageProvider;
+import org.ssssssss.script.MagicScriptContext;
+
+/**
+ * 自定义获取分页参数
+ * https://ssssssss.org/guide/custom/page.html
+ * @see org.ssssssss.magicapi.provider.PageProvider
+ * @see org.ssssssss.magicapi.provider.impl.DefaultPageProvider
+ */
+public class CustomPageProvider implements PageProvider {
+
+	@Override
+	public Page getPage(MagicScriptContext context) {
+		// 从Request中提取page以及pageSize
+		long page = NumberUtils.toLong(context.getString("page"), 1);
+		long pageSize = NumberUtils.toLong(context.getString("size"), 10);
+		return new Page(page, pageSize);
+	}
+}

+ 145 - 0
src/main/java/org/ssssssss/example/provider/CustomSqlCache.java

@@ -0,0 +1,145 @@
+package org.ssssssss.example.provider;
+
+import org.ssssssss.magicapi.cache.SqlCache;
+
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * 自定义SQL缓存
+ * https://ssssssss.org/guide/custom/cache.html
+ * @see org.ssssssss.magicapi.cache.SqlCache
+ * @see org.ssssssss.magicapi.cache.DefaultSqlCache
+ */
+public class CustomSqlCache extends LinkedHashMap<String, CustomSqlCache.ExpireNode<Object>> implements SqlCache {
+
+	private final String separator = ":";
+
+	private final int capacity;
+
+	private final long expire;
+
+	private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
+
+	public CustomSqlCache() {
+		this(10000, 30 * 60L);
+	}
+
+	public CustomSqlCache(int capacity, long expire) {
+		super((int) Math.ceil(capacity / 0.75) + 1, 0.75f, true);
+		// 容量
+		this.capacity = capacity;
+		// 固定过期时间
+		this.expire = expire;
+	}
+
+	@Override
+	public void put(String name, String key, Object value) {
+		// 封装成过期时间节点
+		put(name, key, value, this.expire);
+	}
+
+	@Override
+	public void put(String name, String key, Object value, long ttl) {
+		long expireTime = ttl > 0 ? (System.currentTimeMillis() + ttl) :
+				(this.expire > -1 ? System.currentTimeMillis() + this.expire : Long.MAX_VALUE);
+		lock.writeLock().lock();
+		try {
+			// 封装成过期时间节点
+			put(name + separator + key, new CustomSqlCache.ExpireNode<>(expireTime, value));
+		} finally {
+			lock.writeLock().unlock();
+		}
+	}
+
+	@Override
+	public Object get(String name, String key) {
+		key = name + separator + key;
+		lock.readLock().lock();
+		CustomSqlCache.ExpireNode<Object> expireNode;
+		try {
+			expireNode = super.get(key);
+		} finally {
+			lock.readLock().unlock();
+		}
+		if (expireNode == null) {
+			return null;
+		}
+		// 惰性删除过期的
+//        if (this.expire > -1L && expireNode.expire < System.currentTimeMillis()) {
+		if (expireNode.expire < System.currentTimeMillis()) {
+			try {
+				lock.writeLock().lock();
+				super.remove(key);
+			} finally {
+				lock.writeLock().unlock();
+			}
+			return null;
+		}
+		return expireNode.value;
+	}
+
+	@Override
+	public void delete(String name) {
+		try {
+			lock.writeLock().lock();
+			Iterator<Map.Entry<String, CustomSqlCache.ExpireNode<Object>>> iterator = super.entrySet().iterator();
+			String prefix = name + separator;
+			// 清除所有key前缀为name + separator的缓存
+			while (iterator.hasNext()) {
+				Map.Entry<String, CustomSqlCache.ExpireNode<Object>> entry = iterator.next();
+				if (entry.getKey().startsWith(prefix)) {
+					iterator.remove();
+				}
+			}
+		} finally {
+			lock.writeLock().unlock();
+		}
+	}
+
+
+	@Override
+	protected boolean removeEldestEntry(Map.Entry<String, CustomSqlCache.ExpireNode<Object>> eldest) {
+		if (this.expire > -1L && size() > capacity) {
+			clean();
+		}
+		// lru淘汰
+		return size() > this.capacity;
+	}
+
+	/**
+	 * 清理已过期的数据
+	 */
+	private void clean() {
+		try {
+			lock.writeLock().lock();
+			Iterator<Map.Entry<String, CustomSqlCache.ExpireNode<Object>>> iterator = super.entrySet().iterator();
+			long now = System.currentTimeMillis();
+			while (iterator.hasNext()) {
+				Map.Entry<String, CustomSqlCache.ExpireNode<Object>> next = iterator.next();
+				// 判断是否过期
+				if (next.getValue().expire < now) {
+					iterator.remove();
+				}
+			}
+		} finally {
+			lock.writeLock().unlock();
+		}
+	}
+
+
+	/**
+	 * 过期时间节点
+	 */
+	static class ExpireNode<V> {
+		long expire;
+		V value;
+
+		ExpireNode(long expire, V value) {
+			this.expire = expire;
+			this.value = value;
+		}
+	}
+}

+ 44 - 0
src/main/java/org/ssssssss/example/scripts/CustomFunction.java

@@ -0,0 +1,44 @@
+package org.ssssssss.example.scripts;
+
+import org.ssssssss.magicapi.config.MagicFunction;
+import org.ssssssss.script.annotation.Comment;
+import org.ssssssss.script.annotation.Function;
+import org.ssssssss.script.functions.DateExtension;
+
+import java.util.Date;
+
+/**
+ * 自定义函数
+ * https://ssssssss.org/guide/custom/function.html
+ * @see org.ssssssss.magicapi.config.MagicFunction
+ */
+public class CustomFunction implements MagicFunction {
+
+	// 脚本中直接使用 now();
+	@Function
+	@Comment("取当前时间")
+	public static Date now() {
+		return new Date();
+	}
+	// 脚本中使用 date_format(now())
+	@Function
+	@Comment("日期格式化")
+	public static String date_format(@Comment("目标日期") Date target) {
+		return target == null ? null : DateExtension.format(target, "yyyy-MM-dd HH:mm:ss");
+	}
+
+	// 脚本中使用 date_format(now(),'yyyy-MM-dd')
+	@Function
+	@Comment("日期格式化")
+	public static String date_format(@Comment("目标日期") Date target, @Comment("格式") String pattern) {
+		return target == null ? null : DateExtension.format(target, pattern);
+	}
+
+	// 脚本中直接使用ifnull() 调用
+	@Function
+	@Comment("判断值是否为空")
+	public static Object ifnull(@Comment("目标值") Object target, @Comment("为空的值") Object trueValue, @Comment("不为空的值") Object falseValue) {
+		return target == null ? trueValue : falseValue;
+	}
+
+}

+ 35 - 0
src/main/java/org/ssssssss/example/scripts/CustomFunctionExtension.java

@@ -0,0 +1,35 @@
+package org.ssssssss.example.scripts;
+
+import org.apache.commons.lang3.math.NumberUtils;
+import org.ssssssss.script.annotation.Comment;
+import org.ssssssss.script.functions.ExtensionMethod;
+
+/**
+ * 自定义扩展方法
+ * https://ssssssss.org/guide/custom/extension.html
+ * @see ExtensionMethod
+ */
+public class CustomFunctionExtension implements ExtensionMethod {
+	/**
+	 * 扩展String方法
+	 */
+	@Override
+	public Class<?> support() {
+		return String.class;
+	}
+
+	/**
+	 *	方法参数至少有一个,且第一个参数必须为support方法返回的类型
+	 *	以将字符串转为int为例,该方法编写如下,最终调用时使用strVar.toInt()调用
+	 *	该方法第一个参数会自动被传入,所以调用时无需传入
+	 *	var str = '123';
+	 *  //以下两种方式都支持
+	 *  return '1234'.toInt();
+	 *  //return str.toInt();
+	 */
+	@Comment("将字符串转为Integer(方法名的提示)")
+	public Integer toInt(String str){    // 第一个参数无需使用@Comment注解
+		return NumberUtils.toInt(str);
+	}
+
+}

+ 34 - 0
src/main/java/org/ssssssss/example/scripts/CustomModule.java

@@ -0,0 +1,34 @@
+package org.ssssssss.example.scripts;
+
+import org.ssssssss.magicapi.config.MagicModule;
+import org.ssssssss.script.annotation.Comment;
+
+/**
+ * 自定义模块
+ * 脚本中使用
+ * import custom;    //导入模块
+ * custom.println('Custom Module!');
+ *
+ * https://ssssssss.org/guide/custom/module.html
+ *
+ * @see org.ssssssss.magicapi.config.MagicModule
+ * @see org.ssssssss.magicapi.modules.SQLModule
+ * @see org.ssssssss.magicapi.modules.MongoModule
+ * @see org.ssssssss.magicapi.modules.RedisModule
+ * @see org.ssssssss.magicapi.modules.AssertModule
+ */
+public class CustomModule implements MagicModule {
+
+	/**
+	 * 模块名称
+	 */
+	@Override
+	public String getModuleName() {
+		return "custom";
+	}
+
+	@Comment("方法名的注释(用于提示)")
+	public void println(@Comment("参数名的提示(用于提示)")String value) {
+		System.out.println(value);
+	}
+}

+ 53 - 0
src/main/resources/application.yml

@@ -0,0 +1,53 @@
+server:
+  port: 6101
+  # 配置静态资源启用 gzip 压缩
+  compression:
+    enabled: true
+    min-response-size: 128
+# 配置主数据源
+spring:
+  jackson:
+    date-format: yyyy-MM-dd HH:mm:ss
+    time-zone: GMT+8
+  datasource:
+    url: jdbc:oracle:thin:@localhost:1521:baoandb 
+    username: baoandba
+    password: baoandb123
+    # url: jdbc:oracle:thin:@localhost:1521:ORCL 
+    # username: LRF
+    # password: 1qaz2wsx
+#  data:
+    # 配置mongo数据源
+#    mongodb:
+#      host: localhost
+#      port: 27017
+#      database: magicapi
+#      username: magicapi
+#      password: 123456
+  # 配置redis数据源
+#  redis:
+#    host: localhost
+#    port: 6379
+#    database: 4
+#    timeout: 5000
+logging:
+  level:
+    org:
+      springframework:
+        jdbc:
+          core:
+            JdbcTemplate: DEBUG #打印SQL
+            StatementCreatorUtils: TRACE  #打印SQL参数
+magic-api:
+  web: /magic/web
+  resource:
+    type: database  # 配置接口存储方式,这里选择存在数据库中
+    table-name: magic_api_file  # 数据库中的表名
+    prefix: /magic-api  # 前缀
+  response-code-config:
+    success: 0 #执行成功的code值
+    invalid: -1 #参数验证未通过的code值
+    exception: 500 #执行出现异常的code值
+  sql-column-case: default
+#    location: classpath:magic-api
+# 其它配置请参考 https://ssssssss.org/config/

+ 7 - 0
src/main/resources/magic-api/api/1SQL相关/group.json

@@ -0,0 +1,7 @@
+{
+  "id" : "08c2af4fd56543e690b14515d83d66ae",
+  "name" : "1SQL相关",
+  "type" : "1",
+  "parentId" : "0",
+  "path" : "/sql"
+}

+ 34 - 0
src/main/resources/magic-api/api/1SQL相关/事务.ms

@@ -0,0 +1,34 @@
+{
+  "id" : "c1f0bc60cedd445faa62042cf9ce35e8",
+  "script" : null,
+  "groupId" : "08c2af4fd56543e690b14515d83d66ae",
+  "name" : "事务",
+  "createTime" : 1615818724895,
+  "updateTime" : 1615818724895,
+  "method" : "GET",
+  "path" : "/transaction",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : null,
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+// 自动事务
+var val = db.transaction(()=>{
+    return db.update("""delete from magic_api_info where id = '999' """);
+});
+return val;
+
+// 手动事务
+var tx = db.transaction();  //开启事务
+try{
+    var value = db.update('...');
+    tx.commit();    // 提交事务
+    return value;
+}catch(e){
+    tx.rollback();  // 回滚事务
+}
+return 'ok'

+ 21 - 0
src/main/resources/magic-api/api/1SQL相关/使用缓存.ms

@@ -0,0 +1,21 @@
+{
+  "id" : "4bb05c67a5e94cf1a3b147cccc25559e",
+  "script" : null,
+  "groupId" : "08c2af4fd56543e690b14515d83d66ae",
+  "name" : "使用缓存",
+  "createTime" : null,
+  "updateTime" : null,
+  "method" : "GET",
+  "path" : "/cache",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : "{\n    \"code\": 1,\n    \"message\": \"success\",\n    \"data\": [\n        {\n            \"1\": 1\n        }\n    ],\n    \"timestamp\": 1615818234132,\n    \"executeTime\": 2\n}",
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+
+return db.cache('sql',2000)  // 使用缓存名为sql的缓存,有效期为2s
+    .select('select 1')

+ 44 - 0
src/main/resources/magic-api/api/1SQL相关/分页查询.ms

@@ -0,0 +1,44 @@
+{
+  "id" : "a105153610374cb4a8102852542c2b7d",
+  "script" : null,
+  "groupId" : "08c2af4fd56543e690b14515d83d66ae",
+  "name" : "分页查询",
+  "createTime" : null,
+  "updateTime" : null,
+  "method" : "GET",
+  "path" : "/page",
+  "parameters" : [ {
+    "name" : "page",
+    "value" : "1",
+    "description" : "页码",
+    "required" : false,
+    "dataType" : "String",
+    "type" : null,
+    "defaultValue" : "1",
+    "validateType" : null,
+    "error" : null,
+    "expression" : null
+  }, {
+    "name" : "size",
+    "value" : "2",
+    "description" : "页大小",
+    "required" : false,
+    "dataType" : null,
+    "type" : null,
+    "defaultValue" : null,
+    "validateType" : null,
+    "error" : null,
+    "expression" : null
+  } ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : "{\n    \"code\": 1,\n    \"message\": \"success\",\n    \"data\": {\n        \"total\": 49,\n        \"list\": [\n            {\n                \"api_name\": \"文件下载\"\n            },\n            {\n                \"api_name\": \"读取配置\"\n            }\n        ]\n    },\n    \"timestamp\": 1615817365659,\n    \"executeTime\": 28\n}",
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+var sql = """
+    select api_name from magic_api_info
+"""
+return db.page(sql);

+ 32 - 0
src/main/resources/magic-api/api/1SQL相关/动态参数判断.ms

@@ -0,0 +1,32 @@
+{
+  "id" : "affaed31406c477790ded329f844a620",
+  "script" : null,
+  "groupId" : "08c2af4fd56543e690b14515d83d66ae",
+  "name" : "动态参数判断",
+  "createTime" : null,
+  "updateTime" : null,
+  "method" : "GET",
+  "path" : "/params",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : "{\n    \"code\": 1,\n    \"message\": \"success\",\n    \"data\": \"ok\",\n    \"timestamp\": 1615818676485,\n    \"executeTime\": 99\n}",
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+var ids = ['1','2','3'];
+
+//具体执行的SQL请看打印的运行日志信息。
+
+db.select('select * from magic_api_info where id in (#{ids})')  //对参数自动展开
+
+//var id = '123';
+db.select("select * from magic_api_info where id = #{id} ")  //#{} 是占位符,${} 是拼接字符串
+
+
+//var name = '123';
+db.select("select * from magic_api_info where id = '123' ?{name,and api_name = #{name}}")  //if 判断
+
+return 'ok';

+ 46 - 0
src/main/resources/magic-api/api/1SQL相关/单表操作_保存.ms

@@ -0,0 +1,46 @@
+{
+  "id" : "74810f0720894ef1846295dff9984ff4",
+  "script" : null,
+  "groupId" : "08c2af4fd56543e690b14515d83d66ae",
+  "name" : "单表操作_保存",
+  "createTime" : null,
+  "updateTime" : null,
+  "method" : "GET",
+  "path" : "/save",
+  "parameters" : [ {
+    "name" : "id",
+    "value" : "2",
+    "description" : "",
+    "required" : true,
+    "dataType" : null,
+    "type" : null,
+    "defaultValue" : "1",
+    "validateType" : null,
+    "error" : null,
+    "expression" : null
+  }, {
+    "name" : "name",
+    "value" : "测试",
+    "description" : "",
+    "required" : false,
+    "dataType" : null,
+    "type" : null,
+    "defaultValue" : null,
+    "validateType" : null,
+    "error" : null,
+    "expression" : null
+  } ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : "{\n    \"code\": 1,\n    \"message\": \"success\",\n    \"data\": 0,\n    \"timestamp\": 1615817982689,\n    \"executeTime\": 7\n}",
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+return db.table('magic_api_info')
+        .primary('id')
+        .save({
+            id, // 当id不为null时做修改,否则做插入
+            api_name: name + Math.random()
+        }) 

Diff do ficheiro suprimidas por serem muito extensas
+ 34 - 0
src/main/resources/magic-api/api/1SQL相关/单表操作_查询.ms


Diff do ficheiro suprimidas por serem muito extensas
+ 22 - 0
src/main/resources/magic-api/api/1SQL相关/查询List.ms


Diff do ficheiro suprimidas por serem muito extensas
+ 30 - 0
src/main/resources/magic-api/api/1SQL相关/驼峰命名转换.ms


+ 7 - 0
src/main/resources/magic-api/api/2操作案例/group.json

@@ -0,0 +1,7 @@
+{
+  "id" : "d528abe95ca74f3cb195425afd7415af",
+  "name" : "2操作案例",
+  "type" : "1",
+  "parentId" : "0",
+  "path" : "/case"
+}

+ 29 - 0
src/main/resources/magic-api/api/2操作案例/http请求.ms

@@ -0,0 +1,29 @@
+{
+  "id" : "578b5f6bb9644ee18573f80c8321fae1",
+  "script" : null,
+  "groupId" : "d528abe95ca74f3cb195425afd7415af",
+  "name" : "http请求",
+  "createTime" : null,
+  "updateTime" : null,
+  "method" : "GET",
+  "path" : "/http",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : "{\n    \"code\": 1,\n    \"message\": \"success\",\n    \"data\": {\n        \"success\": true,\n        \"message\": \"执行成功\"\n    },\n    \"timestamp\": 1615986002116,\n    \"executeTime\": 8\n}",
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+// 本Demo采用Jsoup库进行请求
+import 'org.jsoup.Jsoup' as Jsoup;
+import 'org.jsoup.Connection$Method' as Method;
+import 'org.apache.commons.io.FileUtils' as FileUtils;
+import 'com.fasterxml.jackson.databind.ObjectMapper' as mapper;
+var str = Jsoup.connect('http://127.0.0.1:9999/response/json')
+    .method(Method.GET)
+    .ignoreContentType(true)
+    .execute()
+    .body()
+return mapper.readValue(str,Map.class)

+ 28 - 0
src/main/resources/magic-api/api/2操作案例/json转换.ms

@@ -0,0 +1,28 @@
+{
+  "id" : "5fd0b65310ed4c75a701fd95ce216499",
+  "script" : null,
+  "groupId" : "d528abe95ca74f3cb195425afd7415af",
+  "name" : "json转换",
+  "createTime" : null,
+  "updateTime" : null,
+  "method" : "GET",
+  "path" : "/json",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : "{\n    \"code\": 1,\n    \"message\": \"success\",\n    \"data\": {\n        \"jsonObject\": {\n            \"name\": \"李富贵\"\n        },\n        \"jsonString\": \"{\\\"name\\\":\\\"李富贵\\\"}\"\n    },\n    \"timestamp\": 1615986094038,\n    \"executeTime\": 9\n}",
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+import 'com.fasterxml.jackson.databind.ObjectMapper' as mapper; // 导入Spring中的类
+// 利用jackson进行转换,你也可以选择fastjson、gson进行操作
+var json = {
+    "name" : "李富贵"
+}
+var jsonString = '{"name": "李富贵"}'
+return {
+    'jsonObject' : mapper.readValue(jsonString,Map.class),
+    'jsonString' : mapper.writeValueAsString(json)
+}

+ 20 - 0
src/main/resources/magic-api/api/2操作案例/使用Spring中的Bean.ms

@@ -0,0 +1,20 @@
+{
+  "id" : "83c6b79c8723457e85143f3612e6644f",
+  "script" : null,
+  "groupId" : "d528abe95ca74f3cb195425afd7415af",
+  "name" : "使用Spring中的Bean",
+  "createTime" : null,
+  "updateTime" : null,
+  "method" : "GET",
+  "path" : "/spring",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : "{\n    \"code\": 1,\n    \"message\": \"success\",\n    \"data\": \"/magic/web\",\n    \"timestamp\": 1615986308312,\n    \"executeTime\": 3\n}",
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+import 'org.springframework.core.env.Environment' as env;   // 导入Spring中的bean
+return env.getProperty('magic-api.web');

+ 26 - 0
src/main/resources/magic-api/api/2操作案例/数值转换.ms

@@ -0,0 +1,26 @@
+{
+  "id" : "dd98420301264750bbf97138e206df95",
+  "script" : null,
+  "groupId" : "d528abe95ca74f3cb195425afd7415af",
+  "name" : "数值转换",
+  "createTime" : null,
+  "updateTime" : null,
+  "method" : "GET",
+  "path" : "/number/convert",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : "{\n    \"code\": -1000,\n    \"message\": \"Expected ',', but got 'isInt'\",\n    \"data\": null,\n    \"timestamp\": 1615984558701,\n    \"executeTime\": 7\n}",
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+return {
+    'fixed' : 123.455.toFixed(2), //仿JS ,会返回String
+    'round' : 123.452.round(2),  // 保留两位小数
+    'percent': 0.456789.asPercent(2), //转为百分比,保留2位小数
+    'ceil': 1.1.ceil(), //向上取整
+    'floor': 1.9.floor(), // 向下取整
+    '::int': '-456.789'::int   // 强制类型转换
+}

+ 22 - 0
src/main/resources/magic-api/api/2操作案例/调用其他接口.ms

@@ -0,0 +1,22 @@
+{
+  "id" : "e51d7756285f4e3c8ec28c7fb94fdc16",
+  "script" : null,
+  "groupId" : "d528abe95ca74f3cb195425afd7415af",
+  "name" : "调用其他接口",
+  "createTime" : 1615985897335,
+  "updateTime" : 1615985897335,
+  "method" : "GET",
+  "path" : "/call",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : null,
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+import '@get:/base/module/assert' as test;
+var id = '1';
+var message = 'hello'
+return test();

+ 24 - 0
src/main/resources/magic-api/api/2操作案例/调用函数.ms

@@ -0,0 +1,24 @@
+{
+  "id" : "5a47cfbd857f47b196681e66d3aaa18f",
+  "script" : null,
+  "groupId" : "d528abe95ca74f3cb195425afd7415af",
+  "name" : "调用函数",
+  "createTime" : 1615985597097,
+  "updateTime" : 1615985597097,
+  "method" : "GET",
+  "path" : "/function",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : null,
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+import '@/test/add' as add;
+import '@/test/nested' as nested;
+return {
+    'add': add(1,2),
+    'nested': nested()
+}

+ 7 - 0
src/main/resources/magic-api/api/3LINQ相关/group.json

@@ -0,0 +1,7 @@
+{
+  "id" : "8b4ffb920a6e4758ae142ccda0685519",
+  "name" : "3LINQ相关",
+  "type" : "1",
+  "parentId" : "0",
+  "path" : "/linq"
+}

+ 23 - 0
src/main/resources/magic-api/api/3LINQ相关/list转tree.ms

@@ -0,0 +1,23 @@
+{
+  "id" : "d6858902837a4b63b4bc9a2292dc8ee5",
+  "script" : null,
+  "groupId" : "8b4ffb920a6e4758ae142ccda0685519",
+  "name" : "list转tree",
+  "createTime" : 1615983226114,
+  "updateTime" : 1615983226114,
+  "method" : "GET",
+  "path" : "/tree",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : null,
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+
+var toTree = (list,parentId) => select t.*,toTree(list,t.id) children from list t where t.parent_id = parentId
+
+// 根节点为 0
+return toTree(db.select('select id,group_name,parent_id from magic_group'),'0')

+ 24 - 0
src/main/resources/magic-api/api/3LINQ相关/关联.ms

@@ -0,0 +1,24 @@
+{
+  "id" : "f0ee5da0f4914213953e6340c1d1811d",
+  "script" : null,
+  "groupId" : "8b4ffb920a6e4758ae142ccda0685519",
+  "name" : "关联",
+  "createTime" : 1615983189124,
+  "updateTime" : 1615983189124,
+  "method" : "GET",
+  "path" : "/join",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : null,
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+return 
+    select 
+        t.*,
+        g.groupName
+    from db.camel().select('select api_name,api_group_id from magic_api_info') t
+    left join db.camel().select('select id,group_name from magic_group') g on t.apiGroupId = g.id

+ 25 - 0
src/main/resources/magic-api/api/3LINQ相关/分组.ms

@@ -0,0 +1,25 @@
+{
+  "id" : "8bcd5c086d944cd08fb41e0463b7b478",
+  "script" : null,
+  "groupId" : "8b4ffb920a6e4758ae142ccda0685519",
+  "name" : "分组",
+  "createTime" : 1615983175744,
+  "updateTime" : 1615983175744,
+  "method" : "GET",
+  "path" : "/group",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : null,
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+return 
+    select 
+        t.api_group_id,
+        count(t.api_group_id) count
+    from db.select('select api_group_id from magic_api_info') t
+    group by t.api_group_id
+    order by count(t.api_group_id) desc

+ 33 - 0
src/main/resources/magic-api/api/3LINQ相关/字段转换.ms

@@ -0,0 +1,33 @@
+{
+  "id" : "4710d409607a4b2aba00b028e8d36dad",
+  "script" : null,
+  "groupId" : "8b4ffb920a6e4758ae142ccda0685519",
+  "name" : "字段转换",
+  "createTime" : 1615983269672,
+  "updateTime" : 1615983269672,
+  "method" : "GET",
+  "path" : "/map",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : null,
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+var list = [{
+    sex : 0,
+    name : '小明',
+    age : 19
+},{
+    sex : 1,
+    name : '小花',
+    age : 18
+}];
+return 
+    select 
+        t.age > 18 ? '成人' : '未成年' age,
+        t.sex == 0 ? '男' : '女' sex,
+        t.name
+    from list t;

+ 28 - 0
src/main/resources/magic-api/api/3LINQ相关/空值转换.ms

@@ -0,0 +1,28 @@
+{
+  "id" : "626d38774a4c48d0b2bc96f59df087b2",
+  "script" : null,
+  "groupId" : "8b4ffb920a6e4758ae142ccda0685519",
+  "name" : "空值转换",
+  "createTime" : 1615983123252,
+  "updateTime" : 1615983123252,
+  "method" : "GET",
+  "path" : "/null",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : null,
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+var list = [
+    {name : null,age: 18},
+    {name : '小明'}
+]
+// || ifnull 都可以做空值转换,区别是 || 会将空字符串、0、空集合、空Map视为空值
+return 
+    select 
+        t.name || '无名' name,
+        ifnull(t.age,20) age
+    from list t

+ 40 - 0
src/main/resources/magic-api/api/3LINQ相关/行转列.ms

@@ -0,0 +1,40 @@
+{
+  "id" : "da433c8708c74cb3ad3482f8fdb09119",
+  "script" : null,
+  "groupId" : "8b4ffb920a6e4758ae142ccda0685519",
+  "name" : "行转列",
+  "createTime" : 1615983153343,
+  "updateTime" : 1615983153343,
+  "method" : "GET",
+  "path" : "/pivot",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : null,
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+var result = db.select('select api_method,api_group_id from magic_api_info');
+var groups = db.select('select id,group_name from magic_group');
+var pivot = (list)=>list.group(it=> it.api_method,values=> values.size())
+return
+    select * from (
+        select 
+            mg.group_name,
+            pivot(ma)
+        from result ma 
+        join groups mg on mg.id = ma.api_group_id
+        group by ma.api_group_id
+        having count(ma.api_method) > 5
+    ) t order by t.POST desc
+// 期待结果如下
+/*
+  -     GET    POST 
+分组1    X       X
+分组2    X       X
+分组3    X       X
+分组4    X       X
+其中X为该分组对应请求方法的数量
+*/

+ 26 - 0
src/main/resources/magic-api/api/3LINQ相关/过滤.ms

@@ -0,0 +1,26 @@
+{
+  "id" : "112e04509b274bb8bbac347e29787e21",
+  "script" : null,
+  "groupId" : "8b4ffb920a6e4758ae142ccda0685519",
+  "name" : "过滤",
+  "createTime" : 1615983206716,
+  "updateTime" : 1615983206716,
+  "method" : "GET",
+  "path" : "/filter",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : null,
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+var list = [{
+    sex : 0,
+    name : '小明'
+},{
+    sex : 1,
+    name : '小花'
+}]
+return select * from list t where t.sex = 0

+ 7 - 0
src/main/resources/magic-api/api/4lambda相关/group.json

@@ -0,0 +1,7 @@
+{
+  "id" : "aa81e76ddfd7471a97aa423abd80b2aa",
+  "name" : "4lambda相关",
+  "type" : "1",
+  "parentId" : "0",
+  "path" : "/lambda"
+}

+ 28 - 0
src/main/resources/magic-api/api/4lambda相关/list转tree.ms

@@ -0,0 +1,28 @@
+{
+  "id" : "8c5642b3f026430db18c5e2cf223ea41",
+  "script" : null,
+  "groupId" : "aa81e76ddfd7471a97aa423abd80b2aa",
+  "name" : "list转tree",
+  "createTime" : 1615983313969,
+  "updateTime" : 1615983313969,
+  "method" : "GET",
+  "path" : "/tree",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : null,
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+//var toTree = (list,parentId)=>list.filter(it => it.parent_id == parentId).each(it=>it.children = toTree(list,it.id))
+// 上面为简写
+var toTree = (list,parentId)=>{
+    return list.filter(it => it.parent_id == parentId) // 根据parentId 过滤当前节点
+    .each(it=>{
+        it.children = toTree(list,it.id)    // 过滤后循环这些节点递归添加children属性
+    }) 
+}
+// 根节点为 0
+return toTree(db.select('select id,group_name,parent_id from magic_group'),'0')

+ 27 - 0
src/main/resources/magic-api/api/4lambda相关/关联.ms

@@ -0,0 +1,27 @@
+{
+  "id" : "6328b06b544d4b7a9fd95497fab1717c",
+  "script" : null,
+  "groupId" : "aa81e76ddfd7471a97aa423abd80b2aa",
+  "name" : "关联",
+  "createTime" : 1615983353928,
+  "updateTime" : 1615983353928,
+  "method" : "GET",
+  "path" : "/join",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : null,
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+return db.camel().select('select api_name,api_group_id from magic_api_info')
+    // 关联上分组
+    .join(db.camel().select('select id,group_name from magic_group'),(t1,t2) => t1.apiGroupId == t2.id)
+    // 关联后转换结果
+    .map(it => {
+        name : it.apiName,
+        groupId: it.apiGroupId,
+        groupName: it.groupName
+    })

+ 24 - 0
src/main/resources/magic-api/api/4lambda相关/分组.ms

@@ -0,0 +1,24 @@
+{
+  "id" : "1c65487a57b2457eb5d13b066889ee76",
+  "script" : null,
+  "groupId" : "aa81e76ddfd7471a97aa423abd80b2aa",
+  "name" : "分组",
+  "createTime" : 1615983368435,
+  "updateTime" : 1615983368435,
+  "method" : "GET",
+  "path" : "/group",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : null,
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+// 分组后计算每组的数量
+return db.select('select api_group_id from magic_api_info')
+    // 根据api_group_id 分组,分组后,值为分组结果的大小
+    .group(it => it.api_group_id,list => list.size())
+    // 根据value排序
+    .sort((k1,k2,v1,v2) => v2 - v1)

+ 40 - 0
src/main/resources/magic-api/api/4lambda相关/动态行转列.ms

@@ -0,0 +1,40 @@
+{
+  "id" : "679ace6a76b1435b8a1e75bca28344d7",
+  "script" : null,
+  "groupId" : "aa81e76ddfd7471a97aa423abd80b2aa",
+  "name" : "动态行转列",
+  "createTime" : 1615983402538,
+  "updateTime" : 1615983402538,
+  "method" : "GET",
+  "path" : "/pivot",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : null,
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+var result = db.select('select api_method,api_group_id from magic_api_info');
+// 期待结果如下
+/*
+  -     GET    POST 
+分组1    X       X
+分组2    X       X
+分组3    X       X
+分组4    X       X
+其中X为该分组对应请求方法的数量
+*/
+return result.group(it => it.api_group_id,    // 根据api_group_id 分组
+    list => list.group(item => item.api_method, // 根据 请求方法 再次分组
+        apis => apis.size()
+    )
+).asList((key,value)=>{ // 将分组后的Map<String,Map<String,Object>> 结果转为List<Map<String,Object>
+    ...value,   // 展开Map
+    group_id : key
+})
+//关联分组表,添加分组中文名,此步骤也可以放在SQL中关联。
+.join(db.select('select id,group_name from magic_group'),(t1,t2) => t1.group_id == t2.id)  
+// 移除多余的ID列
+.each(it => it.remove('id')) 

+ 37 - 0
src/main/resources/magic-api/api/4lambda相关/字段转换.ms

@@ -0,0 +1,37 @@
+{
+  "id" : "b19a109bbabb44448e2a74bf0bfd168b",
+  "script" : null,
+  "groupId" : "aa81e76ddfd7471a97aa423abd80b2aa",
+  "name" : "字段转换",
+  "createTime" : 1615983339688,
+  "updateTime" : 1615983339688,
+  "method" : "GET",
+  "path" : "/map",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : null,
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+var list = [{
+    sex : 0,
+    name : '小明',
+    age : 19
+},{
+    sex : 1,
+    name : '小花',
+    age : 18
+}];
+
+var getAge = (age)=>{
+    return age > 18 ? '成人' : '未成年'
+}
+// 利用map函数对list进行过滤
+return list.map((item)=>{
+    age : getAge(item.age),
+    sex : item.sex == 0 ? '男' : '女',
+    name : item.name
+});

+ 27 - 0
src/main/resources/magic-api/api/4lambda相关/过滤.ms

@@ -0,0 +1,27 @@
+{
+  "id" : "ad3bcec84b2740c3889cc467e39fa2d8",
+  "script" : null,
+  "groupId" : "aa81e76ddfd7471a97aa423abd80b2aa",
+  "name" : "过滤",
+  "createTime" : 1615983326607,
+  "updateTime" : 1615983326607,
+  "method" : "GET",
+  "path" : "/filter",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : null,
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+var list = [{
+    sex : 0,
+    name : '小明'
+},{
+    sex : 1,
+    name : '小花'
+}]
+// 利用map函数对list进行过滤
+return list.filter((item)=>item.sex == 0);

+ 30 - 0
src/main/resources/magic-api/api/4lambda相关/过滤和转换.ms

@@ -0,0 +1,30 @@
+{
+  "id" : "02f99c967c184fa4a7c7f360864f08dc",
+  "script" : null,
+  "groupId" : "aa81e76ddfd7471a97aa423abd80b2aa",
+  "name" : "过滤和转换",
+  "createTime" : 1615983383200,
+  "updateTime" : 1615983383200,
+  "method" : "GET",
+  "path" : "/filter-map",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : null,
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+var list = [{
+    sex : 0,
+    name : '小明'
+},{
+    sex : 1,
+    name : '小花'
+}]
+// 利用map函数对list进行过滤,然后进行转换
+return list.filter(item=>item.sex == 0).map((item)=>{
+    sex : item.sex == 0 ? '男' : '女',
+    name : item.name
+});

+ 7 - 0
src/main/resources/magic-api/api/5自定义结果/group.json

@@ -0,0 +1,7 @@
+{
+  "id" : "2b0ce800b6c543efa284ae695e14e4eb",
+  "name" : "5自定义结果",
+  "type" : "1",
+  "parentId" : "0",
+  "path" : "/response"
+}

+ 20 - 0
src/main/resources/magic-api/api/5自定义结果/文件下载.ms

@@ -0,0 +1,20 @@
+{
+  "id" : "a5f46d89e2454149b649d2dd542e522d",
+  "script" : null,
+  "groupId" : "2b0ce800b6c543efa284ae695e14e4eb",
+  "name" : "文件下载",
+  "createTime" : 1615983934415,
+  "updateTime" : 1615983934415,
+  "method" : "GET",
+  "path" : "/download",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : null,
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+import response;
+return response.download('中文测试','str.txt');

+ 22 - 0
src/main/resources/magic-api/api/5自定义结果/模拟分页.ms

@@ -0,0 +1,22 @@
+{
+  "id" : "48a3e16b86d54388a7e5571eac477d72",
+  "script" : null,
+  "groupId" : "2b0ce800b6c543efa284ae695e14e4eb",
+  "name" : "模拟分页",
+  "createTime" : 1615983958385,
+  "updateTime" : 1615983958385,
+  "method" : "GET",
+  "path" : "/page",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : null,
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+import response;
+var total = 5;  //模拟一共有多少条数据
+var list = [1,2];   //模拟数据项
+return response.page(total,list);

+ 66 - 0
src/main/resources/magic-api/api/5自定义结果/生成验证码.ms

@@ -0,0 +1,66 @@
+{
+  "id" : "c7f7004a8e104663aa04361587bfb6b7",
+  "script" : null,
+  "groupId" : "2b0ce800b6c543efa284ae695e14e4eb",
+  "name" : "生成验证码",
+  "createTime" : 1615984025930,
+  "updateTime" : 1615984025930,
+  "method" : "GET",
+  "path" : "image",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : null,
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+import 'java.awt.image.BufferedImage' as BufferedImage;
+import 'java.awt.Color' as Color;
+import 'java.awt.Font' as Font;
+import 'java.io.ByteArrayOutputStream' as ByteArrayOutputStream;
+import 'java.util.Random' as Random;
+import 'javax.imageio.ImageIO' as ImageIO;
+import response;
+import log;
+
+var width = 200;
+var height = 69;
+var image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
+var graphics = image.getGraphics();
+graphics.setColor(Color.WHITE);
+graphics.fillRect(0,0,width,height);
+graphics.setFont(new Font("微软雅黑", Font.BOLD, 40));
+var letter = '123456789abcdefghijklmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ';
+var random = new Random();
+var randomColor = ()=>new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256));
+var x = 10;
+var code = '';
+for (i in range(0, 3)){ //验证码
+    graphics.setColor(randomColor());
+    var degree = random.nextInt() % 30;
+    var ch = letter.charAt(random.nextInt(letter.length()));
+    code = code + ch;
+    graphics.rotate(degree * 3.1415926535 / 180, x, 45);
+    graphics.drawString(ch + '', x, 45);
+    graphics.rotate(-degree * 3.1415926535 / 180, x, 45);
+    x = x + 48;
+}
+log.info('生成的验证码:{}',code)
+for (i in range(0, 6)) {    //干扰线
+    graphics.setColor(randomColor());
+    graphics.drawLine(random.nextInt(width), random.nextInt(height),random.nextInt(width), random.nextInt(height));
+}
+
+for(i in range(0, 30)){  //噪点
+    graphics.setColor(randomColor());
+    graphics.fillRect(random.nextInt(width), random.nextInt(height), 2,2);
+
+}
+graphics.dispose();
+var baos = new ByteArrayOutputStream();
+ImageIO.write(image,"png",baos);
+baos.flush();
+baos.close();
+return response.image(baos.toByteArray(),'image/png');

+ 24 - 0
src/main/resources/magic-api/api/5自定义结果/自定义json.ms

@@ -0,0 +1,24 @@
+{
+  "id" : "a35baae914f64a2784d0fa2b6a281bbb",
+  "script" : null,
+  "groupId" : "2b0ce800b6c543efa284ae695e14e4eb",
+  "name" : "自定义json",
+  "createTime" : 1615984006439,
+  "updateTime" : 1615984006439,
+  "method" : "GET",
+  "path" : "/json",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : null,
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+import response;
+// 注意,这种方式仅仅适合临时输出的格式,如果需要全局统一JSON结果,请参考文档
+return response.json({
+    success : true,
+    message : '执行成功'
+});

+ 7 - 0
src/main/resources/magic-api/api/6基本语法/group.json

@@ -0,0 +1,7 @@
+{
+  "id" : "a02fb62b1c7e4fb3ada92a799a15d733",
+  "name" : "6基本语法",
+  "type" : "1",
+  "parentId" : "0",
+  "path" : "/base"
+}

+ 23 - 0
src/main/resources/magic-api/api/6基本语法/脚本语法/exit语句.ms

@@ -0,0 +1,23 @@
+{
+  "id" : "fe3147eb81cd48089a635f7a94758009",
+  "script" : null,
+  "groupId" : "1534958e40ff4037a50bd9d3c25bceb5",
+  "name" : "exit语句",
+  "createTime" : 1615983896777,
+  "updateTime" : 1615983896777,
+  "method" : "GET",
+  "path" : "/exit",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : null,
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+if(true){
+    exit 400,'参数填写有误'
+}
+// 第一个参数为code,第二个为message,第三个为data,至少要填写一个参数。
+exit 200,'success','ok'

+ 7 - 0
src/main/resources/magic-api/api/6基本语法/脚本语法/group.json

@@ -0,0 +1,7 @@
+{
+  "id" : "1534958e40ff4037a50bd9d3c25bceb5",
+  "name" : "脚本语法",
+  "type" : "1",
+  "parentId" : "a02fb62b1c7e4fb3ada92a799a15d733",
+  "path" : "/script"
+}

+ 45 - 0
src/main/resources/magic-api/api/6基本语法/脚本语法/if判断.ms

@@ -0,0 +1,45 @@
+{
+  "id" : "d875fe71d35f4bc7a418ade47d481849",
+  "script" : null,
+  "groupId" : "1534958e40ff4037a50bd9d3c25bceb5",
+  "name" : "if判断",
+  "createTime" : 1615816620872,
+  "updateTime" : 1615816620872,
+  "method" : "GET",
+  "path" : "/if",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : null,
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+/*
+    if 测试
+*/
+if(a == 1){ 
+    return 1;
+}else if(a == 2){
+    return 2;
+}else{
+    return 0;
+}
+/*
+对于条件判断,特意支持了简写的方式
+如 可以直接写 
+1、if(a) 
+2、else if(a)
+3、while(a) 
+4、a ? 1 : 0 
+
+当a的值是以下情况时为false
+null
+空集合
+空Map
+数值 == 0
+空字符串(length == 0)
+false
+其它情况一律视为true
+*/

+ 27 - 0
src/main/resources/magic-api/api/6基本语法/脚本语法/try_catch.ms

@@ -0,0 +1,27 @@
+{
+  "id" : "6b29727322e34ac8968cd2e51d6f0e41",
+  "script" : null,
+  "groupId" : "1534958e40ff4037a50bd9d3c25bceb5",
+  "name" : "try_catch",
+  "createTime" : null,
+  "updateTime" : null,
+  "method" : "GET",
+  "path" : "/try",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : "{\n    \"code\": 1,\n    \"message\": \"success\",\n    \"data\": \"finally\",\n    \"timestamp\": 1615816823911,\n    \"executeTime\": 2\n}",
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+try{
+    var c = 1 / 0
+}catch(e){  //不用写类型,只写变量即可
+    return e.getMessage();
+}finally{
+    return 'finally'
+}
+// catch 和finally 都可以不写。
+return 'ok'

+ 23 - 0
src/main/resources/magic-api/api/6基本语法/脚本语法/与Java交互.ms

@@ -0,0 +1,23 @@
+{
+  "id" : "08208af67848468eb6e8c1c0c22ac819",
+  "script" : null,
+  "groupId" : "1534958e40ff4037a50bd9d3c25bceb5",
+  "name" : "与Java交互",
+  "createTime" : null,
+  "updateTime" : null,
+  "method" : "GET",
+  "path" : "/java",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : "{\n    \"code\": 1,\n    \"message\": \"success\",\n    \"data\": \"2021-03-15\",\n    \"timestamp\": 1615816582971,\n    \"executeTime\": 18\n}",
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+import 'java.util.Date' as Date;
+import 'java.text.SimpleDateFormat' as SimpleDateFormat;
+var now = new Date();   // 创建对象
+var df = new SimpleDateFormat('yyyy-MM-dd');
+return df.format(now);  // 调用方法

+ 26 - 0
src/main/resources/magic-api/api/6基本语法/脚本语法/可选连.ms

@@ -0,0 +1,26 @@
+{
+  "id" : "64ab21bd4d7c4743a389b332af7eba72",
+  "script" : null,
+  "groupId" : "1534958e40ff4037a50bd9d3c25bceb5",
+  "name" : "可选连",
+  "createTime" : 1615816745360,
+  "updateTime" : 1615816745360,
+  "method" : "GET",
+  "path" : "/optional",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : null,
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+var map = {
+    a : {
+        b : 'ok'
+    },
+    c : 1
+}
+// ?. 不会报错,.会报错
+return map.a.bbbb?.c + '-' + map.a?.b;

Diff do ficheiro suprimidas por serem muito extensas
+ 41 - 0
src/main/resources/magic-api/api/6基本语法/脚本语法/各类运算符.ms


+ 35 - 0
src/main/resources/magic-api/api/6基本语法/脚本语法/定义lambda.ms

@@ -0,0 +1,35 @@
+{
+  "id" : "81b0671e0652403b8864881241e0f074",
+  "script" : null,
+  "groupId" : "1534958e40ff4037a50bd9d3c25bceb5",
+  "name" : "定义lambda",
+  "createTime" : null,
+  "updateTime" : null,
+  "method" : "GET",
+  "path" : "/lambda",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : "{\n    \"code\": 1,\n    \"message\": \"success\",\n    \"data\": 8,\n    \"timestamp\": 1615816558700,\n    \"executeTime\": 2\n}",
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+/*
+    测试Lambda
+*/
+var lambda1 = e => e + 1; //单参数单行代码,省略括号,省略{}
+var lambda2 = (e) => e +1; //单参数单行代码,不省略括号,省略{} 作用同上
+var lambda4 = e => {e + 1};//单参数无返回值,不能省略{}
+var lambda5 = e => {return e + 1};//单参数有返回值,省略括号,不省略{}
+var lambda6 = (e) => {return e + 1};//单参数有返回值,不省略括号,不省略{},作用同上
+var lambda7 = (a,b) => a + b; //多参数单行代码,省略{}
+var lambda7 = (a,b) => {return a + b}; //多参数单行代码,有返回值,作用同上
+var lambda8 = (a,b) =>{ //多参数多行代码, 无法省略括号和{}
+    a = a + 1;
+    return a + b;
+}
+var v1 = lambda1(1);    //返回2
+var v2 = lambda2(v1);    //返回3
+return lambda8(v1,lambda7(v1,v2)); //返回8

+ 25 - 0
src/main/resources/magic-api/api/6基本语法/脚本语法/异步执行.ms

@@ -0,0 +1,25 @@
+{
+  "id" : "83d9fa7ef5a741e793dacfb0755c7535",
+  "script" : null,
+  "groupId" : "1534958e40ff4037a50bd9d3c25bceb5",
+  "name" : "异步执行",
+  "createTime" : 1615983519462,
+  "updateTime" : 1615983519462,
+  "method" : "GET",
+  "path" : "/async",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : null,
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+
+var list = [];
+for(index in range(1,10)){
+    // 执行SQL时,为了线程安全,需要把index参数放入lambda参数中。
+    list.add(async (index)=>db.selectInt('select #{index}'));
+}
+return list.map(f => f.get())

+ 28 - 0
src/main/resources/magic-api/api/6基本语法/脚本语法/扩展运算符.ms

@@ -0,0 +1,28 @@
+{
+  "id" : "f211d0eaf72d478e9100412577642dd1",
+  "script" : null,
+  "groupId" : "1534958e40ff4037a50bd9d3c25bceb5",
+  "name" : "扩展运算符",
+  "createTime" : 1615816769927,
+  "updateTime" : 1615816769927,
+  "method" : "GET",
+  "path" : "/spread",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : null,
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+var map = {
+    a : 1,
+    b : 2
+}
+var list = [1,2,3,4,5]
+return {
+    ...map, //展开Map
+    c : 3,
+    d : [...list]   // 展开list
+};;

+ 31 - 0
src/main/resources/magic-api/api/6基本语法/脚本语法/类型转换.ms

@@ -0,0 +1,31 @@
+{
+  "id" : "7edfa3c0bb9247cba160b1eb45ec8825",
+  "script" : null,
+  "groupId" : "1534958e40ff4037a50bd9d3c25bceb5",
+  "name" : "类型转换",
+  "createTime" : null,
+  "updateTime" : null,
+  "method" : "GET",
+  "path" : "/convert",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : "{\n    \"code\": -1000,\n    \"message\": \"找不到方法 asInt(Integer)\",\n    \"data\": null,\n    \"timestamp\": 1615816481060,\n    \"executeTime\": 22\n}",
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+var a = 123;
+var str = "456.0";
+/* 目前转换的办法一共有三种,
+    1、使用Java相关函数,如Integer.parseInt
+    2、是使用脚本提供的语法::进行转换,支持::int ::double ::string ::byte ::long ::short ::float ::date
+    3、使用扩展方法,xxx.asXXX(); 如 a.asInt()
+*/
+return {
+    '::string': a::string,  // 使用::转换,好处是它是语法级的,不会产生空指针,
+    '::int' : str::int(0),  // 转换失败是使用默认值0,
+    'ext': a.asString(),   // 使用扩展方法转换
+    'toDate' : '2020-01-01'::date('yyyy-MM-dd')
+}

+ 7 - 0
src/main/resources/magic-api/api/Web相关/group.json

@@ -0,0 +1,7 @@
+{
+  "id" : "18a58c0d73a14135bfca55274d4e0ffc",
+  "name" : "Web相关",
+  "type" : "1",
+  "parentId" : "a02fb62b1c7e4fb3ada92a799a15d733",
+  "path" : "/web"
+}

+ 20 - 0
src/main/resources/magic-api/api/Web相关/下载文件.ms

@@ -0,0 +1,20 @@
+{
+  "id" : "9973ddc13e0543dc9b44595836ce4090",
+  "script" : null,
+  "groupId" : "18a58c0d73a14135bfca55274d4e0ffc",
+  "name" : "下载文件",
+  "createTime" : 1615817141026,
+  "updateTime" : 1615817141026,
+  "method" : "GET",
+  "path" : "/download",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "{\r\n\t\r\n}",
+  "headers" : [ ],
+  "responseBody" : null,
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+import response;
+return response.download('文件内容','test.txt');

+ 52 - 0
src/main/resources/magic-api/api/Web相关/参数自动验证.ms

@@ -0,0 +1,52 @@
+{
+  "id" : "89640999511b49a8b8f77fba690f4412",
+  "script" : null,
+  "groupId" : "18a58c0d73a14135bfca55274d4e0ffc",
+  "name" : "参数自动验证",
+  "createTime" : null,
+  "updateTime" : null,
+  "method" : "GET",
+  "path" : "/validate",
+  "parameters" : [ {
+    "name" : "id",
+    "value" : "",
+    "description" : "",
+    "required" : true,
+    "dataType" : null,
+    "type" : null,
+    "defaultValue" : null,
+    "validateType" : null,
+    "error" : "id必填",
+    "expression" : null
+  }, {
+    "name" : "age",
+    "value" : "",
+    "description" : "",
+    "required" : false,
+    "dataType" : "String",
+    "type" : null,
+    "defaultValue" : null,
+    "validateType" : "pattern",
+    "error" : "age必须为数字",
+    "expression" : "^\\d+$"
+  }, {
+    "name" : "phone",
+    "value" : "",
+    "description" : "",
+    "required" : true,
+    "dataType" : "String",
+    "type" : null,
+    "defaultValue" : null,
+    "validateType" : "expression",
+    "error" : "手机号必填且必须是11位",
+    "expression" : "phone.length() == 11"
+  } ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : "{\n    \"code\": 0,\n    \"message\": \"id必填\",\n    \"data\": null,\n    \"timestamp\": 1615984896144,\n    \"executeTime\": 0\n}",
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+return '参数验证通过' 

Diff do ficheiro suprimidas por serem muito extensas
+ 66 - 0
src/main/resources/magic-api/api/Web相关/生成图片.ms


+ 48 - 0
src/main/resources/magic-api/api/Web相关/获取请求参数.ms

@@ -0,0 +1,48 @@
+{
+  "id" : "1e88ab135a3b4d23acdc4e6c93b39fbb",
+  "script" : null,
+  "groupId" : "18a58c0d73a14135bfca55274d4e0ffc",
+  "name" : "获取请求参数",
+  "createTime" : null,
+  "updateTime" : null,
+  "method" : "POST",
+  "path" : "/param",
+  "parameters" : [ {
+    "name" : "name",
+    "value" : "magic-script",
+    "description" : "",
+    "required" : false,
+    "dataType" : null,
+    "type" : null,
+    "defaultValue" : null,
+    "validateType" : null,
+    "error" : null,
+    "expression" : null
+  } ],
+  "option" : "[]",
+  "requestBody" : "{\r\n\t\"data\" : {\r\n        \"id\" : 123456\r\n    }\r\n}",
+  "headers" : [ {
+    "name" : "token",
+    "value" : "123456",
+    "description" : "",
+    "required" : false,
+    "dataType" : null,
+    "type" : null,
+    "defaultValue" : null,
+    "validateType" : null,
+    "error" : null,
+    "expression" : null
+  } ],
+  "responseBody" : "{\n    \"code\": 1,\n    \"message\": \"success\",\n    \"data\": {\n        \"Request\": \"magic-script\",\n        \"Header\": \"123456\",\n        \"RequestBody\": 123456,\n        \"Path\": null\n    },\n    \"timestamp\": 1615816974752,\n    \"executeTime\": 3\n}",
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+import request;
+return {
+    'Request': name,
+    'Header' : header.token,
+    'RequestBody': body.data.id,
+    'Path' : path.id,
+    'file' : request.getFile('file')
+}

+ 21 - 0
src/main/resources/magic-api/api/Web相关/设置Cookie.ms

@@ -0,0 +1,21 @@
+{
+  "id" : "cc3a5c42d0e94204aca7d5e5ecca32f3",
+  "script" : null,
+  "groupId" : "18a58c0d73a14135bfca55274d4e0ffc",
+  "name" : "设置Cookie",
+  "createTime" : null,
+  "updateTime" : null,
+  "method" : "GET",
+  "path" : "/cookie",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "{\r\n\t\r\n}",
+  "headers" : [ ],
+  "responseBody" : "{\n    \"code\": 1,\n    \"message\": \"success\",\n    \"data\": \"请按F12后在控制台中查看\",\n    \"timestamp\": 1615817035547,\n    \"executeTime\": 5\n}",
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+import response;
+response.addCookie('name','value');
+return '请按F12后在控制台中查看'

+ 21 - 0
src/main/resources/magic-api/api/Web相关/设置Header.ms

@@ -0,0 +1,21 @@
+{
+  "id" : "df85508a9597424394562b40f19a67ef",
+  "script" : null,
+  "groupId" : "18a58c0d73a14135bfca55274d4e0ffc",
+  "name" : "设置Header",
+  "createTime" : null,
+  "updateTime" : null,
+  "method" : "GET",
+  "path" : "/header",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "{\r\n\t\r\n}",
+  "headers" : [ ],
+  "responseBody" : "{\n    \"code\": 1,\n    \"message\": \"success\",\n    \"data\": \"请按F12在控制台中查看\",\n    \"timestamp\": 1615817099072,\n    \"executeTime\": 4\n}",
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+import response;
+response.setHeader('key','value');
+return '请按F12在控制台中查看'

+ 32 - 0
src/main/resources/magic-api/api/循环/for循环.ms

@@ -0,0 +1,32 @@
+{
+  "id" : "61b45eda9e0144ab89d3b65eea714f27",
+  "script" : null,
+  "groupId" : "fcab7c3c199b42a39d87da01c78633b3",
+  "name" : "for循环",
+  "createTime" : 1615982993404,
+  "updateTime" : 1615982993404,
+  "method" : "GET",
+  "path" : "/for",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : null,
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+/*
+    测试循环
+*/
+var sum = 0;
+for(val in range(0,100)){   //包括0 包括100
+    if(val > 90){
+        break;  //跳出循环
+    }
+    if(val % 3 == 0){
+        continue;   //进入下一次循环
+    }
+    sum = sum + val;
+}
+return sum;

+ 7 - 0
src/main/resources/magic-api/api/循环/group.json

@@ -0,0 +1,7 @@
+{
+  "id" : "fcab7c3c199b42a39d87da01c78633b3",
+  "name" : "循环",
+  "type" : "1",
+  "parentId" : "a02fb62b1c7e4fb3ada92a799a15d733",
+  "path" : "/loop"
+}

+ 22 - 0
src/main/resources/magic-api/api/循环/lambda循环list.ms

@@ -0,0 +1,22 @@
+{
+  "id" : "62fe9e49f6f54b67a0aa351baf8d0107",
+  "script" : null,
+  "groupId" : "fcab7c3c199b42a39d87da01c78633b3",
+  "name" : "lambda循环list",
+  "createTime" : 1615983025978,
+  "updateTime" : 1615983025978,
+  "method" : "GET",
+  "path" : "/lambda/list",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : null,
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+var list = [1,2,3,4,5,6,7,8,9,10]
+var sum = 0;
+list.each(it => sum+= it + 1)
+return sum

+ 31 - 0
src/main/resources/magic-api/api/循环/lambda循环map.ms

@@ -0,0 +1,31 @@
+{
+  "id" : "6ff3d4617ac24aa6b31088f919c6c6c5",
+  "script" : null,
+  "groupId" : "fcab7c3c199b42a39d87da01c78633b3",
+  "name" : "lambda循环map",
+  "createTime" : 1615983045187,
+  "updateTime" : 1615983045187,
+  "method" : "GET",
+  "path" : "/lambda/map",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : null,
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+var map = {
+    key1 : 1,
+    key2 : 2,
+    key3 : 3
+};
+var sum = 0;
+var keys = '';
+map.each((key,value) => {
+    keys += key;
+    sum += value;
+
+})
+return keys + '-' + sum;

+ 24 - 0
src/main/resources/magic-api/api/循环/while.ms

@@ -0,0 +1,24 @@
+{
+  "id" : "121a0079e5e1496d9a4cd38ffeea8fa4",
+  "script" : null,
+  "groupId" : "fcab7c3c199b42a39d87da01c78633b3",
+  "name" : "while",
+  "createTime" : 1615983057681,
+  "updateTime" : 1615983057681,
+  "method" : "GET",
+  "path" : "/while",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : null,
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+var index = 0;
+var sum = 0;
+while(index < 100){
+    sum += index++;
+}
+return sum

+ 27 - 0
src/main/resources/magic-api/api/循环/循环list.ms

@@ -0,0 +1,27 @@
+{
+  "id" : "baf2ae4a01e74929a966a8226ac1618f",
+  "script" : null,
+  "groupId" : "fcab7c3c199b42a39d87da01c78633b3",
+  "name" : "循环list",
+  "createTime" : 1615982965931,
+  "updateTime" : 1615982965931,
+  "method" : "GET",
+  "path" : "/list",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : null,
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+/*
+    测试循环List
+*/
+var list = [1,2,3,4,5];
+var sum = 0;
+for(val in list){
+    sum = sum + val;
+}
+return sum;

+ 33 - 0
src/main/resources/magic-api/api/循环/循环map.ms

@@ -0,0 +1,33 @@
+{
+  "id" : "e1b2f29804134742a457fd996c4137a8",
+  "script" : null,
+  "groupId" : "fcab7c3c199b42a39d87da01c78633b3",
+  "name" : "循环map",
+  "createTime" : 1615982980997,
+  "updateTime" : 1615982980997,
+  "method" : "GET",
+  "path" : "/map",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : null,
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+/*
+    测试循环Map
+*/
+var map = {
+    key1 : 1,
+    key2 : 2,
+    key3 : 3
+};
+var sum = 0;
+var keys = '';
+for(key,value in map){
+    sum = sum + value;
+    keys = keys + key
+}
+return keys + '-' + sum;

+ 7 - 0
src/main/resources/magic-api/api/模块相关/group.json

@@ -0,0 +1,7 @@
+{
+  "id" : "1f1767129e1243fe91e873f62d6954d2",
+  "name" : "模块相关",
+  "type" : "1",
+  "parentId" : "a02fb62b1c7e4fb3ada92a799a15d733",
+  "path" : "/module"
+}

+ 25 - 0
src/main/resources/magic-api/api/模块相关/mongo.ms

@@ -0,0 +1,25 @@
+{
+  "id" : "6521572bd9334bd59d7648ac47e79c2e",
+  "script" : null,
+  "groupId" : "1f1767129e1243fe91e873f62d6954d2",
+  "name" : "mongo",
+  "createTime" : 1615983549524,
+  "updateTime" : 1615983549524,
+  "method" : "GET",
+  "path" : "/mongo",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : null,
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+/*
+ !!!!!! DEMO网站未集成Mongo,以下只是作为示例,无法执行。
+*/
+import mongo;   //导入mongodb模块
+
+//return mongo.test.col1.insert({name : 'magic'});
+return mongo.test.col1.find({name : 'magic'}).list();

+ 25 - 0
src/main/resources/magic-api/api/模块相关/redis.ms

@@ -0,0 +1,25 @@
+{
+  "id" : "baf43c09dc804e928aac74dd572da225",
+  "script" : null,
+  "groupId" : "1f1767129e1243fe91e873f62d6954d2",
+  "name" : "redis",
+  "createTime" : null,
+  "updateTime" : null,
+  "method" : "GET",
+  "path" : "/redis",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : null,
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+/*
+ !!!!!! DEMO网站未集成Redis,以下只是作为示例,无法执行。
+*/
+import redis;   //导入redis模块
+
+redis.set('magic','hello magic-api')
+return redis.get('magic');

+ 22 - 0
src/main/resources/magic-api/api/模块相关/手动验证参数.ms

@@ -0,0 +1,22 @@
+{
+  "id" : "8103a3a701394e52827da7433211c871",
+  "script" : null,
+  "groupId" : "1f1767129e1243fe91e873f62d6954d2",
+  "name" : "手动验证参数",
+  "createTime" : null,
+  "updateTime" : null,
+  "method" : "GET",
+  "path" : "/assert",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : "{\n    \"code\": -1000,\n    \"message\": \"object is not an instance of declaring class\",\n    \"data\": null,\n    \"timestamp\": 1615983817032,\n    \"executeTime\": 14586\n}",
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+import assert;
+assert.notNull(message, 0, 'message 不能为null');
+assert.regx(id,'\d+', 0, 'id必须是数字');
+return 'ok';

+ 39 - 0
src/main/resources/magic-api/api/模块相关/打印日志.ms

@@ -0,0 +1,39 @@
+{
+  "id" : "ede7d3561adb42bc8ec67d5522d38a91",
+  "script" : null,
+  "groupId" : "1f1767129e1243fe91e873f62d6954d2",
+  "name" : "打印日志",
+  "createTime" : null,
+  "updateTime" : null,
+  "method" : "GET",
+  "path" : "/log",
+  "parameters" : [ {
+    "name" : "message",
+    "value" : "hello magic-api",
+    "description" : "",
+    "required" : false,
+    "dataType" : null,
+    "type" : null,
+    "defaultValue" : null,
+    "validateType" : null,
+    "error" : null,
+    "expression" : null
+  } ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : "{\n    \"code\": 1,\n    \"message\": \"success\",\n    \"data\": \"ok\",\n    \"timestamp\": 1615983462666,\n    \"executeTime\": 12\n}",
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+import log;
+// 切换到"运行日志"查看日志信息
+log.info('info日志:{}',message);
+log.warn('warn日志');
+try{
+    return 1 / 0;
+}catch(e){
+    log.error('error日志',e);
+}
+return 'ok';

+ 21 - 0
src/main/resources/magic-api/api/模块相关/读取配置.ms

@@ -0,0 +1,21 @@
+{
+  "id" : "561a0fb12e4949f7be713207f7fc13c1",
+  "script" : null,
+  "groupId" : "1f1767129e1243fe91e873f62d6954d2",
+  "name" : "读取配置",
+  "createTime" : 1615983502669,
+  "updateTime" : 1615983502669,
+  "method" : "GET",
+  "path" : "/env",
+  "parameters" : [ ],
+  "option" : "[]",
+  "requestBody" : "",
+  "headers" : [ ],
+  "responseBody" : null,
+  "description" : null,
+  "optionMap" : { }
+}
+================================
+import env; 
+// 读取Spring中的配置
+return env.get('magic-api.web')

+ 37 - 0
src/main/resources/magic-api/function/测试函数/add.ms

@@ -0,0 +1,37 @@
+{
+  "id" : "6ed4e38b824b4eaea059b539305be1cf",
+  "script" : null,
+  "groupId" : "9219a9a8cdb9442d820f0770ccf483ab",
+  "name" : "add",
+  "createTime" : 1615985567069,
+  "updateTime" : 1615985567069,
+  "path" : "/add",
+  "description" : null,
+  "returnType" : null,
+  "mappingPath" : null,
+  "parameters" : [ {
+    "name" : "a",
+    "value" : null,
+    "description" : "",
+    "required" : false,
+    "dataType" : null,
+    "type" : "java.lang.Number",
+    "defaultValue" : null,
+    "validateType" : null,
+    "error" : null,
+    "expression" : null
+  }, {
+    "name" : "b",
+    "value" : null,
+    "description" : "",
+    "required" : false,
+    "dataType" : null,
+    "type" : "java.lang.Number",
+    "defaultValue" : null,
+    "validateType" : null,
+    "error" : null,
+    "expression" : null
+  } ]
+}
+================================
+return a +b;

+ 7 - 0
src/main/resources/magic-api/function/测试函数/group.json

@@ -0,0 +1,7 @@
+{
+  "id" : "9219a9a8cdb9442d820f0770ccf483ab",
+  "name" : "测试函数",
+  "type" : "2",
+  "parentId" : "0",
+  "path" : "/test"
+}

+ 16 - 0
src/main/resources/magic-api/function/测试函数/函数嵌套.ms

@@ -0,0 +1,16 @@
+{
+  "id" : "d062db46897c4a1fb93ca187ebe44a2f",
+  "script" : null,
+  "groupId" : "9219a9a8cdb9442d820f0770ccf483ab",
+  "name" : "函数嵌套",
+  "createTime" : 1615985594130,
+  "updateTime" : 1615985594130,
+  "path" : "nested",
+  "description" : null,
+  "returnType" : null,
+  "mappingPath" : null,
+  "parameters" : [ ]
+}
+================================
+import '@/test/add' as add;
+return add(1,2);