WebUIController.java 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. package org.ssssssss.magicapi.config;
  2. import org.apache.commons.lang3.StringUtils;
  3. import org.slf4j.Logger;
  4. import org.slf4j.LoggerFactory;
  5. import org.springframework.web.bind.annotation.RequestBody;
  6. import org.springframework.web.bind.annotation.RequestMapping;
  7. import org.springframework.web.bind.annotation.ResponseBody;
  8. import org.ssssssss.magicapi.functions.DatabaseQuery;
  9. import org.ssssssss.magicapi.model.JsonBean;
  10. import org.ssssssss.magicapi.model.JsonBodyBean;
  11. import org.ssssssss.magicapi.provider.ApiServiceProvider;
  12. import org.ssssssss.magicapi.provider.MagicAPIService;
  13. import org.ssssssss.magicapi.provider.ResultProvider;
  14. import org.ssssssss.script.MagicModuleLoader;
  15. import org.ssssssss.script.MagicScriptDebugContext;
  16. import org.ssssssss.script.MagicScriptEngine;
  17. import org.ssssssss.script.ScriptClass;
  18. import org.ssssssss.script.exception.MagicScriptAssertException;
  19. import org.ssssssss.script.exception.MagicScriptException;
  20. import org.ssssssss.script.parsing.Span;
  21. import javax.servlet.http.HttpServletRequest;
  22. import java.util.ArrayList;
  23. import java.util.Arrays;
  24. import java.util.List;
  25. import java.util.Map;
  26. public class WebUIController {
  27. private static Logger logger = LoggerFactory.getLogger(WebUIController.class);
  28. /**
  29. * debug 超时时间
  30. */
  31. private int debugTimeout;
  32. /**
  33. * 接口映射
  34. */
  35. private MappingHandlerMapping mappingHandlerMapping;
  36. /**
  37. * 接口查询service
  38. */
  39. private ApiServiceProvider magicApiService;
  40. /**
  41. * 自定义结果
  42. */
  43. private ResultProvider resultProvider;
  44. /**
  45. * 拦截器
  46. */
  47. private List<RequestInterceptor> requestInterceptors = new ArrayList<>();
  48. public WebUIController() {
  49. // 给前端添加代码提示
  50. MagicScriptEngine.addScriptClass(DatabaseQuery.class);
  51. MagicScriptEngine.addScriptClass(MagicAPIService.class);
  52. }
  53. public void addRequestInterceptor(RequestInterceptor requestInterceptor) {
  54. this.requestInterceptors.add(requestInterceptor);
  55. }
  56. public void setResultProvider(ResultProvider resultProvider) {
  57. this.resultProvider = resultProvider;
  58. }
  59. public void setDebugTimeout(int debugTimeout) {
  60. this.debugTimeout = debugTimeout;
  61. }
  62. public void setMappingHandlerMapping(MappingHandlerMapping mappingHandlerMapping) {
  63. this.mappingHandlerMapping = mappingHandlerMapping;
  64. }
  65. public void setMagicApiService(ApiServiceProvider magicApiService) {
  66. this.magicApiService = magicApiService;
  67. }
  68. public void printBanner() {
  69. System.out.println(" __ __ _ _ ____ ___ ");
  70. System.out.println(" | \\/ | __ _ __ _ (_) ___ / \\ | _ \\|_ _|");
  71. System.out.println(" | |\\/| | / _` | / _` || | / __| / _ \\ | |_) || | ");
  72. System.out.println(" | | | || (_| || (_| || || (__ / ___ \\ | __/ | | ");
  73. System.out.println(" |_| |_| \\__,_| \\__, ||_| \\___|/_/ \\_\\|_| |___|");
  74. System.out.println(" |___/ " + WebUIController.class.getPackage().getImplementationVersion());
  75. }
  76. /**
  77. * 删除接口
  78. * @param request
  79. * @param id 接口ID
  80. * @return
  81. */
  82. @RequestMapping("/delete")
  83. @ResponseBody
  84. public JsonBean<Boolean> delete(HttpServletRequest request, String id) {
  85. if (!allowVisit(request, RequestInterceptor.Authorization.DELETE)) {
  86. return new JsonBean<>(-10, "无权限执行删除方法");
  87. }
  88. try {
  89. boolean success = this.magicApiService.delete(id);
  90. if (success) {
  91. mappingHandlerMapping.unregisterMapping(id);
  92. }
  93. return new JsonBean<>(success);
  94. } catch (Exception e) {
  95. logger.error("删除接口出错", e);
  96. return new JsonBean<>(-1, e.getMessage());
  97. }
  98. }
  99. /**
  100. * 删除接口分组
  101. *
  102. * @param request
  103. * @param apiIds 接口ID列表,逗号分隔
  104. * @param groupName 分组名称
  105. * @return
  106. */
  107. @RequestMapping("/group/delete")
  108. @ResponseBody
  109. public JsonBean<Boolean> deleteGroup(HttpServletRequest request, String apiIds, String groupName) {
  110. if (!allowVisit(request, RequestInterceptor.Authorization.DELETE)) {
  111. return new JsonBean<>(-10, "无权限执行删除方法");
  112. }
  113. try {
  114. boolean success = this.magicApiService.deleteGroup(groupName);
  115. if (success) {
  116. if (StringUtils.isNotBlank(apiIds)) {
  117. String[] ids = apiIds.split(",");
  118. if (ids != null && ids.length > 0) {
  119. for (String id : ids) {
  120. mappingHandlerMapping.unregisterMapping(id);
  121. }
  122. }
  123. }
  124. }
  125. return new JsonBean<>(success);
  126. } catch (Exception e) {
  127. logger.error("删除接口出错", e);
  128. return new JsonBean<>(-1, e.getMessage());
  129. }
  130. }
  131. /**
  132. * 查询所有接口
  133. *
  134. * @return
  135. */
  136. @RequestMapping("/list")
  137. @ResponseBody
  138. public JsonBean<List<ApiInfo>> list() {
  139. try {
  140. return new JsonBean<>(magicApiService.list());
  141. } catch (Exception e) {
  142. logger.error("查询接口列表失败", e);
  143. return new JsonBean<>(-1, e.getMessage());
  144. }
  145. }
  146. /**
  147. * debug 恢复断点
  148. *
  149. * @param id
  150. * @return
  151. */
  152. @RequestMapping("/continue")
  153. @ResponseBody
  154. public JsonBean<Object> debugContinue(String id) {
  155. MagicScriptDebugContext context = MagicScriptDebugContext.getDebugContext(id);
  156. if (context == null) {
  157. return new JsonBean<>(0, "debug session not found!", resultProvider.buildResult(0, "debug session not found!"));
  158. }
  159. try {
  160. context.singal(); //等待语句执行到断点或执行完毕
  161. } catch (InterruptedException e) {
  162. e.printStackTrace();
  163. }
  164. if (context.isRunning()) { //判断是否执行完毕
  165. return new JsonBodyBean<>(1000, context.getId(), resultProvider.buildResult(1000, context.getId()), context.getDebugInfo());
  166. } else if (context.isException()) {
  167. return resolveThrowable((Throwable) context.getReturnValue());
  168. }
  169. return new JsonBodyBean<>(resultProvider.buildResult(context.getReturnValue()), context.getReturnValue());
  170. }
  171. /**
  172. * 获取所有class
  173. */
  174. @RequestMapping("/classes")
  175. @ResponseBody
  176. public JsonBean<Map<String, ScriptClass>> classes() {
  177. Map<String, ScriptClass> classMap = MagicScriptEngine.getScriptClassMap();
  178. classMap.putAll(MagicModuleLoader.getModules());
  179. return new JsonBean<>(classMap);
  180. }
  181. /**
  182. * 获取单个class
  183. *
  184. * @param className 类名
  185. * @return
  186. */
  187. @RequestMapping("/class")
  188. @ResponseBody
  189. public JsonBean<List<ScriptClass>> clazz(String className) {
  190. return new JsonBean<>(MagicScriptEngine.getScriptClass(className));
  191. }
  192. /**
  193. * 测试运行
  194. *
  195. * @param servletRequest
  196. * @param request 请求参数
  197. * @return
  198. */
  199. @RequestMapping("/test")
  200. @ResponseBody
  201. public JsonBean<Object> test(HttpServletRequest servletRequest, @RequestBody(required = false) Map<String, Object> request) {
  202. if (!allowVisit(servletRequest, RequestInterceptor.Authorization.RUN)) {
  203. return new JsonBean<>(-10, "无权限执行测试方法");
  204. }
  205. Object script = request.get("script");
  206. if (script != null) {
  207. request.remove("script");
  208. Object breakpoints = request.get("breakpoints");
  209. request.remove("breakpoints");
  210. MagicScriptDebugContext context = new MagicScriptDebugContext();
  211. try {
  212. context.putMapIntoContext((Map<String, Object>) request.get("request"));
  213. context.putMapIntoContext((Map<String, Object>) request.get("path"));
  214. context.set("cookie", request.get("cookie"));
  215. context.set("session", request.get("session"));
  216. context.set("header", request.get("header"));
  217. } catch (Exception e) {
  218. return new JsonBean<>(0, "请求参数填写错误", resultProvider.buildResult(0, "请求参数填写错误"));
  219. }
  220. try {
  221. context.setBreakpoints((List<Integer>) breakpoints); //设置断点
  222. context.setTimeout(this.debugTimeout); //设置断点超时时间
  223. Object result = MagicScriptEngine.execute(MagicScriptCompiler.compile(script.toString()), context);
  224. if (context.isRunning()) { //判断是否执行完毕
  225. return new JsonBodyBean<>(1000, context.getId(), resultProvider.buildResult(1000, context.getId(), result), result);
  226. } else if (context.isException()) { //判断是否出现异常
  227. return resolveThrowable((Throwable) context.getReturnValue());
  228. }
  229. return new JsonBean<>(resultProvider.buildResult(result));
  230. } catch (Exception e) {
  231. return resolveThrowable(e);
  232. }
  233. }
  234. return new JsonBean<>(resultProvider.buildResult(0, "脚本不能为空"));
  235. }
  236. /**
  237. * 解决异常
  238. */
  239. private JsonBean<Object> resolveThrowable(Throwable root) {
  240. MagicScriptException se = null;
  241. Throwable parent = root;
  242. do {
  243. if (parent instanceof MagicScriptAssertException) {
  244. MagicScriptAssertException sae = (MagicScriptAssertException) parent;
  245. return new JsonBean<>(sae.getCode(), sae.getMessage(), resultProvider.buildResult(sae.getCode(), sae.getMessage()));
  246. }
  247. if (parent instanceof MagicScriptException) {
  248. se = (MagicScriptException) parent;
  249. }
  250. } while ((parent = parent.getCause()) != null);
  251. logger.error("测试脚本出错", root);
  252. if (se != null) {
  253. Span.Line line = se.getLine();
  254. return new JsonBodyBean<>(-1000, se.getSimpleMessage(), resultProvider.buildResult(-1000, se.getSimpleMessage()), line == null ? null : Arrays.asList(line.getLineNumber(), line.getEndLineNumber(), line.getStartCol(), line.getEndCol()));
  255. }
  256. return new JsonBean<>(-1, root.getMessage(), resultProvider.buildResult(-1, root.getMessage()));
  257. }
  258. /**
  259. * 查询接口详情
  260. *
  261. * @param request
  262. * @param id 接口ID
  263. * @return
  264. */
  265. @RequestMapping("/get")
  266. @ResponseBody
  267. public JsonBean<ApiInfo> get(HttpServletRequest request, String id) {
  268. if (!allowVisit(request, RequestInterceptor.Authorization.DETAIL)) {
  269. return new JsonBean<>(-10, "无权限执行查看详情方法");
  270. }
  271. try {
  272. return new JsonBean<>(this.magicApiService.get(id));
  273. } catch (Exception e) {
  274. logger.error("查询接口出错");
  275. return new JsonBean<>(-1, e.getMessage());
  276. }
  277. }
  278. /**
  279. * 保存接口
  280. *
  281. * @param request
  282. * @param info 接口信息
  283. * @return
  284. */
  285. @RequestMapping("/save")
  286. @ResponseBody
  287. public JsonBean<String> save(HttpServletRequest request, ApiInfo info) {
  288. if (!allowVisit(request, RequestInterceptor.Authorization.SAVE)) {
  289. return new JsonBean<>(-10, "无权限执行保存方法");
  290. }
  291. try {
  292. if (StringUtils.isBlank(info.getMethod())) {
  293. return new JsonBean<>(0, "请求方法不能为空");
  294. }
  295. if (StringUtils.isBlank(info.getPath())) {
  296. return new JsonBean<>(0, "请求路径不能为空");
  297. }
  298. if (StringUtils.isBlank(info.getName())) {
  299. return new JsonBean<>(0, "接口名称不能为空");
  300. }
  301. if (StringUtils.isBlank(info.getScript())) {
  302. return new JsonBean<>(0, "脚本内容不能为空");
  303. }
  304. if (StringUtils.isBlank(info.getId())) {
  305. // 先判断接口是否存在
  306. if (magicApiService.exists(info.getMethod(), info.getPath())) {
  307. return new JsonBean<>(0, String.format("接口%s:%s已存在", info.getMethod(), info.getPath()));
  308. }
  309. magicApiService.insert(info);
  310. } else {
  311. // 先判断接口是否存在
  312. if (magicApiService.existsWithoutId(info.getMethod(), info.getPath(), info.getId())) {
  313. return new JsonBean<>(0, String.format("接口%s:%s已存在", info.getMethod(), info.getPath()));
  314. }
  315. magicApiService.update(info);
  316. }
  317. // 注册接口
  318. mappingHandlerMapping.registerMapping(info);
  319. return new JsonBean<>(info.getId());
  320. } catch (Exception e) {
  321. logger.error("保存接口出错", e);
  322. return new JsonBean<>(-1, e.getMessage());
  323. }
  324. }
  325. /**
  326. * 判断是否有权限访问按钮
  327. *
  328. * @param request
  329. * @param authorization
  330. * @return
  331. */
  332. private boolean allowVisit(HttpServletRequest request, RequestInterceptor.Authorization authorization) {
  333. for (RequestInterceptor requestInterceptor : requestInterceptors) {
  334. if (!requestInterceptor.allowVisit(request, authorization)) {
  335. return false;
  336. }
  337. }
  338. return true;
  339. }
  340. }