Selaa lähdekoodia

代码重构以及优化

mxd 4 vuotta sitten
vanhempi
sitoutus
3b58bcceda
20 muutettua tiedostoa jossa 433 lisäystä ja 389 poistoa
  1. 27 11
      src/main/java/org/ssssssss/magicapi/adapter/resource/DatabaseResource.java
  2. 11 4
      src/main/java/org/ssssssss/magicapi/adapter/resource/RedisResource.java
  3. 36 0
      src/main/java/org/ssssssss/magicapi/config/MagicWebRequestInterceptor.java
  4. 21 0
      src/main/java/org/ssssssss/magicapi/config/Valid.java
  5. 50 115
      src/main/java/org/ssssssss/magicapi/controller/MagicAPIController.java
  6. 45 1
      src/main/java/org/ssssssss/magicapi/controller/MagicController.java
  7. 35 103
      src/main/java/org/ssssssss/magicapi/controller/MagicFunctionController.java
  8. 62 121
      src/main/java/org/ssssssss/magicapi/controller/MagicGroupController.java
  9. 2 2
      src/main/java/org/ssssssss/magicapi/controller/MagicWorkbenchController.java
  10. 12 8
      src/main/java/org/ssssssss/magicapi/controller/RequestHandler.java
  11. 17 0
      src/main/java/org/ssssssss/magicapi/exception/InvalidArgumentException.java
  12. 1 1
      src/main/java/org/ssssssss/magicapi/interceptor/RequestInterceptor.java
  13. 6 0
      src/main/java/org/ssssssss/magicapi/interceptor/SQLInterceptor.java
  14. 8 0
      src/main/java/org/ssssssss/magicapi/model/JsonBean.java
  15. 33 0
      src/main/java/org/ssssssss/magicapi/model/JsonCode.java
  16. 56 0
      src/main/java/org/ssssssss/magicapi/model/JsonCodeConstants.java
  17. 4 15
      src/main/java/org/ssssssss/magicapi/provider/ApiServiceProvider.java
  18. 4 4
      src/main/java/org/ssssssss/magicapi/provider/FunctionServiceProvider.java
  19. 0 1
      src/main/java/org/ssssssss/magicapi/provider/StoreServiceProvider.java
  20. 3 3
      src/main/java/org/ssssssss/magicapi/provider/impl/DefaultGroupServiceProvider.java

+ 27 - 11
src/main/java/org/ssssssss/magicapi/adapter/resource/DatabaseResource.java

@@ -16,7 +16,7 @@ public class DatabaseResource extends KeyValueResource {
 
 	private final String tableName;
 
-	private Map<String,String> cachedContent = new ConcurrentHashMap<>();
+	private Map<String, String> cachedContent = new ConcurrentHashMap<>();
 
 	public DatabaseResource(JdbcTemplate template, String tableName, String separator, String path, boolean readonly, KeyValueResource parent) {
 		super(separator, path, readonly, parent);
@@ -24,7 +24,7 @@ public class DatabaseResource extends KeyValueResource {
 		this.tableName = tableName;
 	}
 
-	public DatabaseResource(JdbcTemplate template, String tableName, String separator, String path, boolean readonly, Map<String,String> cachedContent, KeyValueResource parent) {
+	public DatabaseResource(JdbcTemplate template, String tableName, String separator, String path, boolean readonly, Map<String, String> cachedContent, KeyValueResource parent) {
 		this(template, tableName, separator, path, readonly, parent);
 		this.cachedContent = cachedContent;
 	}
@@ -32,7 +32,7 @@ public class DatabaseResource extends KeyValueResource {
 	@Override
 	public byte[] read() {
 		String value = this.cachedContent.get(path);
-		if(value == null){
+		if (value == null) {
 			String sql = String.format("select file_content from %s where file_path = ?", tableName);
 			value = template.queryForObject(sql, String.class, this.path);
 		}
@@ -41,16 +41,17 @@ public class DatabaseResource extends KeyValueResource {
 
 	@Override
 	public void readAll() {
+		this.cachedContent.clear();
 		String sql = String.format("select file_path, file_content from %s where file_path like '%s%%'", tableName, this.path);
 		SqlRowSet sqlRowSet = template.queryForRowSet(sql);
-		while (sqlRowSet.next()){
-			this.cachedContent.put(sqlRowSet.getString(1),sqlRowSet.getString(2));
+		while (sqlRowSet.next()) {
+			this.cachedContent.put(sqlRowSet.getString(1), sqlRowSet.getString(2));
 		}
 	}
 
 	@Override
 	public boolean exists() {
-		if(this.cachedContent.containsKey(this.path)){
+		if (this.cachedContent.containsKey(this.path)) {
 			return true;
 		}
 		String sql = String.format("select count(*) from %s where file_path = ?", tableName);
@@ -62,10 +63,17 @@ public class DatabaseResource extends KeyValueResource {
 	public boolean write(String content) {
 		String sql = String.format("update %s set file_content = ? where file_path = ?", tableName);
 		if (exists()) {
-			return template.update(sql, content, this.path) >= 0;
+			if (template.update(sql, content, this.path) > 0) {
+				this.cachedContent.put(this.path, content);
+				return true;
+			}
 		}
 		sql = String.format("insert into %s (file_path,file_content) values(?,?)", tableName);
-		return template.update(sql, this.path, content) > 0;
+		if (template.update(sql, this.path, content) > 0) {
+			this.cachedContent.put(this.path, content);
+			return true;
+		}
+		return false;
 	}
 
 	@Override
@@ -78,18 +86,26 @@ public class DatabaseResource extends KeyValueResource {
 	public boolean renameTo(Map<String, String> renameKeys) {
 		List<Object[]> args = renameKeys.entrySet().stream().map(entry -> new Object[]{entry.getValue(), entry.getKey()}).collect(Collectors.toList());
 		String sql = String.format("update %s set file_path = ? where file_path = ?", tableName);
-		return Arrays.stream(template.batchUpdate(sql, args)).sum() > 0;
+		if (Arrays.stream(template.batchUpdate(sql, args)).sum() > 0) {
+			renameKeys.forEach((oldKey, newKey) -> this.cachedContent.put(newKey, this.cachedContent.remove(oldKey)));
+			return true;
+		}
+		return false;
 	}
 
 	@Override
 	public boolean delete() {
 		String sql = String.format("delete from %s where file_path = ? or file_path like '%s%%'", tableName, isDirectory() ? this.path : this.path + separator);
-		return template.update(sql, this.path) > 0;
+		if (template.update(sql, this.path) > 0) {
+			this.cachedContent.remove(this.path);
+			return true;
+		}
+		return false;
 	}
 
 	@Override
 	public Function<String, Resource> mappedFunction() {
-		return it -> new DatabaseResource(template, tableName, separator, it, readonly, this.cachedContent,this);
+		return it -> new DatabaseResource(template, tableName, separator, it, readonly, this.cachedContent, this);
 	}
 
 	@Override

+ 11 - 4
src/main/java/org/ssssssss/magicapi/adapter/resource/RedisResource.java

@@ -33,11 +33,12 @@ public class RedisResource extends KeyValueResource {
 
 	@Override
 	public void readAll() {
+		this.cachedContent.clear();
 		List<String> keys = new ArrayList<>(keys());
 		List<String> values = redisTemplate.opsForValue().multiGet(keys);
-		if(values != null){
-			for (int i = 0,size = keys.size(); i < size; i++) {
-				this.cachedContent.put(keys.get(i),values.get(i));
+		if (values != null) {
+			for (int i = 0, size = keys.size(); i < size; i++) {
+				this.cachedContent.put(keys.get(i), values.get(i));
 			}
 		}
 	}
@@ -54,12 +55,14 @@ public class RedisResource extends KeyValueResource {
 	@Override
 	public boolean write(String content) {
 		this.redisTemplate.opsForValue().set(this.path, content);
+		this.cachedContent.put(this.path, content);
 		return true;
 	}
 
 	@Override
 	protected boolean renameTo(Map<String, String> renameKeys) {
 		renameKeys.forEach(this.redisTemplate::rename);
+		renameKeys.forEach((oldKey, newKey) -> this.cachedContent.put(newKey, this.cachedContent.remove(oldKey)));
 		return true;
 	}
 
@@ -74,7 +77,11 @@ public class RedisResource extends KeyValueResource {
 
 	@Override
 	protected boolean deleteByKey(String key) {
-		return Boolean.TRUE.equals(this.redisTemplate.delete(key));
+		if (Boolean.TRUE.equals(this.redisTemplate.delete(key))) {
+			this.cachedContent.remove(key);
+			return true;
+		}
+		return false;
 	}
 
 	@Override

+ 36 - 0
src/main/java/org/ssssssss/magicapi/config/MagicWebRequestInterceptor.java

@@ -0,0 +1,36 @@
+package org.ssssssss.magicapi.config;
+
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.HandlerInterceptor;
+import org.ssssssss.magicapi.controller.MagicController;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * /magic/web相关接口的拦截器
+ */
+public class MagicWebRequestInterceptor implements HandlerInterceptor {
+
+	private final MagicCorsFilter magicCorsFilter;
+
+	public MagicWebRequestInterceptor(MagicCorsFilter magicCorsFilter) {
+		this.magicCorsFilter = magicCorsFilter;
+	}
+
+	@Override
+	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
+		HandlerMethod handlerMethod;
+		if (handler instanceof HandlerMethod) {
+			handlerMethod = (HandlerMethod) handler;
+			handler = handlerMethod.getBean();
+			if (handler instanceof MagicController) {
+				if (magicCorsFilter != null) {
+					magicCorsFilter.process(request, response);
+				}
+				((MagicController) handler).doValid(request, handlerMethod.getMethodAnnotation(Valid.class));
+			}
+		}
+		return true;
+	}
+}

+ 21 - 0
src/main/java/org/ssssssss/magicapi/config/Valid.java

@@ -0,0 +1,21 @@
+package org.ssssssss.magicapi.config;
+
+import org.ssssssss.magicapi.interceptor.RequestInterceptor.Authorization;
+
+import java.lang.annotation.*;
+
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Valid {
+
+	/**
+	 * 验证是否有该权限
+	 */
+	Authorization authorization() default Authorization.NONE;
+
+	/**
+	 * 验证是否是只读模式
+	 */
+	boolean readonly() default true;
+}

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

@@ -1,19 +1,17 @@
 package org.ssssssss.magicapi.controller;
 
 import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 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.RequestInterceptor;
 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 javax.servlet.http.HttpServletRequest;
 import java.util.List;
 import java.util.Optional;
 
@@ -22,9 +20,7 @@ import java.util.Optional;
  */
 public class MagicAPIController extends MagicController {
 
-	private static Logger logger = LoggerFactory.getLogger(MagicAPIController.class);
-
-	private ApiServiceProvider magicApiService;
+	private final ApiServiceProvider magicApiService;
 
 	public MagicAPIController(MagicConfiguration configuration) {
 		super(configuration);
@@ -38,23 +34,13 @@ public class MagicAPIController extends MagicController {
 	 */
 	@RequestMapping("/delete")
 	@ResponseBody
-	public JsonBean<Boolean> delete(String id, HttpServletRequest request) {
-		if(configuration.getWorkspace().readonly()){
-			return new JsonBean<>(0, "当前为只读模式,无法删除");
-		}
-		if (!allowVisit(request, RequestInterceptor.Authorization.DELETE)) {
-			return new JsonBean<>(-10, "无权限执行删除方法");
-		}
-		try {
-			boolean success = magicApiService.delete(id);
-			if (success) {    //删除成功时在取消注册
-				configuration.getMappingHandlerMapping().unregisterMapping(id, true);
-			}
-			return new JsonBean<>(success);
-		} catch (Exception e) {
-			logger.error("删除接口出错", e);
-			return new JsonBean<>(-1, e.getMessage());
+	@Valid(readonly = false, authorization = RequestInterceptor.Authorization.DELETE)
+	public JsonBean<Boolean> delete(String id) {
+		boolean success = magicApiService.delete(id);
+		if (success) {    //删除成功时在取消注册
+			configuration.getMappingHandlerMapping().unregisterMapping(id, true);
 		}
+		return new JsonBean<>(success);
 	}
 
 	/**
@@ -63,12 +49,7 @@ public class MagicAPIController extends MagicController {
 	@RequestMapping("/list")
 	@ResponseBody
 	public JsonBean<List<ApiInfo>> list() {
-		try {
-			return new JsonBean<>(magicApiService.list());
-		} catch (Exception e) {
-			logger.error("查询接口列表失败", e);
-			return new JsonBean<>(-1, e.getMessage());
-		}
+		return new JsonBean<>(magicApiService.list());
 	}
 
 	/**
@@ -78,16 +59,9 @@ public class MagicAPIController extends MagicController {
 	 */
 	@RequestMapping("/get")
 	@ResponseBody
-	public JsonBean<ApiInfo> get(HttpServletRequest request, String id) {
-		if (!allowVisit(request, RequestInterceptor.Authorization.DETAIL)) {
-			return new JsonBean<>(-10, "无权限执行查看详情方法");
-		}
-		try {
-			return new JsonBean<>(magicApiService.get(id));
-		} catch (Exception e) {
-			logger.error("查询接口出错");
-			return new JsonBean<>(-1, e.getMessage());
-		}
+	@Valid(authorization = RequestInterceptor.Authorization.DELETE)
+	public JsonBean<ApiInfo> get(String id) {
+		return new JsonBean<>(magicApiService.get(id));
 	}
 
 	/**
@@ -118,29 +92,16 @@ public class MagicAPIController extends MagicController {
 	 */
 	@RequestMapping("/api/move")
 	@ResponseBody
-	public JsonBean<Boolean> apiMove(String id, String groupId, HttpServletRequest request) {
-		if(configuration.getWorkspace().readonly()){
-			return new JsonBean<>(0, "当前为只读模式,无法移动");
-		}
-		if (!allowVisit(request, RequestInterceptor.Authorization.SAVE)) {
-			return new JsonBean<>(-10, "无权限执行保存方法");
-		}
-		if (!configuration.getGroupServiceProvider().containsApiGroup(groupId)) {
-			return new JsonBean<>(0, "找不到分组信息");
-		}
-		try {
-			if (!magicApiService.allowMove(id, groupId)) {
-				return new JsonBean<>(0, "移动后名称会重复,请修改名称后在试。");
-			}
-			if (!configuration.getMappingHandlerMapping().move(id, groupId)) {
-				return new JsonBean<>(0, "该路径已被映射,请换一个请求方法或路径");
-			} else {
-				return new JsonBean<>(magicApiService.move(id, groupId));
-			}
-		} catch (Exception e) {
-			logger.error("移动接口出错", e);
-			return new JsonBean<>(-1, e.getMessage());
-		}
+	@Valid(readonly = false, authorization = RequestInterceptor.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));
 	}
 
 	/**
@@ -150,62 +111,36 @@ public class MagicAPIController extends MagicController {
 	 */
 	@RequestMapping("/save")
 	@ResponseBody
-	public JsonBean<String> save(HttpServletRequest request, @RequestBody ApiInfo info) {
-		if(configuration.getWorkspace().readonly()){
-			return new JsonBean<>(0, "当前为只读模式,无法保存");
-		}
-		if (!allowVisit(request, RequestInterceptor.Authorization.SAVE)) {
-			return new JsonBean<>(-10, "无权限执行保存方法");
-		}
-		try {
-			if (StringUtils.isBlank(info.getMethod())) {
-				return new JsonBean<>(0, "请求方法不能为空");
-			}
-			if (StringUtils.isBlank(info.getPath())) {
-				return new JsonBean<>(0, "请求路径不能为空");
-			}
-			if (StringUtils.isBlank(info.getName())) {
-				return new JsonBean<>(0, "接口名称不能为空");
-			}
-			if (!IoUtils.validateFileName(info.getName())) {
-				return new JsonBean<>(0, "接口名称不能包含特殊字符,只允许中文、数字、字母以及_组合");
-			}
-			if (StringUtils.isBlank(info.getScript())) {
-				return new JsonBean<>(0, "脚本内容不能为空");
-			}
-			if (configuration.getMappingHandlerMapping().hasRegisterMapping(info)) {
-				return new JsonBean<>(0, "该路径已被映射,请换一个请求方法或路径");
-			}
-			if (StringUtils.isBlank(info.getId())) {
-				// 先判断接口是否存在
-				if (magicApiService.exists(info.getName(), info.getGroupId(), info.getMethod(), info.getPath())) {
-					return new JsonBean<>(0, String.format("接口%s:%s已存在或接口名称重复", info.getMethod(), info.getPath()));
-				}
-				if (!magicApiService.insert(info)) {
-					return new JsonBean<>(0, "保存失败,请检查接口名称是否重复且不能包含特殊字符。");
-				}
-			} else {
-				// 先判断接口是否存在
-				if (magicApiService.existsWithoutId(info.getName(), info.getGroupId(), info.getMethod(), info.getPath(), info.getId())) {
-					return new JsonBean<>(0, String.format("接口%s:%s已存在或接口名称重复", 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)) {
-					if(!magicApiService.update(info)){
-						return new JsonBean<>(0, "保存失败,请检查接口名称是否重复且不能包含特殊字符。");
-					}
-					magicApiService.backup(info);
-				}
+	@Valid(readonly = false, authorization = RequestInterceptor.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());
-		} catch (Exception e) {
-			logger.error("保存接口出错", e);
-			return new JsonBean<>(-1, e.getMessage());
 		}
+		// 注册接口
+		configuration.getMappingHandlerMapping().registerMapping(info, true);
+		return new JsonBean<>(info.getId());
 	}
 
 }

+ 45 - 1
src/main/java/org/ssssssss/magicapi/controller/MagicController.java

@@ -1,14 +1,25 @@
 package org.ssssssss.magicapi.controller;
 
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseBody;
 import org.ssssssss.magicapi.config.MagicConfiguration;
+import org.ssssssss.magicapi.config.Valid;
+import org.ssssssss.magicapi.exception.InvalidArgumentException;
 import org.ssssssss.magicapi.interceptor.RequestInterceptor;
+import org.ssssssss.magicapi.model.JsonBean;
+import org.ssssssss.magicapi.model.JsonCode;
+import org.ssssssss.magicapi.model.JsonCodeConstants;
 import org.ssssssss.magicapi.utils.MD5Utils;
 
 import javax.servlet.http.HttpServletRequest;
 import java.util.Objects;
 
-public class MagicController {
+public class MagicController implements JsonCodeConstants {
 
+	private static final Logger logger = LoggerFactory.getLogger(MagicController.class);
 
 	public static final String HEADER_REQUEST_SESSION = "Magic-Request-Session";
 
@@ -26,6 +37,39 @@ public class MagicController {
 		this.configuration = configuration;
 	}
 
+	@ExceptionHandler(Exception.class)
+	public Object exceptionHandler(Exception e) {
+		logger.error("magic-api调用接口出错", e);
+		return new JsonBean<>(-1, e.getMessage());
+	}
+
+	@ExceptionHandler(InvalidArgumentException.class)
+	@ResponseBody
+	public Object exceptionHandler(InvalidArgumentException e) {
+		return new JsonBean<>(e.getCode(), e.getMessage());
+	}
+
+	public void doValid(HttpServletRequest request, Valid valid) {
+		if (valid != null) {
+			if (!valid.readonly() && configuration.getWorkspace().readonly()) {
+				throw new InvalidArgumentException(IS_READ_ONLY);
+			}
+			if (valid.authorization() != RequestInterceptor.Authorization.NONE && !allowVisit(request, valid.authorization())) {
+				throw new InvalidArgumentException(PERMISSION_INVALID);
+			}
+		}
+	}
+
+	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);
+	}
+
 	/**
 	 * 判断是否有权限访问按钮
 	 */

+ 35 - 103
src/main/java/org/ssssssss/magicapi/controller/MagicFunctionController.java

@@ -1,25 +1,21 @@
 package org.ssssssss.magicapi.controller;
 
 import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 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.RequestInterceptor;
 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 javax.servlet.http.HttpServletRequest;
 import java.util.List;
 
 public class MagicFunctionController extends MagicController {
 
-	private FunctionServiceProvider functionService;
-
-	private static final Logger logger = LoggerFactory.getLogger(MagicFunctionController.class);
+	private final FunctionServiceProvider functionService;
 
 	public MagicFunctionController(MagicConfiguration configuration) {
 		super(configuration);
@@ -29,26 +25,14 @@ public class MagicFunctionController extends MagicController {
 	@RequestMapping("/function/list")
 	@ResponseBody
 	public JsonBean<List<FunctionInfo>> list() {
-		try {
-			return new JsonBean<>(functionService.list());
-		} catch (Exception e) {
-			logger.error("查询函数列表失败", e);
-			return new JsonBean<>(-1, e.getMessage());
-		}
+		return new JsonBean<>(functionService.list());
 	}
 
 	@RequestMapping("/function/get")
 	@ResponseBody
-	public JsonBean<FunctionInfo> get(String id, HttpServletRequest request) {
-		if (!allowVisit(request, RequestInterceptor.Authorization.DETAIL)) {
-			return new JsonBean<>(-10, "无权限执行查看详情方法");
-		}
-		try {
-			return new JsonBean<>(functionService.get(id));
-		} catch (Exception e) {
-			logger.error("查询函数出错", e);
-			return new JsonBean<>(-1, e.getMessage());
-		}
+	@Valid(authorization = RequestInterceptor.Authorization.DETAIL)
+	public JsonBean<FunctionInfo> get(String id) {
+		return new JsonBean<>(functionService.get(id));
 	}
 
 	@RequestMapping("/function/backup/get")
@@ -65,96 +49,44 @@ public class MagicFunctionController extends MagicController {
 
 	@RequestMapping("/function/move")
 	@ResponseBody
-	public JsonBean<Boolean> move(String id, String groupId, HttpServletRequest request) {
-		if(configuration.getWorkspace().readonly()){
-			return new JsonBean<>(0, "当前为只读模式,无法移动");
-		}
-		if (!allowVisit(request, RequestInterceptor.Authorization.SAVE)) {
-			return new JsonBean<>(-10, "无权限执行移动函数");
-		}
-		try {
-			if (!functionService.allowMove(id, groupId)) {
-				return new JsonBean<>(0, "移动后名称会重复,请修改名称后在试。");
-			}
-			if (!configuration.getMagicFunctionManager().move(id, groupId)) {
-				return new JsonBean<>(0, "该路径已被映射,请换一个路径");
-			} else {
-				return new JsonBean<>(functionService.move(id, groupId));
-			}
-		} catch (Exception e) {
-			logger.error("移动函数出错", e);
-			return new JsonBean<>(-1, e.getMessage());
-		}
+	@Valid(readonly = false, authorization = RequestInterceptor.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));
 	}
 
 
 	@RequestMapping("/function/save")
 	@ResponseBody
-	public JsonBean<String> save(FunctionInfo functionInfo, HttpServletRequest request) {
-		if(configuration.getWorkspace().readonly()){
-			return new JsonBean<>(0, "当前为只读模式,无法保存");
-		}
-		if (!allowVisit(request, RequestInterceptor.Authorization.SAVE)) {
-			return new JsonBean<>(-10, "无权限执行保存方法");
-		}
-		if (StringUtils.isBlank(functionInfo.getName())) {
-			return new JsonBean<>(0, "函数名称不能为空");
-		}
-		if (!IoUtils.validateFileName(functionInfo.getName())) {
-			return new JsonBean<>(0, "函数名称不能包含特殊字符,只允许中文、数字、字母以及_组合");
-		}
-		if (StringUtils.isBlank(functionInfo.getPath())) {
-			return new JsonBean<>(0, "函数路径不能为空");
-		}
-		if (StringUtils.isBlank(functionInfo.getScript())) {
-			return new JsonBean<>(0, "脚本内容不能为空");
-		}
-		if (configuration.getMagicFunctionManager().hasRegister(functionInfo)) {
-			return new JsonBean<>(0, "该路径已被映射,请换一个路径");
-		}
-		try {
-			if (StringUtils.isBlank(functionInfo.getId())) {
-				if (functionService.exists(functionInfo.getName(), functionInfo.getPath(), functionInfo.getGroupId())) {
-					return new JsonBean<>(0, String.format("函数%s已存在或名称重复", functionInfo.getPath()));
-				}
-				if(!functionService.insert(functionInfo)){
-					return new JsonBean<>(0, "保存失败,请检查函数名称是否重复且不能包含特殊字符。");
-				}
-			} else {
-				if (functionService.existsWithoutId(functionInfo.getName(), functionInfo.getPath(), functionInfo.getGroupId(), functionInfo.getId())) {
-					return new JsonBean<>(0, String.format("函数%s已存在或名称重复", functionInfo.getPath()));
-				}
-				if(!functionService.update(functionInfo)){
-					return new JsonBean<>(0, "保存失败,请检查函数名称是否重复且不能包含特殊字符。");
-				}
-				functionService.backup(functionInfo);
-			}
-			configuration.getMagicFunctionManager().register(functionInfo);
-			return new JsonBean<>(functionInfo.getId());
-		} catch (Exception e) {
-			logger.error("保存函数出错", e);
-			return new JsonBean<>(-1, e.getMessage());
-		}
+	@Valid(readonly = false, authorization = RequestInterceptor.Authorization.SAVE)
+	public JsonBean<String> save(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());
 	}
 
 	@RequestMapping("/function/delete")
 	@ResponseBody
-	public JsonBean<Boolean> delete(String id, HttpServletRequest request) {
-		if(configuration.getWorkspace().readonly()){
-			return new JsonBean<>(0, "当前为只读模式,无法删除");
-		}
-		if (!allowVisit(request, RequestInterceptor.Authorization.DELETE)) {
-			return new JsonBean<>(-10, "无权限执行删除方法");
-		}
-		try {
-			boolean success = functionService.delete(id);
-			if (success) {
-				configuration.getMagicFunctionManager().unregister(id);
-			}
-			return new JsonBean<>(success);
-		} catch (Exception e) {
-			logger.error("删除函数出错", e);
-			return new JsonBean<>(-1, e.getMessage());
+	@Valid(readonly = false, authorization = RequestInterceptor.Authorization.DELETE)
+	public JsonBean<Boolean> delete(String id) {
+		boolean success = functionService.delete(id);
+		if (success) {
+			configuration.getMagicFunctionManager().unregister(id);
 		}
+		return new JsonBean<>(success);
 	}
 }

+ 62 - 121
src/main/java/org/ssssssss/magicapi/controller/MagicGroupController.java

@@ -1,11 +1,10 @@
 package org.ssssssss.magicapi.controller;
 
 import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 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.RequestInterceptor;
 import org.ssssssss.magicapi.model.Group;
 import org.ssssssss.magicapi.model.JsonBean;
@@ -13,16 +12,13 @@ import org.ssssssss.magicapi.model.TreeNode;
 import org.ssssssss.magicapi.provider.GroupServiceProvider;
 import org.ssssssss.magicapi.utils.IoUtils;
 
-import javax.servlet.http.HttpServletRequest;
 import java.util.List;
 import java.util.Objects;
 import java.util.stream.Collectors;
 
 public class MagicGroupController extends MagicController {
 
-	private static Logger logger = LoggerFactory.getLogger(MagicGroupController.class);
-
-	private GroupServiceProvider groupServiceProvider;
+	private final GroupServiceProvider groupServiceProvider;
 
 	public MagicGroupController(MagicConfiguration configuration) {
 		super(configuration);
@@ -34,49 +30,37 @@ public class MagicGroupController extends MagicController {
 	 */
 	@RequestMapping("/group/delete")
 	@ResponseBody
-	public JsonBean<Boolean> deleteGroup(String groupId, HttpServletRequest request) {
-		if(configuration.getWorkspace().readonly()){
-			return new JsonBean<>(0, "当前为只读模式,无法删除");
-		}
-		if (!allowVisit(request, RequestInterceptor.Authorization.DELETE)) {
-			return new JsonBean<>(-10, "无权限执行删除方法");
-		}
-		try {
-			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));
-				if (treeNode == null) {
-					return new JsonBean<>(0, "分组不存在!");
-				}
-				isApi = false;
+	@Valid(readonly = false, authorization = RequestInterceptor.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));
+			isTrue(treeNode != null, 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();
 			}
-			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();
-				}
+		} else {
+			// 删除函数
+			if (success = configuration.getFunctionServiceProvider().deleteGroup(groupId, children)) {
+				// 取消注册
+				configuration.getMagicFunctionManager().deleteGroup(children);
+				children.forEach(configuration.getGroupServiceProvider()::delete);
+				// 重新加载分组
+				configuration.getMagicFunctionManager().loadGroup();
 			}
-			return new JsonBean<>(success);
-		} catch (Exception e) {
-			logger.error("删除分组出错", e);
-			return new JsonBean<>(-1, e.getMessage());
 		}
+		return new JsonBean<>(success);
 	}
 
 	/**
@@ -84,48 +68,29 @@ public class MagicGroupController extends MagicController {
 	 */
 	@RequestMapping("/group/update")
 	@ResponseBody
-	public synchronized JsonBean<Boolean> groupUpdate(Group group, HttpServletRequest request) {
-		if(configuration.getWorkspace().readonly()){
-			return new JsonBean<>(0, "当前为只读模式,无法修改");
-		}
-		if (!allowVisit(request, RequestInterceptor.Authorization.SAVE)) {
-			return new JsonBean<>(-10, "无权限执行删除方法");
-		}
+	@Valid(readonly = false, authorization = RequestInterceptor.Authorization.SAVE)
+	public synchronized JsonBean<Boolean> groupUpdate(Group group) {
 		if (StringUtils.isBlank(group.getParentId())) {
 			group.setParentId("0");
 		}
-		if (StringUtils.isBlank(group.getName())) {
-			return new JsonBean<>(0, "分组名称不能为空");
-		}
-		if (!IoUtils.validateFileName(group.getName())) {
-			return new JsonBean<>(0, "分组名称不能包含特殊字符,只允许中文、数字、字母以及_组合");
-		}
-		if (StringUtils.isBlank(group.getType())) {
-			return new JsonBean<>(0, "分组类型不能为空");
-		}
-		try {
-			boolean isApiGroup = "1".equals(group.getType());
-			boolean isFunctionGroup = "2".equals(group.getType());
-			if (isApiGroup && configuration.getMappingHandlerMapping().checkGroup(group)) {
-				if (groupServiceProvider.update(group)) {    // 如果数据库修改成功,则修改接口路径
-					configuration.getMappingHandlerMapping().updateGroup(group);
-				}else{
-					return new JsonBean<>(0, "修改分组失败,同一组下分组名称不能重复且不能包含特殊字符。");
-				}
-				return new JsonBean<>(true);
-			} else if (isFunctionGroup && configuration.getMagicFunctionManager().checkGroup(group)) {
-				if (groupServiceProvider.update(group)) {    // 如果数据库修改成功,则修改接口路径
-					configuration.getMagicFunctionManager().updateGroup(group);
-				}else{
-					return new JsonBean<>(0, "修改分组失败,同一组下分组名称不能重复且不能包含特殊字符。");
-				}
-				return new JsonBean<>(true);
-			}
-			return new JsonBean<>(-20, "修改分组后,名称或路径会有冲突,请检查!");
-		} catch (Exception e) {
-			logger.error("修改分组出错", e);
-			return new JsonBean<>(-1, e.getMessage());
-		}
+		notBlank(group.getName(), GROUP_NAME_REQUIRED);
+		isTrue(IoUtils.validateFileName(group.getName()), NAME_INVALID);
+
+		notBlank(group.getType(), GROUP_TYPE_REQUIRED);
+		boolean isApiGroup = "1".equals(group.getType());
+		boolean isFunctionGroup = "2".equals(group.getType());
+		if (isApiGroup && configuration.getMappingHandlerMapping().checkGroup(group)) {
+			isTrue(groupServiceProvider.update(group), GROUP_SAVE_FAILURE);
+			// 如果数据库修改成功,则修改接口路径
+			configuration.getMappingHandlerMapping().updateGroup(group);
+			return new JsonBean<>(true);
+		} else if (isFunctionGroup && configuration.getMagicFunctionManager().checkGroup(group)) {
+			isTrue(groupServiceProvider.update(group), GROUP_SAVE_FAILURE);
+			// 如果数据库修改成功,则修改接口路径
+			configuration.getMagicFunctionManager().updateGroup(group);
+			return new JsonBean<>(true);
+		}
+		return new JsonBean<>(GROUP_CONFLICT);
 	}
 
 	/**
@@ -134,12 +99,7 @@ public class MagicGroupController extends MagicController {
 	@RequestMapping("/group/list")
 	@ResponseBody
 	public JsonBean<List<Group>> groupList(String type) {
-		try {
-			return new JsonBean<>(groupServiceProvider.groupList(type));
-		} catch (Exception e) {
-			logger.error("查询分组列表失败", e);
-			return new JsonBean<>(-1, e.getMessage());
-		}
+		return new JsonBean<>(groupServiceProvider.groupList(type));
 	}
 
 	/**
@@ -147,39 +107,20 @@ public class MagicGroupController extends MagicController {
 	 */
 	@RequestMapping("/group/create")
 	@ResponseBody
-	public JsonBean<String> createGroup(Group group, HttpServletRequest request) {
-		if(configuration.getWorkspace().readonly()){
-			return new JsonBean<>(0, "当前为只读模式,无法创建");
-		}
-		if (!allowVisit(request, RequestInterceptor.Authorization.SAVE)) {
-			return new JsonBean<>(-10, "无权限执行保存方法");
-		}
+	@Valid(readonly = false, authorization = RequestInterceptor.Authorization.SAVE)
+	public JsonBean<String> createGroup(Group group) {
 		if (StringUtils.isBlank(group.getParentId())) {
 			group.setParentId("0");
 		}
-		if (StringUtils.isBlank(group.getName())) {
-			return new JsonBean<>(0, "分组名称不能为空");
-		}
-		if (!IoUtils.validateFileName(group.getName())) {
-			return new JsonBean<>(0, "分组名称不能包含特殊字符,只允许中文、数字、字母以及_组合");
-		}
-		if (StringUtils.isBlank(group.getType())) {
-			return new JsonBean<>(0, "分组类型不能为空");
-		}
-		try {
-			if(groupServiceProvider.insert(group)){
-				if (Objects.equals(group.getType(), "1")) {
-					configuration.getMappingHandlerMapping().loadGroup();
-				} else {
-					configuration.getMagicFunctionManager().loadGroup();
-				}
-				return new JsonBean<>(group.getId());
-			}else {
-				return new JsonBean<>(-1,"保存分组失败,同一组下分组名称不能重复且不能包含特殊字符。");
-			}
-		} catch (Exception e) {
-			logger.error("保存分组出错", e);
-			return new JsonBean<>(-1, e.getMessage());
+		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(), "1")) {
+			configuration.getMappingHandlerMapping().loadGroup();
+		} else {
+			configuration.getMagicFunctionManager().loadGroup();
 		}
+		return new JsonBean<>(group.getId());
 	}
 }

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

@@ -25,7 +25,7 @@ import java.util.stream.Stream;
 
 public class MagicWorkbenchController extends MagicController {
 
-	private static Logger logger = LoggerFactory.getLogger(MagicWorkbenchController.class);
+	private static final Logger logger = LoggerFactory.getLogger(MagicWorkbenchController.class);
 
 	public MagicWorkbenchController(MagicConfiguration configuration) {
 		super(configuration);
@@ -38,7 +38,7 @@ public class MagicWorkbenchController extends MagicController {
 	@ResponseBody
 	public JsonBean<Boolean> login(String username, String password, HttpServletRequest request, HttpServletResponse response) {
 		if (username != null && password != null && Objects.equals(username, configuration.getUsername()) && Objects.equals(password, configuration.getPassword())) {
-			response.setHeader(configuration.getTokenKey(),MD5Utils.encrypt(String.format("%s||%s", username, password)));
+			response.setHeader(configuration.getTokenKey(), MD5Utils.encrypt(String.format("%s||%s", username, password)));
 			response.setHeader(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, configuration.getTokenKey());
 			return new JsonBean<>(true);
 		} else if (allowVisit(request, null)) {

+ 12 - 8
src/main/java/org/ssssssss/magicapi/controller/RequestHandler.java

@@ -70,29 +70,29 @@ public class RequestHandler extends MagicController {
 			response.setHeader(HEADER_RESPONSE_WITH_MAGIC_API, CONST_STRING_TRUE);
 			response.setHeader(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, HEADER_RESPONSE_WITH_MAGIC_API);
 			if (!allowVisit(request, RequestInterceptor.Authorization.RUN)) {
-				return new JsonBean<>(-10, "无权限执行测试方法");
+				return new JsonBean<>(PERMISSION_INVALID);
 			}
 		}
 		if (requestEntity.getApiInfo() == null) {
-			logger.error("接口不存在");
-			return resultProvider.buildResult(requestEntity, 1001, "fail", "接口不存在");
+			logger.error("{}找不到对应接口", request.getRequestURI());
+			return buildResult(requestEntity, API_NOT_FOUND, "接口不存在");
 		}
 		// 验证
 		Object value = doValidate(requestEntity, "参数", requestEntity.getApiInfo().getParameters(), parameters);
 		if (value != null) {
-			return requestEntity.isRequestedFromTest() ? new JsonBean<>(0, "参数验证失败", value) : value;
+			return requestEntity.isRequestedFromTest() ? new JsonBean<>(PARAMETER_INVALID, value) : value;
 		}
 		Map<String, Object> headers = new HashMap<String, Object>() {
 			@Override
 			public Object get(Object key) {
-				return request.getHeader(key.toString());
+				return getOrDefault(key, request.getHeader(key.toString()));
 			}
 		};
 		requestEntity.setHeaders(headers);
 		// 验证 header
 		value = doValidate(requestEntity, "header", requestEntity.getApiInfo().getHeaders(), headers);
 		if (value != null) {
-			return requestEntity.isRequestedFromTest() ? new JsonBean<>(0, "header验证失败", value) : value;
+			return requestEntity.isRequestedFromTest() ? new JsonBean<>(HEADER_INVALID, value) : value;
 		}
 		MagicScriptContext context = createMagicScriptContext(requestEntity);
 		requestEntity.setMagicScriptContext(context);
@@ -110,6 +110,10 @@ public class RequestHandler extends MagicController {
 		return invokeRequest(requestEntity);
 	}
 
+	private Object buildResult(RequestEntity requestEntity, JsonCode code, Object data) {
+		return resultProvider.buildResult(requestEntity, code.getCode(), code.getMessage(), data);
+	}
+
 	private <T extends BaseDefinition> Object doValidate(RequestEntity requestEntity, String comment, List<T> validateParameters, Map<String, Object> parameters) {
 		for (BaseDefinition parameter : validateParameters) {
 			String requestValue = StringUtils.defaultIfBlank(Objects.toString(parameters.get(parameter.getName())), Objects.toString(parameter.getDefaultValue(), EMPTY));
@@ -184,12 +188,12 @@ public class RequestHandler extends MagicController {
 		String sessionId = getRequestedSessionId(request);
 		MagicScriptDebugContext context = MagicScriptDebugContext.getDebugContext(sessionId);
 		if (context == null) {
-			return new JsonBean<>(0, "debug session not found!", resultProvider.buildResult(requestEntity, 0, "debug session not found!"));
+			return new JsonBean<>(DEBUG_SESSION_NOT_FOUND, buildResult(requestEntity, DEBUG_SESSION_NOT_FOUND, null));
 		}
 		// 重置断点
 		context.setBreakpoints(getRequestedBreakpoints(request));
 		// 步进
-		context.setStepInto("true".equalsIgnoreCase(request.getHeader(HEADER_REQUEST_STEP_INTO)));
+		context.setStepInto(CONST_STRING_TRUE.equalsIgnoreCase(request.getHeader(HEADER_REQUEST_STEP_INTO)));
 		try {
 			context.singal();    //等待语句执行到断点或执行完毕
 		} catch (InterruptedException e) {

+ 17 - 0
src/main/java/org/ssssssss/magicapi/exception/InvalidArgumentException.java

@@ -0,0 +1,17 @@
+package org.ssssssss.magicapi.exception;
+
+import org.ssssssss.magicapi.model.JsonCode;
+
+public class InvalidArgumentException extends RuntimeException {
+
+	private final JsonCode jsonCode;
+
+	public InvalidArgumentException(JsonCode jsonCode) {
+		super(jsonCode.getMessage());
+		this.jsonCode = jsonCode;
+	}
+
+	public int getCode() {
+		return jsonCode.getCode();
+	}
+}

+ 1 - 1
src/main/java/org/ssssssss/magicapi/interceptor/RequestInterceptor.java

@@ -13,7 +13,7 @@ import javax.servlet.http.HttpServletResponse;
 public interface RequestInterceptor {
 
 	enum Authorization {
-		SAVE, DETAIL, RUN, DELETE
+		NONE, SAVE, DETAIL, RUN, DELETE
 	}
 
 	/**

+ 6 - 0
src/main/java/org/ssssssss/magicapi/interceptor/SQLInterceptor.java

@@ -2,8 +2,14 @@ package org.ssssssss.magicapi.interceptor;
 
 import org.ssssssss.magicapi.modules.BoundSql;
 
+/**
+ * SQL 拦截器
+ */
 public interface SQLInterceptor {
 
+	/**
+	 * 执行SQL之前
+	 */
 	void preHandle(BoundSql boundSql);
 
 }

+ 8 - 0
src/main/java/org/ssssssss/magicapi/model/JsonBean.java

@@ -46,6 +46,14 @@ public class JsonBean<T> {
     public JsonBean() {
     }
 
+    public JsonBean(JsonCode jsonCode) {
+        this(jsonCode, null);
+    }
+
+    public JsonBean(JsonCode jsonCode, T data) {
+        this(jsonCode.getCode(), jsonCode.getMessage(), data);
+    }
+
     public JsonBean(T data) {
         this.data = data;
     }

+ 33 - 0
src/main/java/org/ssssssss/magicapi/model/JsonCode.java

@@ -0,0 +1,33 @@
+package org.ssssssss.magicapi.model;
+
+public class JsonCode {
+
+	private int code;
+
+	private String message;
+
+	public JsonCode(int code, String message) {
+		this.code = code;
+		this.message = message;
+	}
+
+	public int getCode() {
+		return code;
+	}
+
+	public void setCode(int code) {
+		this.code = code;
+	}
+
+	public String getMessage() {
+		return message;
+	}
+
+	public void setMessage(String message) {
+		this.message = message;
+	}
+
+	public JsonCode format(Object... args) {
+		return new JsonCode(this.code, String.format(this.message, args));
+	}
+}

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

@@ -0,0 +1,56 @@
+package org.ssssssss.magicapi.model;
+
+public interface JsonCodeConstants {
+
+	JsonCode SUCCESS = new JsonCode(1, "success");
+
+	JsonCode IS_READ_ONLY = new JsonCode(-2, "当前为只读模式,无法操作");
+
+	JsonCode PERMISSION_INVALID = new JsonCode(-10, "无权限操作.");
+
+	JsonCode GROUP_NOT_FOUND = new JsonCode(0, "找不到分组信息");
+
+	JsonCode NAME_CONFLICT = new JsonCode(0, "移动后名称会重复,请修改名称后在试。");
+
+	JsonCode REQUEST_PATH_CONFLICT = new JsonCode(0, "该路径已被映射,请换一个请求方法或路径");
+
+	JsonCode FUNCTION_PATH_CONFLICT = new JsonCode(0, "该路径已被映射,请换一个请求方法或路径");
+
+	JsonCode REQUEST_METHOD_REQUIRED = new JsonCode(0, "请求方法不能为空");
+
+	JsonCode REQUEST_PATH_REQUIRED = new JsonCode(0, "请求路径不能为空");
+
+	JsonCode FUNCTION_PATH_REQUIRED = new JsonCode(0, "函数路径不能为空");
+
+	JsonCode SCRIPT_REQUIRED = new JsonCode(0, "脚本内容不能为空");
+
+	JsonCode API_NAME_REQUIRED = new JsonCode(0, "接口名称不能为空");
+
+	JsonCode GROUP_NAME_REQUIRED = new JsonCode(0, "分组名称不能为空");
+
+	JsonCode GROUP_TYPE_REQUIRED = new JsonCode(0, "分组类型不能为空");
+
+	JsonCode FUNCTION_NAME_REQUIRED = new JsonCode(0, "函数名称不能为空");
+
+	JsonCode NAME_INVALID = new JsonCode(0, "名称不能包含特殊字符,只允许中文、数字、字母以及_组合");
+
+	JsonCode API_ALREADY_EXISTS = new JsonCode(0, "接口%s:%s已存在或接口名称重复");
+
+	JsonCode FUNCTION_ALREADY_EXISTS = new JsonCode(0, "函数%s已存在或名称重复");
+
+	JsonCode API_SAVE_FAILURE = new JsonCode(0, "保存失败,请检查接口名称是否重复且不能包含特殊字符。");
+
+	JsonCode FUNCTION_SAVE_FAILURE = new JsonCode(0, "保存失败,请检查函数名称是否重复且不能包含特殊字符。");
+
+	JsonCode GROUP_SAVE_FAILURE = new JsonCode(0, "保存失败,同一组下分组名称不能重复且不能包含特殊字符。");
+
+	JsonCode GROUP_CONFLICT = new JsonCode(-20, "修改分组后,名称或路径会有冲突,请检查!");
+
+	JsonCode PARAMETER_INVALID = new JsonCode(0, "参数验证失败");
+
+	JsonCode HEADER_INVALID = new JsonCode(0, "header验证失败");
+
+	JsonCode DEBUG_SESSION_NOT_FOUND = new JsonCode(0, "debug session not found!");
+
+	JsonCode API_NOT_FOUND = new JsonCode(1001, "api not found");
+}

+ 4 - 15
src/main/java/org/ssssssss/magicapi/provider/ApiServiceProvider.java

@@ -16,29 +16,18 @@ public abstract class ApiServiceProvider extends StoreServiceProvider<ApiInfo> {
 
 	/**
 	 * 判断接口是否存在
-	 *
-	 * @param name 接口名称
-	 * @param groupId 分组Id
-	 * @param method  请求方法
-	 * @param path    请求路径
 	 */
-	public boolean exists(String name, String groupId, String method, String path) {
+	public boolean exists(ApiInfo info) {
 		return infos.values().stream()
-				.anyMatch(it -> groupId.equals(it.getGroupId()) && (name.equals(it.getName()) || (method.equals(it.getMethod()) && path.equals(it.getPath()))));
+				.anyMatch(it -> info.getGroupId().equals(it.getGroupId()) && (info.getName().equals(it.getName()) || (info.getMethod().equals(it.getMethod()) && info.getPath().equals(it.getPath()))));
 	}
 
 	/**
 	 * 判断接口是否存在
-	 *
-	 * @param name 接口名称
-	 * @param groupId 分组ID
-	 * @param method  请求方法
-	 * @param path    请求路径
-	 * @param id      排除接口
 	 */
-	public boolean existsWithoutId(String name, String groupId, String method, String path, String id) {
+	public boolean existsWithoutId(ApiInfo info) {
 		return infos.values().stream()
-				.anyMatch(it -> !id.equals(it.getId()) && groupId.equals(it.getGroupId()) && (name.equals(it.getName()) || (method.equals(it.getMethod()) && path.equals(it.getPath()))));
+				.anyMatch(it -> !info.getId().equals(it.getId()) && info.getGroupId().equals(it.getGroupId()) && (info.getName().equals(it.getName()) || (info.getMethod().equals(it.getMethod()) && info.getPath().equals(it.getPath()))));
 	}
 
 	@Override

+ 4 - 4
src/main/java/org/ssssssss/magicapi/provider/FunctionServiceProvider.java

@@ -9,14 +9,14 @@ public abstract class FunctionServiceProvider extends StoreServiceProvider<Funct
 		super(FunctionInfo.class, workspace, groupServiceProvider);
 	}
 
-	public boolean exists(String name, String path, String groupId){
+	public boolean exists(FunctionInfo info) {
 		return infos.values().stream()
-				.anyMatch(it -> groupId.equals(it.getGroupId()) && (name.equals(it.getName()) || path.equals(it.getPath())));
+				.anyMatch(it -> info.getGroupId().equals(it.getGroupId()) && (info.getName().equals(it.getName()) || info.getPath().equals(it.getPath())));
 	}
 
-	public boolean existsWithoutId(String name, String path, String groupId, String id){
+	public boolean existsWithoutId(FunctionInfo info) {
 		return infos.values().stream()
-				.anyMatch(it -> !id.equals(it.getId()) && groupId.equals(it.getGroupId()) && (name.equals(it.getName()) || path.equals(it.getPath())));
+				.anyMatch(it -> !info.getId().equals(it.getId()) && info.getGroupId().equals(it.getGroupId()) && (info.getName().equals(it.getName()) || info.getPath().equals(it.getPath())));
 	}
 
 	@Override

+ 0 - 1
src/main/java/org/ssssssss/magicapi/provider/StoreServiceProvider.java

@@ -30,7 +30,6 @@ public abstract class StoreServiceProvider<T extends MagicEntity> {
 	public StoreServiceProvider(Class<T> clazz, Resource workspace, GroupServiceProvider groupServiceProvider) {
 		this.clazz = clazz;
 		this.workspace = workspace;
-		this.workspace.readAll();
 		this.groupServiceProvider = groupServiceProvider;
 		if(!this.workspace.exists()){
 			this.workspace.mkdir();

+ 3 - 3
src/main/java/org/ssssssss/magicapi/provider/impl/DefaultGroupServiceProvider.java

@@ -20,18 +20,17 @@ public class DefaultGroupServiceProvider implements GroupServiceProvider {
 
 	private final Resource workspace;
 
-	private String metabase = "group.json";
+	private final String metabase = "group.json";
 
 	public DefaultGroupServiceProvider(Resource workspace) {
 		this.workspace = workspace;
-		this.workspace.readAll();
 	}
 
 	@Override
 	public boolean insert(Group group) {
 		group.setId(UUID.randomUUID().toString().replace("-", ""));
 		Resource directory = this.getGroupResource(group.getParentId());
-		directory = directory == null ? this.getGroupResource(group.getType(),group.getName()) : directory.getDirectory(group.getName());
+		directory = directory == null ? this.getGroupResource(group.getType(), group.getName()) : directory.getDirectory(group.getName());
 		if (!directory.exists() && directory.mkdir()) {
 			Resource resource = directory.getResource(metabase);
 			if (resource.write(JsonUtils.toJsonString(group))) {
@@ -99,6 +98,7 @@ public class DefaultGroupServiceProvider implements GroupServiceProvider {
 	@Override
 	public List<Group> groupList(String type) {
 		Resource resource = this.workspace.getDirectory("1".equals(type) ? "api" : "function");
+		resource.readAll();
 		return resource.dirs().stream().map(it -> it.getResource(metabase)).filter(Resource::exists)
 				.map(it -> {
 					Group group = JsonUtils.readValue(it.read(), Group.class);