Sfoglia il codice sorgente

新增接口、函数的增删改查接口。

mxd 4 anni fa
parent
commit
5a5a379f21

+ 62 - 61
src/main/java/org/ssssssss/magicapi/config/MagicConfiguration.java

@@ -5,50 +5,41 @@ import org.ssssssss.magicapi.adapter.Resource;
 import org.ssssssss.magicapi.controller.RequestHandler;
 import org.ssssssss.magicapi.interceptor.AuthorizationInterceptor;
 import org.ssssssss.magicapi.interceptor.RequestInterceptor;
-import org.ssssssss.magicapi.provider.ApiServiceProvider;
-import org.ssssssss.magicapi.provider.FunctionServiceProvider;
-import org.ssssssss.magicapi.provider.GroupServiceProvider;
-import org.ssssssss.magicapi.provider.ResultProvider;
+import org.ssssssss.magicapi.provider.*;
 
 import java.util.ArrayList;
 import java.util.List;
 
 public class MagicConfiguration {
 
+	/**
+	 * 拦截器
+	 */
+	private final List<RequestInterceptor> requestInterceptors = new ArrayList<>();
 	/**
 	 * 接口映射
 	 */
 	private MappingHandlerMapping mappingHandlerMapping;
-
 	/**
 	 * 函数管理
 	 */
 	private MagicFunctionManager magicFunctionManager;
-
 	/**
 	 * 用户名
 	 */
 	private String username;
-
 	/**
 	 * 密码
 	 */
 	private String password;
-
 	/**
 	 * 编辑器配置文件
 	 */
 	private String editorConfig;
-
-	/**
-	 * 拦截器
-	 */
-	private final List<RequestInterceptor> requestInterceptors = new ArrayList<>();
-
 	/**
 	 * 接口查询Service
 	 */
-	private ApiServiceProvider magicApiService;
+	private ApiServiceProvider apiServiceProvider;
 
 	/**
 	 * 分组查询Service
@@ -65,6 +56,8 @@ public class MagicConfiguration {
 	 */
 	private MagicDynamicDataSource magicDynamicDataSource;
 
+	private MagicAPIService magicAPIService;
+
 	/**
 	 * 请求出错时,是否抛出异常
 	 */
@@ -88,66 +81,34 @@ public class MagicConfiguration {
 
 	private boolean enableWeb = false;
 
-	public void setEnableWeb(boolean enableWeb) {
-		this.enableWeb = enableWeb;
-	}
-
-	public void setUsername(String username) {
-		this.username = username;
-	}
-
-	public void setPassword(String password) {
-		this.password = password;
-	}
-
 	public void addRequestInterceptor(RequestInterceptor requestInterceptor) {
 		this.requestInterceptors.add(requestInterceptor);
 	}
 
-	public void setMappingHandlerMapping(MappingHandlerMapping mappingHandlerMapping) {
-		this.mappingHandlerMapping = mappingHandlerMapping;
-	}
-
-	public void setMagicApiService(ApiServiceProvider magicApiService) {
-		this.magicApiService = magicApiService;
-	}
-
-	public void setGroupServiceProvider(GroupServiceProvider groupServiceProvider) {
-		this.groupServiceProvider = groupServiceProvider;
-	}
-
-	public void setResultProvider(ResultProvider resultProvider) {
-		this.resultProvider = resultProvider;
-	}
-
-	public void setThrowException(boolean throwException) {
-		this.throwException = throwException;
-	}
-
-	public void setHttpMessageConverters(List<HttpMessageConverter<?>> httpMessageConverters) {
-		this.httpMessageConverters = httpMessageConverters;
-	}
-
-	public void setDebugTimeout(int debugTimeout) {
-		this.debugTimeout = debugTimeout;
-	}
-
-	public void setMagicDynamicDataSource(MagicDynamicDataSource magicDynamicDataSource) {
-		this.magicDynamicDataSource = magicDynamicDataSource;
-	}
-
 	public MappingHandlerMapping getMappingHandlerMapping() {
 		return mappingHandlerMapping;
 	}
 
+	public void setMappingHandlerMapping(MappingHandlerMapping mappingHandlerMapping) {
+		this.mappingHandlerMapping = mappingHandlerMapping;
+	}
+
 	public String getUsername() {
 		return username;
 	}
 
+	public void setUsername(String username) {
+		this.username = username;
+	}
+
 	public String getPassword() {
 		return password;
 	}
 
+	public void setPassword(String password) {
+		this.password = password;
+	}
+
 	public AuthorizationInterceptor getAuthorizationInterceptor() {
 		return authorizationInterceptor;
 	}
@@ -160,38 +121,70 @@ public class MagicConfiguration {
 		return requestInterceptors;
 	}
 
-	public ApiServiceProvider getMagicApiService() {
-		return magicApiService;
+	public ApiServiceProvider getApiServiceProvider() {
+		return apiServiceProvider;
+	}
+
+	public void setApiServiceProvider(ApiServiceProvider apiServiceProvider) {
+		this.apiServiceProvider = apiServiceProvider;
 	}
 
 	public GroupServiceProvider getGroupServiceProvider() {
 		return groupServiceProvider;
 	}
 
+	public void setGroupServiceProvider(GroupServiceProvider groupServiceProvider) {
+		this.groupServiceProvider = groupServiceProvider;
+	}
+
 	public MagicDynamicDataSource getMagicDynamicDataSource() {
 		return magicDynamicDataSource;
 	}
 
+	public void setMagicDynamicDataSource(MagicDynamicDataSource magicDynamicDataSource) {
+		this.magicDynamicDataSource = magicDynamicDataSource;
+	}
+
 	public boolean isThrowException() {
 		return throwException;
 	}
 
+	public void setThrowException(boolean throwException) {
+		this.throwException = throwException;
+	}
+
 	public ResultProvider getResultProvider() {
 		return resultProvider;
 	}
 
+	public void setResultProvider(ResultProvider resultProvider) {
+		this.resultProvider = resultProvider;
+	}
+
 	public List<HttpMessageConverter<?>> getHttpMessageConverters() {
 		return httpMessageConverters;
 	}
 
+	public void setHttpMessageConverters(List<HttpMessageConverter<?>> httpMessageConverters) {
+		this.httpMessageConverters = httpMessageConverters;
+	}
+
 	public int getDebugTimeout() {
 		return debugTimeout;
 	}
 
+	public void setDebugTimeout(int debugTimeout) {
+		this.debugTimeout = debugTimeout;
+	}
+
 	public boolean isEnableWeb() {
 		return enableWeb;
 	}
 
+	public void setEnableWeb(boolean enableWeb) {
+		this.enableWeb = enableWeb;
+	}
+
 	public FunctionServiceProvider getFunctionServiceProvider() {
 		return functionServiceProvider;
 	}
@@ -224,6 +217,14 @@ public class MagicConfiguration {
 		this.workspace = workspace;
 	}
 
+	public MagicAPIService getMagicAPIService() {
+		return magicAPIService;
+	}
+
+	public void setMagicAPIService(MagicAPIService magicAPIService) {
+		this.magicAPIService = magicAPIService;
+	}
+
 	/**
 	 * 打印banner
 	 */

+ 13 - 50
src/main/java/org/ssssssss/magicapi/controller/MagicAPIController.java

@@ -1,6 +1,5 @@
 package org.ssssssss.magicapi.controller;
 
-import org.apache.commons.lang3.StringUtils;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.ResponseBody;
@@ -10,21 +9,23 @@ import org.ssssssss.magicapi.interceptor.Authorization;
 import org.ssssssss.magicapi.model.ApiInfo;
 import org.ssssssss.magicapi.model.JsonBean;
 import org.ssssssss.magicapi.provider.ApiServiceProvider;
-import org.ssssssss.magicapi.utils.IoUtils;
+import org.ssssssss.magicapi.provider.MagicAPIService;
 
 import java.util.List;
-import java.util.Optional;
 
 /**
  * 接口相关操作
  */
 public class MagicAPIController extends MagicController implements MagicExceptionHandler {
 
-	private final ApiServiceProvider magicApiService;
+	private final ApiServiceProvider apiServiceProvider;
+
+	private final MagicAPIService magicAPIService;
 
 	public MagicAPIController(MagicConfiguration configuration) {
 		super(configuration);
-		this.magicApiService = configuration.getMagicApiService();
+		this.apiServiceProvider = configuration.getApiServiceProvider();
+		this.magicAPIService = configuration.getMagicAPIService();
 	}
 
 	/**
@@ -36,11 +37,7 @@ public class MagicAPIController extends MagicController implements MagicExceptio
 	@ResponseBody
 	@Valid(readonly = false, authorization = Authorization.DELETE)
 	public JsonBean<Boolean> delete(String id) {
-		boolean success = magicApiService.delete(id);
-		if (success) {    //删除成功时在取消注册
-			configuration.getMappingHandlerMapping().unregisterMapping(id, true);
-		}
-		return new JsonBean<>(success);
+		return new JsonBean<>(magicAPIService.deleteApi(id));
 	}
 
 	/**
@@ -50,7 +47,7 @@ public class MagicAPIController extends MagicController implements MagicExceptio
 	@ResponseBody
 	@Valid(authorization = Authorization.VIEW)
 	public JsonBean<List<ApiInfo>> list() {
-		return new JsonBean<>(magicApiService.list());
+		return new JsonBean<>(magicAPIService.apiList());
 	}
 
 	/**
@@ -62,7 +59,7 @@ public class MagicAPIController extends MagicController implements MagicExceptio
 	@ResponseBody
 	@Valid(authorization = Authorization.VIEW)
 	public JsonBean<ApiInfo> get(String id) {
-		return new JsonBean<>(magicApiService.get(id));
+		return new JsonBean<>(apiServiceProvider.get(id));
 	}
 
 	/**
@@ -74,7 +71,7 @@ public class MagicAPIController extends MagicController implements MagicExceptio
 	@ResponseBody
 	@Valid(authorization = Authorization.VIEW)
 	public JsonBean<List<Long>> backups(String id) {
-		return new JsonBean<>(magicApiService.backupList(id));
+		return new JsonBean<>(apiServiceProvider.backupList(id));
 	}
 
 	/**
@@ -87,7 +84,7 @@ public class MagicAPIController extends MagicController implements MagicExceptio
 	@ResponseBody
 	@Valid(authorization = Authorization.VIEW)
 	public JsonBean<ApiInfo> backups(String id, Long timestamp) {
-		return new JsonBean<>(magicApiService.backupInfo(id, timestamp));
+		return new JsonBean<>(apiServiceProvider.backupInfo(id, timestamp));
 	}
 
 	/**
@@ -97,14 +94,7 @@ public class MagicAPIController extends MagicController implements MagicExceptio
 	@ResponseBody
 	@Valid(readonly = false, authorization = Authorization.SAVE)
 	public JsonBean<Boolean> apiMove(String id, String groupId) {
-		// 验证分组是否存在
-		isTrue(configuration.getGroupServiceProvider().containsApiGroup(groupId), GROUP_NOT_FOUND);
-		// 验证移动后名字是否有冲突
-		isTrue(magicApiService.allowMove(id, groupId), NAME_CONFLICT);
-		// 验证路径是否有冲突
-		isTrue(configuration.getMappingHandlerMapping().move(id, groupId), REQUEST_PATH_CONFLICT);
-
-		return new JsonBean<>(magicApiService.move(id, groupId));
+		return new JsonBean<>(magicAPIService.moveApi(id, groupId));
 	}
 
 	/**
@@ -116,34 +106,7 @@ public class MagicAPIController extends MagicController implements MagicExceptio
 	@ResponseBody
 	@Valid(readonly = false, authorization = Authorization.SAVE)
 	public JsonBean<String> save(@RequestBody ApiInfo info) {
-		// 非空验证
-		notBlank(info.getMethod(), REQUEST_METHOD_REQUIRED);
-		notBlank(info.getPath(), REQUEST_PATH_REQUIRED);
-		notBlank(info.getName(), API_NAME_REQUIRED);
-		notBlank(info.getScript(), SCRIPT_REQUIRED);
-		// 验证名字
-		isTrue(IoUtils.validateFileName(info.getName()), NAME_INVALID);
-		// 验证路径是否有冲突
-		isTrue(!configuration.getMappingHandlerMapping().hasRegisterMapping(info), REQUEST_PATH_CONFLICT);
-		if (StringUtils.isBlank(info.getId())) {
-			// 先判断接口是否存在
-			isTrue(!magicApiService.exists(info), API_ALREADY_EXISTS.format(info.getMethod(), info.getPath()));
-
-			isTrue(magicApiService.insert(info), API_SAVE_FAILURE);
-		} else {
-			// 先判断接口是否存在
-			isTrue(!magicApiService.existsWithoutId(info), API_ALREADY_EXISTS.format(info.getMethod(), info.getPath()));
-			Optional<ApiInfo> optional = configuration.getMappingHandlerMapping().getApiInfos().stream()
-					.filter(it -> it.getId().equals(info.getId()))
-					.findFirst();
-			if (optional.isPresent() && !optional.get().equals(info)) {
-				isTrue(magicApiService.update(info), API_SAVE_FAILURE);
-				magicApiService.backup(info);
-			}
-		}
-		// 注册接口
-		configuration.getMappingHandlerMapping().registerMapping(info, true);
-		return new JsonBean<>(info.getId());
+		return new JsonBean<>(magicAPIService.saveApi(info));
 	}
 
 }

+ 0 - 18
src/main/java/org/ssssssss/magicapi/controller/MagicController.java

@@ -1,6 +1,5 @@
 package org.ssssssss.magicapi.controller;
 
-import org.apache.commons.lang3.StringUtils;
 import org.springframework.web.bind.annotation.ExceptionHandler;
 import org.springframework.web.bind.annotation.ResponseBody;
 import org.ssssssss.magicapi.config.MagicConfiguration;
@@ -11,7 +10,6 @@ import org.ssssssss.magicapi.interceptor.Authorization;
 import org.ssssssss.magicapi.interceptor.MagicUser;
 import org.ssssssss.magicapi.model.Constants;
 import org.ssssssss.magicapi.model.JsonBean;
-import org.ssssssss.magicapi.model.JsonCode;
 import org.ssssssss.magicapi.model.JsonCodeConstants;
 
 import javax.servlet.http.HttpServletRequest;
@@ -35,22 +33,6 @@ public class MagicController implements JsonCodeConstants {
 		}
 	}
 
-	public void notNull(Object value, JsonCode jsonCode) {
-		if (value == null) {
-			throw new InvalidArgumentException(jsonCode);
-		}
-	}
-
-	public void isTrue(boolean value, JsonCode jsonCode) {
-		if (!value) {
-			throw new InvalidArgumentException(jsonCode);
-		}
-	}
-
-	public void notBlank(String value, JsonCode jsonCode) {
-		isTrue(StringUtils.isNotBlank(value), jsonCode);
-	}
-
 	/**
 	 * 判断是否有权限访问按钮
 	 */

+ 4 - 1
src/main/java/org/ssssssss/magicapi/controller/MagicDataSourceController.java

@@ -10,6 +10,7 @@ import org.springframework.boot.context.properties.source.ConfigurationPropertyN
 import org.springframework.boot.context.properties.source.ConfigurationPropertySource;
 import org.springframework.boot.context.properties.source.MapConfigurationPropertySource;
 import org.springframework.boot.jdbc.DatabaseDriver;
+import org.springframework.jdbc.datasource.DataSourceUtils;
 import org.springframework.util.ClassUtils;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -27,6 +28,7 @@ import org.ssssssss.magicapi.utils.JsonUtils;
 import org.ssssssss.script.functions.ObjectConvertExtension;
 
 import javax.sql.DataSource;
+import java.sql.Connection;
 import java.util.*;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
@@ -74,7 +76,8 @@ public class MagicDataSourceController extends MagicController implements MagicE
 		DataSource dataSource = null;
 		try {
 			dataSource = createDataSource(properties);
-			dataSource.getConnection();
+			Connection connection = dataSource.getConnection();
+			DataSourceUtils.doCloseConnection(connection, dataSource);
 		} catch (Exception e) {
 			return new JsonBean<>(e.getMessage());
 		} finally {

+ 8 - 27
src/main/java/org/ssssssss/magicapi/controller/MagicFunctionController.java

@@ -1,6 +1,5 @@
 package org.ssssssss.magicapi.controller;
 
-import org.apache.commons.lang3.StringUtils;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.ResponseBody;
@@ -10,7 +9,7 @@ import org.ssssssss.magicapi.interceptor.Authorization;
 import org.ssssssss.magicapi.model.FunctionInfo;
 import org.ssssssss.magicapi.model.JsonBean;
 import org.ssssssss.magicapi.provider.FunctionServiceProvider;
-import org.ssssssss.magicapi.utils.IoUtils;
+import org.ssssssss.magicapi.provider.MagicAPIService;
 
 import java.util.List;
 
@@ -18,16 +17,19 @@ public class MagicFunctionController extends MagicController implements MagicExc
 
 	private final FunctionServiceProvider functionService;
 
+	private final MagicAPIService magicAPIService;
+
 	public MagicFunctionController(MagicConfiguration configuration) {
 		super(configuration);
 		this.functionService = configuration.getFunctionServiceProvider();
+		this.magicAPIService = configuration.getMagicAPIService();
 	}
 
 	@RequestMapping("/function/list")
 	@ResponseBody
 	@Valid(authorization = Authorization.VIEW)
 	public JsonBean<List<FunctionInfo>> list() {
-		return new JsonBean<>(functionService.list());
+		return new JsonBean<>(magicAPIService.functionList());
 	}
 
 	@RequestMapping("/function/get")
@@ -55,9 +57,7 @@ public class MagicFunctionController extends MagicController implements MagicExc
 	@ResponseBody
 	@Valid(readonly = false, authorization = Authorization.SAVE)
 	public JsonBean<Boolean> move(String id, String groupId) {
-		isTrue(functionService.allowMove(id, groupId), NAME_CONFLICT);
-		isTrue(configuration.getMagicFunctionManager().move(id, groupId), FUNCTION_PATH_CONFLICT);
-		return new JsonBean<>(functionService.move(id, groupId));
+		return new JsonBean<>(magicAPIService.moveFunction(id, groupId));
 	}
 
 
@@ -65,32 +65,13 @@ public class MagicFunctionController extends MagicController implements MagicExc
 	@ResponseBody
 	@Valid(readonly = false, authorization = Authorization.SAVE)
 	public JsonBean<String> save(@RequestBody FunctionInfo functionInfo) {
-		notBlank(functionInfo.getName(), FUNCTION_NAME_REQUIRED);
-		isTrue(IoUtils.validateFileName(functionInfo.getName()), NAME_INVALID);
-		notBlank(functionInfo.getPath(), FUNCTION_PATH_REQUIRED);
-		notBlank(functionInfo.getScript(), SCRIPT_REQUIRED);
-		isTrue(!configuration.getMagicFunctionManager().hasRegister(functionInfo), FUNCTION_PATH_CONFLICT);
-
-		if (StringUtils.isBlank(functionInfo.getId())) {
-			isTrue(!functionService.exists(functionInfo), FUNCTION_ALREADY_EXISTS.format(functionInfo.getPath()));
-			isTrue(functionService.insert(functionInfo), FUNCTION_SAVE_FAILURE);
-		} else {
-			isTrue(!functionService.existsWithoutId(functionInfo), FUNCTION_ALREADY_EXISTS.format(functionInfo.getPath()));
-			isTrue(functionService.update(functionInfo), FUNCTION_SAVE_FAILURE);
-			functionService.backup(functionInfo);
-		}
-		configuration.getMagicFunctionManager().register(functionInfo);
-		return new JsonBean<>(functionInfo.getId());
+		return new JsonBean<>(magicAPIService.saveFunction(functionInfo));
 	}
 
 	@RequestMapping("/function/delete")
 	@ResponseBody
 	@Valid(readonly = false, authorization = Authorization.DELETE)
 	public JsonBean<Boolean> delete(String id) {
-		boolean success = functionService.delete(id);
-		if (success) {
-			configuration.getMagicFunctionManager().unregister(id);
-		}
-		return new JsonBean<>(success);
+		return new JsonBean<>(magicAPIService.deleteFunction(id));
 	}
 }

+ 6 - 71
src/main/java/org/ssssssss/magicapi/controller/MagicGroupController.java

@@ -1,30 +1,24 @@
 package org.ssssssss.magicapi.controller;
 
-import org.apache.commons.lang3.StringUtils;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.ResponseBody;
 import org.ssssssss.magicapi.config.MagicConfiguration;
 import org.ssssssss.magicapi.config.Valid;
 import org.ssssssss.magicapi.interceptor.Authorization;
-import org.ssssssss.magicapi.model.Constants;
 import org.ssssssss.magicapi.model.Group;
 import org.ssssssss.magicapi.model.JsonBean;
-import org.ssssssss.magicapi.model.TreeNode;
-import org.ssssssss.magicapi.provider.GroupServiceProvider;
-import org.ssssssss.magicapi.utils.IoUtils;
+import org.ssssssss.magicapi.provider.MagicAPIService;
 
 import java.util.List;
-import java.util.Objects;
-import java.util.stream.Collectors;
 
 public class MagicGroupController extends MagicController implements MagicExceptionHandler {
 
-	private final GroupServiceProvider groupServiceProvider;
+	private final MagicAPIService magicAPIService;
 
 	public MagicGroupController(MagicConfiguration configuration) {
 		super(configuration);
-		this.groupServiceProvider = configuration.getGroupServiceProvider();
+		this.magicAPIService = configuration.getMagicAPIService();
 	}
 
 	/**
@@ -34,35 +28,7 @@ public class MagicGroupController extends MagicController implements MagicExcept
 	@ResponseBody
 	@Valid(readonly = false, authorization = Authorization.DELETE)
 	public JsonBean<Boolean> deleteGroup(String groupId) {
-		boolean isApi = true;
-		TreeNode<Group> treeNode = configuration.getGroupServiceProvider().apiGroupTree().findTreeNode(group -> group.getId().equals(groupId));
-		if (treeNode == null) {
-			treeNode = configuration.getGroupServiceProvider().functionGroupTree().findTreeNode(group -> group.getId().equals(groupId));
-			notNull(treeNode, GROUP_NOT_FOUND);
-			isApi = false;
-		}
-		List<String> children = treeNode.flat().stream().map(Group::getId).collect(Collectors.toList());
-		boolean success;
-		if (isApi) {
-			// 删除接口
-			if (success = configuration.getMagicApiService().deleteGroup(groupId, children)) {
-				// 取消注册
-				configuration.getMappingHandlerMapping().deleteGroup(children);
-				children.forEach(configuration.getGroupServiceProvider()::delete);
-				// 重新加载分组
-				configuration.getMappingHandlerMapping().loadGroup();
-			}
-		} else {
-			// 删除函数
-			if (success = configuration.getFunctionServiceProvider().deleteGroup(groupId, children)) {
-				// 取消注册
-				configuration.getMagicFunctionManager().deleteGroup(children);
-				children.forEach(configuration.getGroupServiceProvider()::delete);
-				// 重新加载分组
-				configuration.getMagicFunctionManager().loadGroup();
-			}
-		}
-		return new JsonBean<>(success);
+		return new JsonBean<>(magicAPIService.deleteGroup(groupId));
 	}
 
 	/**
@@ -72,26 +38,7 @@ public class MagicGroupController extends MagicController implements MagicExcept
 	@ResponseBody
 	@Valid(readonly = false, authorization = Authorization.SAVE)
 	public synchronized JsonBean<Boolean> groupUpdate(@RequestBody Group group) {
-		if (StringUtils.isBlank(group.getParentId())) {
-			group.setParentId("0");
-		}
-		notBlank(group.getName(), GROUP_NAME_REQUIRED);
-		isTrue(IoUtils.validateFileName(group.getName()), NAME_INVALID);
-
-		notBlank(group.getType(), GROUP_TYPE_REQUIRED);
-		boolean isApiGroup = Constants.GROUP_TYPE_API.equals(group.getType());
-		boolean isFunctionGroup = Constants.GROUP_TYPE_FUNCTION.equals(group.getType());
-		if (isApiGroup && configuration.getMappingHandlerMapping().checkGroup(group)) {
-			isTrue(groupServiceProvider.update(group), GROUP_SAVE_FAILURE);
-			// 如果数据库修改成功,则修改接口路径
-			configuration.getMappingHandlerMapping().updateGroup(group);
-			configuration.getMagicApiService().reload(group.getId());
-			return new JsonBean<>(true);
-		} else if (isFunctionGroup && configuration.getMagicFunctionManager().checkGroup(group)) {
-			isTrue(groupServiceProvider.update(group), GROUP_SAVE_FAILURE);
-			// 如果数据库修改成功,则修改接口路径
-			configuration.getMagicFunctionManager().updateGroup(group);
-			configuration.getFunctionServiceProvider().reload(group.getId());
+		if (magicAPIService.updateGroup(group)) {
 			return new JsonBean<>(true);
 		}
 		return new JsonBean<>(GROUP_CONFLICT);
@@ -104,7 +51,7 @@ public class MagicGroupController extends MagicController implements MagicExcept
 	@ResponseBody
 	@Valid(authorization = Authorization.VIEW)
 	public JsonBean<List<Group>> groupList(String type) {
-		return new JsonBean<>(groupServiceProvider.groupList(type));
+		return new JsonBean<>(magicAPIService.groupList(type));
 	}
 
 	/**
@@ -114,18 +61,6 @@ public class MagicGroupController extends MagicController implements MagicExcept
 	@ResponseBody
 	@Valid(readonly = false, authorization = Authorization.SAVE)
 	public JsonBean<String> createGroup(@RequestBody Group group) {
-		if (StringUtils.isBlank(group.getParentId())) {
-			group.setParentId("0");
-		}
-		notBlank(group.getName(), GROUP_NAME_REQUIRED);
-		isTrue(IoUtils.validateFileName(group.getName()), NAME_INVALID);
-		notBlank(group.getType(), GROUP_TYPE_REQUIRED);
-		isTrue(groupServiceProvider.insert(group), GROUP_SAVE_FAILURE);
-		if (Objects.equals(group.getType(), Constants.GROUP_TYPE_API)) {
-			configuration.getMappingHandlerMapping().loadGroup();
-		} else {
-			configuration.getMagicFunctionManager().loadGroup();
-		}
 		return new JsonBean<>(group.getId());
 	}
 }

+ 2 - 2
src/main/java/org/ssssssss/magicapi/controller/MagicWorkbenchController.java

@@ -226,7 +226,7 @@ public class MagicWorkbenchController extends MagicController implements MagicEx
 		}
 		Resource backups = configuration.getWorkspace().getDirectory(Constants.PATH_BACKUPS);
 		// 保存
-		write(configuration.getMagicApiService(), backups, apiInfos);
+		write(configuration.getApiServiceProvider(), backups, apiInfos);
 		write(configuration.getFunctionServiceProvider(), backups, functionInfos);
 		// 重新注册
 		configuration.getMappingHandlerMapping().registerAllMapping();
@@ -260,7 +260,7 @@ public class MagicWorkbenchController extends MagicController implements MagicEx
 			for (Resource file : root.files(".ms")) {
 				boolean conflict;
 				if (isApi) {
-					ApiInfo info = configuration.getMagicApiService().deserialize(file.read());
+					ApiInfo info = configuration.getApiServiceProvider().deserialize(file.read());
 					apiInfos.add(info);
 					conflict = !apiPaths.add(Objects.toString(info.getMethod(), "GET") + ":" + PathUtils.replaceSlash(parentPath + "/" + path + "/" + info.getPath()));
 				} else {

+ 19 - 0
src/main/java/org/ssssssss/magicapi/model/JsonCodeConstants.java

@@ -1,5 +1,8 @@
 package org.ssssssss.magicapi.model;
 
+import org.apache.commons.lang3.StringUtils;
+import org.ssssssss.magicapi.exception.InvalidArgumentException;
+
 public interface JsonCodeConstants {
 
 	JsonCode SUCCESS = new JsonCode(1, "success");
@@ -70,4 +73,20 @@ public interface JsonCodeConstants {
 	JsonCode DATASOURCE_NOT_FOUND = new JsonCode(0, "找不到对应的数据源");
 
 	JsonCode DATASOURCE_TYPE_NOT_SET = new JsonCode(0, "请设置数据源类型");
+
+	default void notNull(Object value, JsonCode jsonCode) {
+		if (value == null) {
+			throw new InvalidArgumentException(jsonCode);
+		}
+	}
+
+	default void isTrue(boolean value, JsonCode jsonCode) {
+		if (!value) {
+			throw new InvalidArgumentException(jsonCode);
+		}
+	}
+
+	default void notBlank(String value, JsonCode jsonCode) {
+		isTrue(StringUtils.isNotBlank(value), jsonCode);
+	}
 }

+ 88 - 0
src/main/java/org/ssssssss/magicapi/provider/MagicAPIService.java

@@ -1,7 +1,11 @@
 package org.ssssssss.magicapi.provider;
 
 import org.ssssssss.magicapi.config.MagicModule;
+import org.ssssssss.magicapi.model.ApiInfo;
+import org.ssssssss.magicapi.model.FunctionInfo;
+import org.ssssssss.magicapi.model.Group;
 
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -26,4 +30,88 @@ public interface MagicAPIService extends MagicModule {
 	 * @param context 请求上下文,主要给脚本中使用
 	 */
 	Object call(String method, String path, Map<String, Object> context);
+
+	/**
+	 * 保存接口
+	 *
+	 * @return 保存成功后,返回Id
+	 */
+	String saveApi(ApiInfo apiInfo);
+
+	/**
+	 * 获取接口列表
+	 */
+	List<ApiInfo> apiList();
+
+	/**
+	 * 删除接口
+	 *
+	 * @param id 接口id
+	 */
+	boolean deleteApi(String id);
+
+	/**
+	 * 移动接口
+	 *
+	 * @param id      接口id
+	 * @param groupId 分组id
+	 */
+	boolean moveApi(String id, String groupId);
+
+	/**
+	 * 保存函数
+	 *
+	 * @return 保存成功后,返回Id
+	 */
+	String saveFunction(FunctionInfo functionInfo);
+
+	/**
+	 * 获取函数列表
+	 */
+	List<FunctionInfo> functionList();
+
+	/**
+	 * 删除函数
+	 *
+	 * @param id 函数id
+	 */
+	boolean deleteFunction(String id);
+
+	/**
+	 * 移动函数
+	 *
+	 * @param id      函数id
+	 * @param groupId 分组id
+	 */
+	boolean moveFunction(String id, String groupId);
+
+
+	/**
+	 * 创建分组
+	 *
+	 * @param group 分组信息
+	 * @return 创建成功后返回分组id
+	 */
+	String createGroup(Group group);
+
+	/**
+	 * 修改分组信息
+	 *
+	 * @param group 分组信息
+	 */
+	boolean updateGroup(Group group);
+
+	/**
+	 * 删除分组
+	 *
+	 * @param id 分组id
+	 */
+	boolean deleteGroup(String id);
+
+	/**
+	 * 查询分组列表
+	 *
+	 * @param type 分组类型,1 接口分组,2 函数分组
+	 */
+	List<Group> groupList(String type);
 }

+ 203 - 6
src/main/java/org/ssssssss/magicapi/provider/impl/DefaultMagicAPIService.java

@@ -1,12 +1,13 @@
 package org.ssssssss.magicapi.provider.impl;
 
+import org.apache.commons.lang3.StringUtils;
+import org.ssssssss.magicapi.config.MagicFunctionManager;
 import org.ssssssss.magicapi.config.MappingHandlerMapping;
 import org.ssssssss.magicapi.exception.MagicServiceException;
-import org.ssssssss.magicapi.model.ApiInfo;
-import org.ssssssss.magicapi.model.RequestEntity;
-import org.ssssssss.magicapi.provider.MagicAPIService;
-import org.ssssssss.magicapi.provider.ResultProvider;
+import org.ssssssss.magicapi.model.*;
+import org.ssssssss.magicapi.provider.*;
 import org.ssssssss.magicapi.script.ScriptManager;
+import org.ssssssss.magicapi.utils.IoUtils;
 import org.ssssssss.script.MagicResourceLoader;
 import org.ssssssss.script.MagicScript;
 import org.ssssssss.script.MagicScriptContext;
@@ -16,9 +17,13 @@ import org.ssssssss.script.parsing.ast.Expression;
 
 import javax.script.ScriptContext;
 import javax.script.SimpleScriptContext;
+import java.util.List;
 import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Collectors;
 
-public class DefaultMagicAPIService implements MagicAPIService {
+public class DefaultMagicAPIService implements MagicAPIService, JsonCodeConstants {
 
 	private final MappingHandlerMapping mappingHandlerMapping;
 
@@ -26,9 +31,21 @@ public class DefaultMagicAPIService implements MagicAPIService {
 
 	private final ResultProvider resultProvider;
 
-	public DefaultMagicAPIService(MappingHandlerMapping mappingHandlerMapping, ResultProvider resultProvider, boolean throwException) {
+	private final ApiServiceProvider apiServiceProvider;
+
+	private final FunctionServiceProvider functionServiceProvider;
+
+	private final GroupServiceProvider groupServiceProvider;
+
+	private final MagicFunctionManager magicFunctionManager;
+
+	public DefaultMagicAPIService(MappingHandlerMapping mappingHandlerMapping, ApiServiceProvider apiServiceProvider, FunctionServiceProvider functionServiceProvider, GroupServiceProvider groupServiceProvider, ResultProvider resultProvider, MagicFunctionManager magicFunctionManager, boolean throwException) {
 		this.mappingHandlerMapping = mappingHandlerMapping;
+		this.apiServiceProvider = apiServiceProvider;
+		this.functionServiceProvider = functionServiceProvider;
+		this.groupServiceProvider = groupServiceProvider;
 		this.resultProvider = resultProvider;
+		this.magicFunctionManager = magicFunctionManager;
 		this.throwException = throwException;
 		MagicResourceLoader.addFunctionLoader((name) -> {
 			int index = name.indexOf(":");
@@ -92,6 +109,186 @@ public class DefaultMagicAPIService implements MagicAPIService {
 		}
 	}
 
+	@Override
+	public String saveApi(ApiInfo info) {
+		// 非空验证
+		notBlank(info.getMethod(), REQUEST_METHOD_REQUIRED);
+		notBlank(info.getPath(), REQUEST_PATH_REQUIRED);
+		notBlank(info.getName(), API_NAME_REQUIRED);
+		notBlank(info.getScript(), SCRIPT_REQUIRED);
+		// 验证名字
+		isTrue(IoUtils.validateFileName(info.getName()), NAME_INVALID);
+		// 验证路径是否有冲突
+		isTrue(!mappingHandlerMapping.hasRegisterMapping(info), REQUEST_PATH_CONFLICT);
+		if (StringUtils.isBlank(info.getId())) {
+			// 先判断接口是否存在
+			isTrue(!apiServiceProvider.exists(info), API_ALREADY_EXISTS.format(info.getMethod(), info.getPath()));
+
+			isTrue(apiServiceProvider.insert(info), API_SAVE_FAILURE);
+		} else {
+			// 先判断接口是否存在
+			isTrue(!apiServiceProvider.existsWithoutId(info), API_ALREADY_EXISTS.format(info.getMethod(), info.getPath()));
+			Optional<ApiInfo> optional = mappingHandlerMapping.getApiInfos().stream()
+					.filter(it -> it.getId().equals(info.getId()))
+					.findFirst();
+			if (optional.isPresent() && !optional.get().equals(info)) {
+				isTrue(apiServiceProvider.update(info), API_SAVE_FAILURE);
+				apiServiceProvider.backup(info);
+			}
+		}
+		// 注册接口
+		mappingHandlerMapping.registerMapping(info, true);
+		return info.getId();
+	}
+
+	@Override
+	public List<ApiInfo> apiList() {
+		return apiServiceProvider.list();
+	}
+
+	@Override
+	public boolean deleteApi(String id) {
+		boolean success = apiServiceProvider.delete(id);
+		if (success) {    //删除成功时在取消注册
+			mappingHandlerMapping.unregisterMapping(id, true);
+		}
+		return success;
+	}
+
+	@Override
+	public boolean moveApi(String id, String groupId) {
+		// 验证分组是否存在
+		isTrue(groupServiceProvider.containsApiGroup(groupId), GROUP_NOT_FOUND);
+		// 验证移动后名字是否有冲突
+		isTrue(apiServiceProvider.allowMove(id, groupId), NAME_CONFLICT);
+		// 验证路径是否有冲突
+		isTrue(mappingHandlerMapping.move(id, groupId), REQUEST_PATH_CONFLICT);
+		return apiServiceProvider.move(id, groupId);
+	}
+
+	@Override
+	public String saveFunction(FunctionInfo functionInfo) {
+		notBlank(functionInfo.getName(), FUNCTION_NAME_REQUIRED);
+		isTrue(IoUtils.validateFileName(functionInfo.getName()), NAME_INVALID);
+		notBlank(functionInfo.getPath(), FUNCTION_PATH_REQUIRED);
+		notBlank(functionInfo.getScript(), SCRIPT_REQUIRED);
+		isTrue(!magicFunctionManager.hasRegister(functionInfo), FUNCTION_PATH_CONFLICT);
+
+		if (StringUtils.isBlank(functionInfo.getId())) {
+			isTrue(!functionServiceProvider.exists(functionInfo), FUNCTION_ALREADY_EXISTS.format(functionInfo.getPath()));
+			isTrue(functionServiceProvider.insert(functionInfo), FUNCTION_SAVE_FAILURE);
+		} else {
+			isTrue(!functionServiceProvider.existsWithoutId(functionInfo), FUNCTION_ALREADY_EXISTS.format(functionInfo.getPath()));
+			isTrue(functionServiceProvider.update(functionInfo), FUNCTION_SAVE_FAILURE);
+			functionServiceProvider.backup(functionInfo);
+		}
+		magicFunctionManager.register(functionInfo);
+		return functionInfo.getId();
+	}
+
+	@Override
+	public List<FunctionInfo> functionList() {
+		return functionServiceProvider.list();
+	}
+
+	@Override
+	public boolean deleteFunction(String id) {
+		boolean success = functionServiceProvider.delete(id);
+		if (success) {
+			magicFunctionManager.unregister(id);
+		}
+		return success;
+	}
+
+	@Override
+	public boolean moveFunction(String id, String groupId) {
+		isTrue(functionServiceProvider.allowMove(id, groupId), NAME_CONFLICT);
+		isTrue(magicFunctionManager.move(id, groupId), FUNCTION_PATH_CONFLICT);
+		return functionServiceProvider.move(id, groupId);
+	}
+
+	@Override
+	public String createGroup(Group group) {
+		if (StringUtils.isBlank(group.getParentId())) {
+			group.setParentId("0");
+		}
+		notBlank(group.getName(), GROUP_NAME_REQUIRED);
+		isTrue(IoUtils.validateFileName(group.getName()), NAME_INVALID);
+		notBlank(group.getType(), GROUP_TYPE_REQUIRED);
+		isTrue(groupServiceProvider.insert(group), GROUP_SAVE_FAILURE);
+		if (Objects.equals(group.getType(), Constants.GROUP_TYPE_API)) {
+			mappingHandlerMapping.loadGroup();
+		} else {
+			magicFunctionManager.loadGroup();
+		}
+		return group.getId();
+	}
+
+	@Override
+	public boolean updateGroup(Group group) {
+		if (StringUtils.isBlank(group.getParentId())) {
+			group.setParentId("0");
+		}
+		notBlank(group.getName(), GROUP_NAME_REQUIRED);
+		isTrue(IoUtils.validateFileName(group.getName()), NAME_INVALID);
+
+		notBlank(group.getType(), GROUP_TYPE_REQUIRED);
+		boolean isApiGroup = Constants.GROUP_TYPE_API.equals(group.getType());
+		boolean isFunctionGroup = Constants.GROUP_TYPE_FUNCTION.equals(group.getType());
+		if (isApiGroup && mappingHandlerMapping.checkGroup(group)) {
+			isTrue(groupServiceProvider.update(group), GROUP_SAVE_FAILURE);
+			// 如果数据库修改成功,则修改接口路径
+			mappingHandlerMapping.updateGroup(group);
+			apiServiceProvider.reload(group.getId());
+			return true;
+		} else if (isFunctionGroup && magicFunctionManager.checkGroup(group)) {
+			isTrue(groupServiceProvider.update(group), GROUP_SAVE_FAILURE);
+			// 如果数据库修改成功,则修改接口路径
+			magicFunctionManager.updateGroup(group);
+			functionServiceProvider.reload(group.getId());
+			return true;
+		}
+		return false;
+	}
+
+	@Override
+	public boolean deleteGroup(String groupId) {
+		boolean isApi = true;
+		TreeNode<Group> treeNode = groupServiceProvider.apiGroupTree().findTreeNode(group -> group.getId().equals(groupId));
+		if (treeNode == null) {
+			treeNode = groupServiceProvider.functionGroupTree().findTreeNode(group -> group.getId().equals(groupId));
+			notNull(treeNode, GROUP_NOT_FOUND);
+			isApi = false;
+		}
+		List<String> children = treeNode.flat().stream().map(Group::getId).collect(Collectors.toList());
+		boolean success;
+		if (isApi) {
+			// 删除接口
+			if (success = apiServiceProvider.deleteGroup(groupId, children)) {
+				// 取消注册
+				mappingHandlerMapping.deleteGroup(children);
+				children.forEach(groupServiceProvider::delete);
+				// 重新加载分组
+				mappingHandlerMapping.loadGroup();
+			}
+		} else {
+			// 删除函数
+			if (success = functionServiceProvider.deleteGroup(groupId, children)) {
+				// 取消注册
+				magicFunctionManager.deleteGroup(children);
+				children.forEach(groupServiceProvider::delete);
+				// 重新加载分组
+				magicFunctionManager.loadGroup();
+			}
+		}
+		return success;
+	}
+
+	@Override
+	public List<Group> groupList(String type) {
+		return groupServiceProvider.groupList(type);
+	}
+
 	@Override
 	public String getModuleName() {
 		return "magic";