Browse Source

请求处理

mxd 5 years ago
parent
commit
8dc7af6a9a

+ 66 - 0
src/main/java/org/ssssssss/magicapi/config/MagicApiService.java

@@ -0,0 +1,66 @@
+package org.ssssssss.magicapi.config;
+
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.RowMapper;
+
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+public class MagicApiService {
+
+	private final String deleteById = "delete from magic_api_info where id = ?";
+	private final String selectList = "select id,api_name name,api_path path,api_method method from magic_api_info order by api_update_time desc";
+	private final String selectListWithScript = "select id,api_name name,api_path path,api_method method,api_script script from magic_api_info";
+	private final String selectOne = "select api_method method,api_script script,api_path path,api_name name from magic_api_info where id = ?";
+	private final String exists = "select count(*) from magic_api_info where api_method = ? and api_path = ?";
+	private final String existsWithoutId = "select count(*) from magic_api_info where api_method = ? and api_path = ? and id !=?";
+	private final String insert = "insert into magic_api_info(id,api_method,api_path,api_script,api_name,api_create_time,api_update_time) values(?,?,?,?,?,?,?)";
+	private final String update = "update magic_api_info set api_method = ?,api_path = ?,api_script = ?,api_name = ?,api_update_time = ? where id = ?";
+	private RowMapper<ApiInfo> rowMapper = new BeanPropertyRowMapper<>(ApiInfo.class);
+	private JdbcTemplate template;
+
+	public MagicApiService(JdbcTemplate template) {
+		this.template = template;
+	}
+
+	protected boolean delete(String id) {
+		Map<String, Object> info = template.queryForMap("select * from magic_api_info where id = ?", id);
+		if (info != null) {
+			return template.update(deleteById, id) > 0;
+		}
+		return false;
+	}
+
+	protected List<ApiInfo> list() {
+		return template.query(selectList, rowMapper);
+	}
+
+	protected List<ApiInfo> listWithScript() {
+		return template.query(selectListWithScript, rowMapper);
+	}
+
+	protected ApiInfo get(String id) {
+		return template.queryForObject(selectOne, rowMapper, id);
+	}
+
+	protected boolean exists(String method, String path) {
+		return template.queryForObject(exists, Integer.class, method, path) > 0;
+	}
+
+	protected boolean existsWithoutId(String method, String path, String id) {
+		return template.queryForObject(existsWithoutId, Integer.class, method, path, id) > 0;
+	}
+
+	protected boolean insert(ApiInfo info) {
+		info.setId(UUID.randomUUID().toString().replace("-", ""));
+		long time = System.currentTimeMillis();
+		return template.update(insert, info.getId(), info.getMethod(), info.getPath(), info.getScript(), info.getName(), time, time) > 0;
+	}
+
+	protected boolean update(ApiInfo info) {
+		long time = System.currentTimeMillis();
+		return template.update(update, info.getMethod(), info.getPath(), info.getScript(), info.getName(), System.currentTimeMillis(), info.getId()) > 0;
+	}
+}

+ 110 - 0
src/main/java/org/ssssssss/magicapi/config/MappingHandlerMapping.java

@@ -0,0 +1,110 @@
+package org.ssssssss.magicapi.config;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.context.request.NativeWebRequest;
+import org.springframework.web.context.request.RequestAttributes;
+import org.springframework.web.context.request.ServletWebRequest;
+import org.springframework.web.servlet.HandlerMapping;
+import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
+import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class MappingHandlerMapping {
+
+	private static Map<String, ApiInfo> mappings = new ConcurrentHashMap<>();
+	private static Logger logger = LoggerFactory.getLogger(MappingHandlerMapping.class);
+	private RequestMappingHandlerMapping requestMappingHandlerMapping;
+	private RequestHandler handler;
+	private Method method = RequestHandler.class.getDeclaredMethod("invoke", HttpServletRequest.class, HttpServletResponse.class, Map.class, Map.class, Map.class);
+	private MagicApiService magicApiService;
+
+	public MappingHandlerMapping() throws NoSuchMethodException {
+	}
+
+	public static ApiInfo getMappingApiInfo(HttpServletRequest request) {
+		NativeWebRequest webRequest = new ServletWebRequest(request);
+		String requestMapping = (String) webRequest.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST);
+		return getMappingApiInfo(buildMappingKey(request.getMethod(), requestMapping));
+	}
+
+	public static ApiInfo getMappingApiInfo(String key) {
+		return mappings.get(key);
+	}
+
+	public static String buildMappingKey(String requestMethod, String requestMapping) {
+		return requestMethod.toUpperCase() + ":" + requestMapping;
+	}
+
+	public void setRequestMappingHandlerMapping(RequestMappingHandlerMapping requestMappingHandlerMapping) {
+		this.requestMappingHandlerMapping = requestMappingHandlerMapping;
+	}
+
+	public void setHandler(RequestHandler handler) {
+		this.handler = handler;
+	}
+
+	public void setMagicApiService(MagicApiService magicApiService) {
+		this.magicApiService = magicApiService;
+	}
+
+	public void registerAllMapping() {
+		List<ApiInfo> list = magicApiService.listWithScript();
+		if (list != null) {
+			for (ApiInfo info : list) {
+				registerMapping(info);
+			}
+		}
+	}
+
+	/**
+	 * 注册请求映射
+	 *
+	 * @param info
+	 */
+	public void registerMapping(ApiInfo info) {
+		if (mappings.containsKey(info.getId())) {
+			ApiInfo oldInfo = mappings.get(info.getId());
+			logger.info("取消注册接口:{}", oldInfo.getName());
+			// 取消注册
+			mappings.remove(getMappingKey(info));
+			requestMappingHandlerMapping.unregisterMapping(getRequestMapping(oldInfo));
+		}
+		logger.info("注册接口:{}", info.getName());
+		// 注册
+		RequestMappingInfo requestMapping = getRequestMapping(info);
+		mappings.put(info.getId(), info);
+		mappings.put(getMappingKey(info), info);
+		requestMappingHandlerMapping.registerMapping(requestMapping, handler, method);
+	}
+
+	/**
+	 * 取消注册请求映射
+	 *
+	 * @param id
+	 */
+	public void unregisterMapping(String id) {
+		ApiInfo info = mappings.remove(id);
+		if (info != null) {
+			logger.info("取消注册接口:{}", info.getName());
+			mappings.remove(getMappingKey(info));
+			requestMappingHandlerMapping.unregisterMapping(getRequestMapping(info));
+		}
+	}
+
+	private String getMappingKey(ApiInfo info) {
+		return buildMappingKey(info.getMethod(), info.getPath());
+	}
+
+	private RequestMappingInfo getRequestMapping(ApiInfo info) {
+		return RequestMappingInfo.paths(info.getPath()).methods(RequestMethod.valueOf(info.getMethod().toUpperCase())).build();
+	}
+
+}

+ 0 - 68
src/main/java/org/ssssssss/magicapi/config/RequestExecutor.java

@@ -1,68 +0,0 @@
-package org.ssssssss.magicapi.config;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.ResponseBody;
-import org.ssssssss.magicapi.context.RequestContext;
-import org.ssssssss.magicapi.model.JsonBean;
-
-import javax.servlet.http.HttpServletRequest;
-import java.util.ArrayList;
-import java.util.List;
-
-public class RequestExecutor {
-
-    private static Logger logger = LoggerFactory.getLogger(RequestExecutor.class);
-
-    private List<RequestInterceptor> requestInterceptors = new ArrayList<>();
-
-    public void addRequestInterceptor(RequestInterceptor requestInterceptor){
-        this.requestInterceptors.add(requestInterceptor);
-    }
-
-    /**
-     * http请求入口
-     *
-     * @param request
-     * @return
-     */
-    @ResponseBody
-    public Object invoke(HttpServletRequest request) {
-        return invoke(request, null);
-    }
-
-    /**
-     * http请求入口(带RequestBody)
-     */
-    @ResponseBody
-    public Object invoke(HttpServletRequest request, @RequestBody(required = false) Object requestBody) {
-        try {
-            // 创建RequestContex对象,供后续使用
-            RequestContext requestContext = new RequestContext(request);
-            if (!requestContext.containsKey("body")) {
-                requestContext.setRequestBody(requestBody);
-            }
-            // 执行前置拦截器
-            for (RequestInterceptor requestInterceptor : requestInterceptors) {
-                Object value = requestInterceptor.preHandle(requestContext);
-                if (value != null) {
-                    return value;
-                }
-            }
-            Object value = null;
-            // 执行后置拦截器
-            for (RequestInterceptor requestInterceptor : requestInterceptors) {
-                Object target = requestInterceptor.postHandle(requestContext, value);
-                if (target != null) {
-                    return target;
-                }
-            }
-            return value;
-        } catch (Exception e) {
-            logger.error("系统出现错误", e);
-            return new JsonBean<>(-1, e.getMessage());
-        }
-    }
-
-}

+ 86 - 0
src/main/java/org/ssssssss/magicapi/config/RequestHandler.java

@@ -0,0 +1,86 @@
+package org.ssssssss.magicapi.config;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.ssssssss.magicapi.model.JsonBean;
+import org.ssssssss.script.MagicScriptContext;
+import org.ssssssss.script.MagicScriptEngine;
+import org.ssssssss.script.MagicScriptError;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class RequestHandler {
+
+	private static Logger logger = LoggerFactory.getLogger(RequestHandler.class);
+
+	private List<RequestInterceptor> requestInterceptors = new ArrayList<>();
+
+	public void addRequestInterceptor(RequestInterceptor requestInterceptor) {
+		requestInterceptors.add(requestInterceptor);
+	}
+
+	@ResponseBody
+	public Object invoke(HttpServletRequest request, HttpServletResponse response,
+						 @PathVariable(required = false) Map<String, Object> pathVariables,
+						 @RequestParam(required = false) Map<String, Object> parameters,
+						 @RequestBody(required = false) Map<String, Object> requestBody) {
+		ApiInfo info;
+		try {
+			info = MappingHandlerMapping.getMappingApiInfo(request);
+			MagicScriptContext context = new MagicScriptContext();
+			putMapIntoContext(parameters, context);
+			putMapIntoContext(pathVariables, context);
+			if (requestBody != null) {
+				context.set("body", requestBody);
+			}
+			// 执行前置拦截器
+			for (RequestInterceptor requestInterceptor : requestInterceptors) {
+				Object value = requestInterceptor.preHandle(info, context);
+				if (value != null) {
+					return value;
+				}
+			}
+			Object value = MagicScriptEngine.execute(info.getScript(), context);
+			// 执行后置拦截器
+			for (RequestInterceptor requestInterceptor : requestInterceptors) {
+				Object target = requestInterceptor.postHandle(info, context, value);
+				if (target != null) {
+					return target;
+				}
+			}
+			return new JsonBean<>(value);
+		} catch (Throwable root) {
+			MagicScriptError.ScriptException se = null;
+			Throwable parent = root;
+			do {
+				if (parent instanceof MagicScriptError.ScriptException) {
+					se = (MagicScriptError.ScriptException) parent;
+				}
+			} while ((parent = parent.getCause()) != null);
+			logger.error("执行接口出错", root);
+			if (se != null) {
+				return new JsonBean<>(-1, se.getSimpleMessage());
+			}
+			return new JsonBean<>(-1, root.getMessage());
+		}
+
+	}
+
+	private void putMapIntoContext(Map<String, Object> map, MagicScriptContext context) {
+		if (map != null && !map.isEmpty()) {
+			Set<Map.Entry<String, Object>> entries = map.entrySet();
+			for (Map.Entry<String, Object> entry : entries) {
+				context.set(entry.getKey(), entry.getValue());
+			}
+		}
+	}
+}

+ 5 - 4
src/main/java/org/ssssssss/magicapi/config/RequestInterceptor.java

@@ -1,6 +1,6 @@
 package org.ssssssss.magicapi.config;
 
-import org.ssssssss.magicapi.context.RequestContext;
+import org.ssssssss.script.MagicScriptContext;
 
 /**
  * 请求拦截器
@@ -13,18 +13,19 @@ public interface RequestInterceptor {
      * @return 当返回对象时,直接将此对象返回到页面,返回null时,继续执行后续操作
      * @throws Exception
      */
-    default Object preHandle(RequestContext context) throws Exception {
+    default Object preHandle(ApiInfo info, MagicScriptContext context) throws Exception {
         return null;
     }
 
 
     /**
      * 执行完毕之后执行
+     *
      * @param value 即将要返回到页面的值
-     * @return 返回到页面的对象,当返回null时执行后续拦截器,否则直接返回该值,不执行后续拦截器
+     * @return 返回到页面的对象, 当返回null时执行后续拦截器,否则直接返回该值,不执行后续拦截器
      * @throws Exception
      */
-    default Object postHandle(RequestContext context, Object value) throws Exception {
+    default Object postHandle(ApiInfo info, MagicScriptContext context, Object value) throws Exception {
         return null;
     }
 

+ 42 - 63
src/main/java/org/ssssssss/magicapi/config/WebUIController.java

@@ -3,8 +3,6 @@ package org.ssssssss.magicapi.config;
 import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.jdbc.core.BeanPropertyRowMapper;
-import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.ResponseBody;
@@ -17,22 +15,30 @@ import org.ssssssss.script.parsing.Span;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
-import java.util.UUID;
 
 public class WebUIController {
 
 	private static Logger logger = LoggerFactory.getLogger(WebUIController.class);
 
-	private JdbcTemplate template;
-
 	private int debugTimeout;
 
-	public WebUIController(JdbcTemplate template,int debugTimeout) {
-		this.template = template;
+	private MappingHandlerMapping mappingHandlerMapping;
+
+	private MagicApiService magicApiService;
+
+	public void setDebugTimeout(int debugTimeout) {
 		this.debugTimeout = debugTimeout;
 	}
 
-	public void printBanner(){
+	public void setMappingHandlerMapping(MappingHandlerMapping mappingHandlerMapping) {
+		this.mappingHandlerMapping = mappingHandlerMapping;
+	}
+
+	public void setMagicApiService(MagicApiService magicApiService) {
+		this.magicApiService = magicApiService;
+	}
+
+	public void printBanner() {
 		System.out.println("  __  __                _           _     ____  ___ ");
 		System.out.println(" |  \\/  |  __ _   __ _ (_)  ___    / \\   |  _ \\|_ _|");
 		System.out.println(" | |\\/| | / _` | / _` || | / __|  / _ \\  | |_) || | ");
@@ -43,13 +49,9 @@ public class WebUIController {
 
 	@RequestMapping("/delete")
 	@ResponseBody
-	public JsonBean<Void> delete(String id) {
+	public JsonBean<Boolean> delete(String id) {
 		try {
-			Map<String, Object> info = template.queryForMap("select * from magic_api_info where id = ?", id);
-			if (info != null) {
-				template.update("delete from magic_api_info where id = ?", id);
-			}
-			return new JsonBean<>();
+			return new JsonBean<>(this.magicApiService.delete(id));
 		} catch (Exception e) {
 			logger.error("删除接口出错", e);
 			return new JsonBean<>(-1, e.getMessage());
@@ -60,7 +62,7 @@ public class WebUIController {
 	@ResponseBody
 	public JsonBean<List<ApiInfo>> list() {
 		try {
-			return new JsonBean<>(template.query("select id,api_name name,api_path path,api_method method from magic_api_info order by api_update_time desc",new BeanPropertyRowMapper<ApiInfo>(ApiInfo.class)));
+			return new JsonBean<>(magicApiService.list());
 		} catch (Exception e) {
 			logger.error("查询接口列表失败", e);
 			return new JsonBean<>(-1, e.getMessage());
@@ -69,19 +71,19 @@ public class WebUIController {
 
 	@RequestMapping("/continue")
 	@ResponseBody
-	public JsonBean<Object> debugContinue(String id){
+	public JsonBean<Object> debugContinue(String id) {
 		MagicScriptDebugContext context = MagicScriptDebugContext.getDebugContext(id);
-		if(context == null){
-			return new JsonBean<>(0,"debug session not found!");
+		if (context == null) {
+			return new JsonBean<>(0, "debug session not found!");
 		}
 		try {
 			context.singal();
 		} catch (InterruptedException e) {
 			e.printStackTrace();
 		}
-		if(context.isRunning()){
-			return new JsonBean<>(1000,context.getId(),context.getDebugInfo());
-		}else if(context.isException()){
+		if (context.isRunning()) {
+			return new JsonBean<>(1000, context.getId(), context.getDebugInfo());
+		} else if (context.isException()) {
 			return resolveThrowable((Throwable) context.getReturnValue());
 		}
 		return new JsonBean<>(context.getReturnValue());
@@ -100,9 +102,9 @@ public class WebUIController {
 				context.setBreakpoints((List<Integer>) breakpoints);
 				context.setTimeout(this.debugTimeout);
 				Object result = MagicScriptEngine.execute(script.toString(), context);
-				if(context.isRunning()){
-					return new JsonBean<>(1000,context.getId(),result);
-				}else if(context.isException()){
+				if (context.isRunning()) {
+					return new JsonBean<>(1000, context.getId(), result);
+				} else if (context.isException()) {
 					return resolveThrowable((Throwable) context.getReturnValue());
 				}
 				return new JsonBean<>(result);
@@ -113,27 +115,27 @@ public class WebUIController {
 		return new JsonBean<>(0, "脚本不能为空");
 	}
 
-	private JsonBean<Object> resolveThrowable(Throwable root){
+	private JsonBean<Object> resolveThrowable(Throwable root) {
 		MagicScriptError.ScriptException se = null;
 		Throwable parent = root;
-		do{
-			if(parent instanceof MagicScriptError.ScriptException){
-				se = (MagicScriptError.ScriptException)parent;
+		do {
+			if (parent instanceof MagicScriptError.ScriptException) {
+				se = (MagicScriptError.ScriptException) parent;
 			}
-		}while((parent = parent.getCause()) != null);
-		logger.error("测试脚本出错",root);
-		if(se != null){
+		} while ((parent = parent.getCause()) != null);
+		logger.error("测试脚本出错", root);
+		if (se != null) {
 			Span.Line line = se.getLine();
-			return new JsonBean<>(-1000, se.getSimpleMessage(), line == null ? null : Arrays.asList(line.getLineNumber(), line.getEndLineNumber(),line.getStartCol(), line.getEndCol()));
+			return new JsonBean<>(-1000, se.getSimpleMessage(), line == null ? null : Arrays.asList(line.getLineNumber(), line.getEndLineNumber(), line.getStartCol(), line.getEndCol()));
 		}
-		return new JsonBean<>(-1,root.getMessage());
+		return new JsonBean<>(-1, root.getMessage());
 	}
 
 	@RequestMapping("/get")
 	@ResponseBody
-	public JsonBean<Map<String, Object>> get(String id) {
+	public JsonBean<ApiInfo> get(String id) {
 		try {
-			return new JsonBean<>(template.queryForMap("select * from magic_api_info where id = ?", id));
+			return new JsonBean<>(this.magicApiService.get(id));
 		} catch (Exception e) {
 			logger.error("查询接口出错");
 			return new JsonBean<>(-1, e.getMessage());
@@ -157,40 +159,17 @@ public class WebUIController {
 				return new JsonBean<>(0, "脚本内容不能为空");
 			}
 			if (StringUtils.isBlank(info.getId())) {
-				info.setId(UUID.randomUUID().toString().replace("-", ""));
-				Integer count = template.queryForObject("select count(*) from magic_api_info where api_method = ? and api_path = ?",
-						Integer.class,
-						info.getMethod(),
-						info.getPath());
-				if (count > 0) {
+				if (magicApiService.exists(info.getMethod(), info.getPath())) {
 					return new JsonBean<>(0, String.format("接口%s:%s已存在", info.getMethod(), info.getPath()));
 				}
-				long time = System.currentTimeMillis();
-				template.update("insert into magic_api_info(id,api_method,api_path,api_script,api_name,api_create_time,api_update_time) values(?,?,?,?,?,?,?)",
-						info.getId(),
-						info.getMethod(),
-						info.getPath(),
-						info.getScript(),
-						info.getName(),
-						time,
-						time);
+				magicApiService.insert(info);
 			} else {
-				Integer count = template.queryForObject("select count(*) from magic_api_info where api_method = ? and api_path = ? and id !=?",
-						Integer.class,
-						info.getMethod(),
-						info.getPath(),
-						info.getId());
-				if (count > 0) {
+				if (magicApiService.existsWithoutId(info.getMethod(), info.getPath(), info.getId())) {
 					return new JsonBean<>(0, String.format("接口%s:%s已存在", info.getMethod(), info.getPath()));
 				}
-				template.update("update magic_api_info set api_method = ?,api_path = ?,api_script = ?,api_name = ?,api_update_time = ? where id = ?",
-						info.getMethod(),
-						info.getPath(),
-						info.getScript(),
-						info.getName(),
-						System.currentTimeMillis(),
-						info.getId());
+				magicApiService.update(info);
 			}
+			mappingHandlerMapping.registerMapping(info);
 			return new JsonBean<>(info.getId());
 		} catch (Exception e) {
 			logger.error("保存接口出错", e);

+ 5 - 4
src/main/resources/magicapi-support/js/index.js

@@ -271,11 +271,12 @@ $(function(){
             },
             success : function(info){
                 apiId = id;
-                $('input[name=name]').val(info.api_name);
-                $('input[name=path]').val(info.api_path);
-                $('select[name=method]').val(info.api_method);
+                $('input[name=name]').val(info.name);
+                $('input[name=path]').val(info.path);
+                $('select[name=method]').val(info.method);
                 layui.form.render();
-                editor.setValue(info.api_script);
+                resetEditor();
+                editor.setValue(info.script);
 
             }
         })