diff --git a/.drone.yml b/.drone.yml index f1d8d41..3dec36a 100644 --- a/.drone.yml +++ b/.drone.yml @@ -74,7 +74,7 @@ volumes: path: /home/build/fateverse - name: skywalking host: - path: /home/skywalking-agent + path: /home/build/skywalking-agent - name: config # k8s对接的配置文件 host: path: /home/kubect diff --git a/Dockerfile b/Dockerfile index d28e349..172bad7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,17 +2,15 @@ FROM azul/zulu-openjdk:11.0.22-jdk VOLUME /tmp RUN useradd -b /home -m -s /bin/bash clay RUN chmod a+xr -R /home/clay && chown clay:clay -R /home/clay -#COPY skywalking /home/clay/skywalking-agent -#RUN chmod a+xr -R /home/clay/skywalking-agent && chown clay:clay -R /home/clay/skywalking-agent +COPY skywalking /home/clay/skywalking-agent +RUN chmod a+xr -R /home/clay/skywalking-agent && chown clay:clay -R /home/clay/skywalking-agent USER clay ARG NAME=$DRONE_COMMIT_BRANCH COPY ./$NAME.jar /home/clay/$NAME.jar COPY start.sh /home/clay/start.sh WORKDIR /home/clay RUN mkdir -p /home/clay/logs && touch /home/clay/logs/spring.log -#RUN mkdir -p /home/clay/code -#RUN chmod 777 /home/clay/code -#RUN mkdir -p /home/clay/skywalking-agent/logs && touch /home/clay/skywalking-agent/logs/skywalking-api.log +RUN mkdir -p /home/clay/skywalking-agent/logs && touch /home/clay/skywalking-agent/logs/skywalking-api.log ENV REF_NAME dev EXPOSE 8080 CMD bash /home/clay/start.sh $REF_NAME && echo "start logging..." && : > /home/clay/logs/spring.log && tail -F -n 500 /home/clay/logs/spring.log \ No newline at end of file diff --git a/README.md b/README.md index 446a9c8..a0024d1 100644 --- a/README.md +++ b/README.md @@ -21,12 +21,12 @@ | 依赖 | 版本 | |----------------------|------------| -| Spring Boot | 2.7.5 | -| Spring Cloud | 2021.0.5 | -| Spring Cloud Alibaba | 2021.0.4.0 | +| Spring Boot | 2.7.3 | +| Spring Cloud | 2021.0.3 | +| Spring Cloud Alibaba | 2021.0.1.0 | | Mybatis | 3.5.2 | | Vue | 3.1.3 | -| React | 3.1.3 | +| React | 18.2.0 | ### 模块说明 diff --git a/common/common-code/pom.xml b/common/common-code/pom.xml index 9dea91f..6daff0a 100644 --- a/common/common-code/pom.xml +++ b/common/common-code/pom.xml @@ -21,6 +21,16 @@ cn.fateverse common-core + + org.graalvm.js + js-scriptengine + 22.1.0 + + + org.graalvm.js + js + 22.1.0 + \ No newline at end of file diff --git a/common/common-code/src/main/java/cn/fateverse/common/code/JavaCodeAutoConfiguration.java b/common/common-code/src/main/java/cn/fateverse/common/code/JavaCodeAutoConfiguration.java index 993a65e..ceaa52f 100644 --- a/common/common-code/src/main/java/cn/fateverse/common/code/JavaCodeAutoConfiguration.java +++ b/common/common-code/src/main/java/cn/fateverse/common/code/JavaCodeAutoConfiguration.java @@ -13,8 +13,8 @@ import org.springframework.context.annotation.Bean; public class JavaCodeAutoConfiguration { @Bean - public JavaCodeEngine javaCodeEngine(JavaCodeProperties javaCodeProperties){ - return new JavaCodeEngine(javaCodeProperties); + public JavaCodeEngine javaCodeEngine(JavaCodeProperties javaCodeProperties) { + return new JavaCodeEngine(javaCodeProperties.getClassPath()); } diff --git a/common/common-code/src/main/java/cn/fateverse/common/code/console/ConsoleCapture.java b/common/common-code/src/main/java/cn/fateverse/common/code/console/ConsoleCapture.java new file mode 100644 index 0000000..c5e8fc7 --- /dev/null +++ b/common/common-code/src/main/java/cn/fateverse/common/code/console/ConsoleCapture.java @@ -0,0 +1,51 @@ +package cn.fateverse.common.code.console; + +import cn.fateverse.common.code.model.EngineResult; +import cn.fateverse.common.core.exception.CustomException; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; + +/** + * 控制台输出捕获 + * + * @author Clay + * @date 2024/4/22 17:08 + */ +public class ConsoleCapture { + + + /** + * 捕获方法 + * + * @param task 任務 + * @return 返回结果 + */ + public static EngineResult capture(Task task) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintStream oldOut = System.out; + System.setOut(new PrintStream(baos)); + Object result; + String capturedOutput; + try { + result = task.execute(); + } catch (Exception e) { + if (e instanceof CustomException) { + throw (CustomException) e; + } + throw new RuntimeException(e); + } finally { + System.setOut(oldOut); + // 从捕获的字节数组输出流中获取打印的文本 + capturedOutput = baos.toString(); + } + return new EngineResult(result, capturedOutput); + } + + + public interface Task { + Object execute() throws Exception; + } + + +} diff --git a/common/common-code/src/main/java/cn/fateverse/common/code/engine/JavaCodeEngine.java b/common/common-code/src/main/java/cn/fateverse/common/code/engine/JavaCodeEngine.java index 180e34e..abeff1c 100644 --- a/common/common-code/src/main/java/cn/fateverse/common/code/engine/JavaCodeEngine.java +++ b/common/common-code/src/main/java/cn/fateverse/common/code/engine/JavaCodeEngine.java @@ -1,19 +1,21 @@ package cn.fateverse.common.code.engine; -import cn.fateverse.common.code.config.JavaCodeProperties; +import cn.fateverse.common.code.console.ConsoleCapture; import cn.fateverse.common.code.exception.SandboxClassNotFoundException; import cn.fateverse.common.code.lock.SegmentLock; +import cn.fateverse.common.code.model.EngineResult; import cn.fateverse.common.code.sandbox.SandboxClassLoader; import cn.fateverse.common.code.sandbox.SandboxSecurityManager; +import cn.fateverse.common.core.exception.CustomException; +import lombok.Getter; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; +import org.springframework.util.ObjectUtils; import javax.tools.JavaCompiler; import javax.tools.ToolProvider; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; +import java.io.*; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; @@ -36,9 +38,7 @@ public class JavaCodeEngine { private final URL url; - private final URLClassLoader classLoader; - - private final Map> classCache = new ConcurrentHashMap<>(); + private final Map classCache = new ConcurrentHashMap<>(); private final SandboxSecurityManager securityManager = new SandboxSecurityManager(classCache); @@ -47,54 +47,31 @@ public class JavaCodeEngine { private final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); - public JavaCodeEngine(JavaCodeProperties javaCodeProperties) { + public JavaCodeEngine(String classPath) { try { - CLASS_PATH = javaCodeProperties.getClassPath(); + CLASS_PATH = classPath; File file = new File(CLASS_PATH); if (!file.exists()) { file.mkdirs(); } url = file.toURI().toURL(); - classLoader = new SandboxClassLoader(new URL[]{url}); } catch (MalformedURLException e) { throw new RuntimeException(e); } } - /** - * 执行方法 - * - * @param code 代码字符串 - * @param className 类名 - * @param methodName 方法名 - * @param paramClass 参数类型数组 - * @param args 参数数组 - * @param development 是否为开发环境 开发环境下会将生成的类在执行完成后删除,不是生产环境则会缓存提高运行效率 - * @return 执行结果 - */ - public T execute(String code, String className, String methodName, Class[] paramClass, Object[] args, boolean development) { - if (development) { - return developmentExecute(code, className, methodName, paramClass, args); - } else { - return onlineExecute(code, className, methodName, paramClass, args); - } - } - - /** * 用于在开发环境中执行代码的私有方法。 * * @param code 需要执行的代码字符串 * @param className 类名 * @param methodName 方法名 - * @param paramClass 参数类型数组 * @param args 参数数组 - * @param 接收泛型 * @return 执行结构 */ @SneakyThrows - private T developmentExecute(String code, String className, String methodName, Class[] paramClass, Object[] args) { + public EngineResult mockExecute(String code, String className, String methodName, Object[] args) { Class loadClass = null; try { // 加锁,确保类只加载一次 @@ -104,12 +81,12 @@ public class JavaCodeEngine { // 创建一个URLClassLoader,用于加载代码字符串 tempClassLoader = new URLClassLoader(new URL[]{url}); // 编译代码字符串为类 - Class tempClass = compilerClass(className, code, tempClassLoader); - // 将编译好的类放入缓存 - classCache.put(className, tempClass); - return tempClass; + return compilerClass(className, code, tempClassLoader); } catch (Exception e) { e.printStackTrace(); + if (e instanceof CustomException) { + throw (CustomException) e; + } // 异常处理,并抛出自定义的SandboxClassNotFoundException异常 throw new SandboxClassNotFoundException(e.getMessage()); } finally { @@ -119,14 +96,17 @@ public class JavaCodeEngine { } }); // 获取需要执行的方法 - Method method = loadClass.getMethod(methodName, paramClass); + Method method = getMethod(methodName, loadClass); // 设置安全检查器 System.setSecurityManager(securityManager); // 执行方法并返回结果 - return (T) method.invoke(null, args); + return ConsoleCapture.capture(() -> method.invoke(null, args)); + } catch (CustomException e) { + EngineResult result = new EngineResult(); + result.setSuccess(Boolean.FALSE); + result.setConsole(e.getMessage()); + return result; } finally { - // 从缓存中移除编译好的类 - classCache.remove(className); // 清空安全检查器 System.setSecurityManager(null); if (loadClass != null) { @@ -153,37 +133,53 @@ public class JavaCodeEngine { * @param code 需要执行的代码字符串 * @param className 类名 * @param methodName 方法名 - * @param paramClass 参数类型数组 * @param args 参数数组 - * @param 接收泛型 * @return 执行结构 */ - private T onlineExecute(String code, String className, String methodName, Class[] paramClass, Object[] args) { + public Object execute(String code, String className, String methodName, Object[] args) { try { Class loadClass = null; - loadClass = classCache.get(className); - if (loadClass == null) { - loadClass = getLoadClass(code, className); - Method method = loadClass.getMethod(methodName, paramClass); - System.setSecurityManager(securityManager); - return (T) method.invoke(null, args); + //从缓存中获取 + CacheWrapper wrapper = classCache.get(className); + //缓存中不存在 + if (wrapper == null) { + //加载 + wrapper = getLoadClass(code, className); } + //获取到类信息 + loadClass = wrapper.getClazz(); + //获取方法 + Method method = getMethod(methodName, loadClass); + //开启安全模式 + System.setSecurityManager(securityManager); + //执行方法 + return method.invoke(null, args); } catch (Exception e) { + remove(className); e.printStackTrace(); } finally { System.setSecurityManager(null); - File javaFile = new File(CLASS_PATH + className + JAVA_SUFFIX); - if (javaFile.exists()) { - javaFile.delete(); - } - File classFile = new File(CLASS_PATH + className + CLASS_SUFFIX); - if (classFile.exists()) { - classFile.delete(); - } } return null; } + /** + * 获取到方法 + * + * @param methodName 方法名称 + * @param loadClass 类信息 + * @return 方法对象 + */ + private Method getMethod(String methodName, Class loadClass) { + Method method = null; + for (Method declaredMethod : loadClass.getDeclaredMethods()) { + if (declaredMethod.getName().equals(methodName)) { + method = declaredMethod; + } + } + return method; + } + /** * 获取到编译完成的Class对象 * @@ -191,15 +187,18 @@ public class JavaCodeEngine { * @param className 类名 * @return 编译后的Java对象 */ - private Class getLoadClass(String code, String className) { + private CacheWrapper getLoadClass(String code, String className) { //使用分段锁,提高效率,放多并发情况下多次对同一个类进行编译 return SegmentLock.lock(className, () -> { try { + URLClassLoader classLoader = new SandboxClassLoader(new URL[]{url}); //执行编译 Class tempClass = compilerClass(className, code, classLoader); + //创建缓存包装对象 + CacheWrapper wrapper = new CacheWrapper(tempClass, classLoader); //将编译之后的类对象放在缓存中,提高线上环境的运行效率 - classCache.put(className, tempClass); - return tempClass; + classCache.put(className, wrapper); + return wrapper; } catch (Exception e) { throw new RuntimeException(e); } @@ -215,32 +214,49 @@ public class JavaCodeEngine { * @return 编译完成的类对象 */ private Class compilerClass(String className, String code, URLClassLoader classLoader) { - log.info(code); File tempFile = new File(CLASS_PATH + className + JAVA_SUFFIX); try (FileWriter writer = new FileWriter(tempFile)) { writer.write(code); writer.close(); + ByteArrayOutputStream errorStream = new ByteArrayOutputStream(10240); // 编译.java文件 - compiler.run(null, null, null, tempFile.getPath()); + compiler.run(null, null, errorStream, tempFile.getPath()); + String trace = errorStream.toString();//存放控制台输出的字符串 + if (!ObjectUtils.isEmpty(trace)) { + trace = trace.replace(CLASS_PATH + className + ".", ""); + throw new CustomException("编译错误: " + trace); + } return classLoader.loadClass(className); } catch (Exception e) { e.printStackTrace(); - throw new RuntimeException(e); + if (e instanceof CustomException) { + throw (CustomException) e; + } + throw new CustomException("执行或者编辑错误!"); } } /** * 删除类 + * * @param className 删除类 * @return 删除结果 */ public Boolean remove(String className) { return SegmentLock.lock(className, () -> { - classCache.remove(className); + CacheWrapper wrapper = classCache.get(className); + if (wrapper != null) { + classCache.remove(className); + wrapper.remove(); + } + //进行gc 垃圾挥手 + System.gc(); + //删除Java文件 File javaFile = new File(CLASS_PATH + className + JAVA_SUFFIX); if (javaFile.exists()) { javaFile.delete(); } + //删除class文件 File classFile = new File(CLASS_PATH + className + CLASS_SUFFIX); if (classFile.exists()) { classFile.delete(); @@ -248,4 +264,24 @@ public class JavaCodeEngine { return true; }); } + + + @Getter + public static class CacheWrapper { + + private Class clazz; + + private URLClassLoader classLoader; + + public CacheWrapper(Class clazz, URLClassLoader classLoader) { + this.clazz = clazz; + this.classLoader = classLoader; + } + + + public void remove(){ + clazz = null; + classLoader = null; + } + } } diff --git a/common/common-code/src/main/java/cn/fateverse/common/code/engine/JavaScriptEngine.java b/common/common-code/src/main/java/cn/fateverse/common/code/engine/JavaScriptEngine.java index 085390d..dd0542b 100644 --- a/common/common-code/src/main/java/cn/fateverse/common/code/engine/JavaScriptEngine.java +++ b/common/common-code/src/main/java/cn/fateverse/common/code/engine/JavaScriptEngine.java @@ -1,9 +1,15 @@ package cn.fateverse.common.code.engine; -import javax.script.Invocable; -import javax.script.ScriptEngine; -import javax.script.ScriptEngineManager; -import javax.script.ScriptException; +import cn.fateverse.common.code.console.ConsoleCapture; +import cn.fateverse.common.code.lock.SegmentLock; +import cn.fateverse.common.code.model.EngineResult; +import cn.fateverse.common.core.exception.CustomException; +import com.alibaba.fastjson2.JSON; +import org.graalvm.polyglot.Context; +import org.graalvm.polyglot.Value; + +import java.util.HashMap; +import java.util.Map; /** * js 工具类 @@ -13,25 +19,89 @@ import javax.script.ScriptException; */ public class JavaScriptEngine { + + // 创建 GraalVM 上下文 + private static final Context context = Context.newBuilder() + .allowAllAccess(true) +// .allowHostClassLoading(true) +// .allowIO(true) +// .allowNativeAccess(true) + .build(); + + + private static final Map functionMap = new HashMap<>(); + + /** * 执行js代码 - * @param script js脚本 - * @param function js函数名 - * @param args 参数 + * + * @param script js脚本 + * @param functionName js函数名 + * @param args 参数 * @return 返回结构 - * @param 泛型类型 */ - public static T executeScript(String script, String function, Object... args) { - ScriptEngineManager manager = new ScriptEngineManager(); - ScriptEngine engine = manager.getEngineByName("JavaScript"); + public static Object execute(String script, String functionName, Object args) { try { - engine.eval(script); - Invocable inv = (Invocable) engine; - return (T) inv.invokeFunction(function, args); - } catch (ScriptException | NoSuchMethodException e) { - throw new RuntimeException(e); + Value executeFunction = getFunction(functionName, script); + Value javaObjectAsValue = Value.asValue(args); + Value result = executeFunction.execute(javaObjectAsValue); + return result.as(Object.class); + } catch (Exception e) { + remove(functionName); + throw new CustomException("运行失败!"); } } + public static EngineResult mockExecute(String script, String functionName, Object args) { + try { + return ConsoleCapture.capture(() -> { + Context context = Context.newBuilder() + .allowAllAccess(true) +// .allowHostClassLoading(true) +// .allowIO(true) +// .allowNativeAccess(true) + .build(); + try { + context.eval("js", script); + } catch (Exception e) { + String message = e.getMessage(); + message = message.replace("java.lang.RuntimeException: org.graalvm.polyglot.PolyglotException: SyntaxError:", ""); + throw new CustomException("js has error : " + message); + } + Value executeFunction = context.getBindings("js").getMember(functionName); + Value javaObjectAsValue = Value.asValue(args); + Value result = executeFunction.execute(javaObjectAsValue); + return result.as(Object.class); + }); + } catch (CustomException e) { + EngineResult result = new EngineResult(); + result.setSuccess(Boolean.FALSE); + result.setConsole(e.getMessage()); + return result; + } + } + + + private static Value getFunction(String functionName, String script) { + return SegmentLock.lock(functionName, () -> { + if (functionMap.containsKey(functionName)) { + return functionMap.get(functionName); + } + context.eval("js", script); + Value executeFunction = context.getBindings("js").getMember(functionName); + functionMap.put(functionName, executeFunction); + return executeFunction; + }); + } + + + public static void remove(String functionName) { + SegmentLock.lock(functionName, () -> { + functionMap.remove(functionName); + return null; + }); + } + + } diff --git a/common/common-code/src/main/java/cn/fateverse/common/code/lock/SegmentLock.java b/common/common-code/src/main/java/cn/fateverse/common/code/lock/SegmentLock.java index 48933de..c21c459 100644 --- a/common/common-code/src/main/java/cn/fateverse/common/code/lock/SegmentLock.java +++ b/common/common-code/src/main/java/cn/fateverse/common/code/lock/SegmentLock.java @@ -6,6 +6,8 @@ import java.util.concurrent.locks.ReentrantLock; import java.util.function.Supplier; /** + * 分段锁对象 + * * @author Clay * @date 2023-10-25 */ @@ -15,10 +17,11 @@ public class SegmentLock { /** * 分段锁 - * @param key 锁名称 + * + * @param key 锁名称 * @param supplier 需要执行的函数 + * @param 接收泛型 * @return 执行后的结果 - * @param 接收泛型 */ public static T lock(String key, Supplier supplier) { ReentrantLock lock = lockMap.get(key); diff --git a/common/common-code/src/main/java/cn/fateverse/common/code/model/EngineResult.java b/common/common-code/src/main/java/cn/fateverse/common/code/model/EngineResult.java new file mode 100644 index 0000000..2f6b8a1 --- /dev/null +++ b/common/common-code/src/main/java/cn/fateverse/common/code/model/EngineResult.java @@ -0,0 +1,28 @@ +package cn.fateverse.common.code.model; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author Clay + * @date 2024/4/22 17:10 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class EngineResult { + + private Object result; + + + private String console; + + private Boolean success; + + public EngineResult(Object result, String console) { + success = true; + this.result = result; + this.console = console; + } +} diff --git a/common/common-code/src/main/java/cn/fateverse/common/code/sandbox/SandboxSecurityManager.java b/common/common-code/src/main/java/cn/fateverse/common/code/sandbox/SandboxSecurityManager.java index 72c1d12..894bfc2 100644 --- a/common/common-code/src/main/java/cn/fateverse/common/code/sandbox/SandboxSecurityManager.java +++ b/common/common-code/src/main/java/cn/fateverse/common/code/sandbox/SandboxSecurityManager.java @@ -1,5 +1,7 @@ package cn.fateverse.common.code.sandbox; +import cn.fateverse.common.code.engine.JavaCodeEngine; + import java.io.FilePermission; import java.lang.reflect.ReflectPermission; import java.security.Permission; @@ -9,9 +11,9 @@ import java.util.Set; public class SandboxSecurityManager extends SecurityManager { - private final Map> classCache; + private final Map classCache; - public SandboxSecurityManager(Map> classCache) { + public SandboxSecurityManager(Map classCache) { this.classCache = classCache; } @@ -38,7 +40,7 @@ public class SandboxSecurityManager extends SecurityManager { private boolean isAllowedPermission(Permission permission) { //权限:用于校验文件系统访问权限,包括读取、写入、删除文件,以及目录操作。权限名称可能包括文件路径和操作,如 "read", "write", "delete", "execute" 等。 - if (permission instanceof FilePermission){ + if (permission instanceof FilePermission) { System.out.println("触发文件读写权限"); return false; } diff --git a/common/common-decrypt/src/main/java/cn/fateverse/common/decrypt/annotation/Encrypt.java b/common/common-decrypt/src/main/java/cn/fateverse/common/decrypt/annotation/Encrypt.java index a378b65..9f2daf5 100644 --- a/common/common-decrypt/src/main/java/cn/fateverse/common/decrypt/annotation/Encrypt.java +++ b/common/common-decrypt/src/main/java/cn/fateverse/common/decrypt/annotation/Encrypt.java @@ -12,4 +12,23 @@ import java.lang.annotation.Target; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Encrypt { + + Position value() default Position.ALL; + + + EncryptType type() default EncryptType.SM4; + + + enum EncryptType { + + SM4, + + } + + enum Position { + ALL, + OUT, + IN + } + } diff --git a/common/common-decrypt/src/main/java/cn/fateverse/common/decrypt/annotation/EncryptField.java b/common/common-decrypt/src/main/java/cn/fateverse/common/decrypt/annotation/EncryptField.java index d3d5582..f361306 100644 --- a/common/common-decrypt/src/main/java/cn/fateverse/common/decrypt/annotation/EncryptField.java +++ b/common/common-decrypt/src/main/java/cn/fateverse/common/decrypt/annotation/EncryptField.java @@ -11,4 +11,12 @@ import java.lang.annotation.Target; @Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface EncryptField { + + Position value() default Position.ALL; + + enum Position { + ALL, + OUT, + IN + } } \ No newline at end of file diff --git a/common/common-decrypt/src/main/java/cn/fateverse/common/decrypt/aspect/EncryptAspect.java b/common/common-decrypt/src/main/java/cn/fateverse/common/decrypt/aspect/EncryptAspect.java index e72f998..73152dc 100644 --- a/common/common-decrypt/src/main/java/cn/fateverse/common/decrypt/aspect/EncryptAspect.java +++ b/common/common-decrypt/src/main/java/cn/fateverse/common/decrypt/aspect/EncryptAspect.java @@ -2,6 +2,7 @@ package cn.fateverse.common.decrypt.aspect; import cn.fateverse.common.core.exception.CustomException; import cn.fateverse.common.core.result.Result; +import cn.fateverse.common.decrypt.annotation.Encrypt; import cn.fateverse.common.decrypt.annotation.EncryptField; import cn.fateverse.common.decrypt.service.EncryptService; import lombok.extern.slf4j.Slf4j; @@ -11,12 +12,10 @@ import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.util.ReflectionUtils; -import javax.annotation.Resource; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Parameter; -import java.util.Collection; -import java.util.List; +import java.util.*; @Slf4j @Aspect @@ -41,36 +40,35 @@ public class EncryptAspect { @Around("@annotation(cn.fateverse.common.decrypt.annotation.Encrypt)") public Object decryptField(ProceedingJoinPoint point) throws Throwable { MethodSignature signature = (MethodSignature) point.getSignature(); - //获取请求参数 - Object[] args = point.getArgs(); //获取方法 Method method = signature.getMethod(); - //获取方法参数 Parameter对象集 参数修饰符、参数名、注解及注解类型 - Parameter[] parameters = method.getParameters(); - for (int i = 0; i < parameters.length; i++) { - Parameter parameter = parameters[i]; - //获取参数注解 - EncryptField encryptField = parameter.getAnnotation(EncryptField.class); - Object arg = args[i]; - if (null != encryptField) { - if (arg instanceof String) { - String decrypt = encryptService.decrypt((String) arg); - args[i] = decrypt; - } else if (arg instanceof List) { - try { - List list = (List) arg; - list.replaceAll(encryptService::decrypt); - args[i] = list; - } catch (Exception e) { - throw new CustomException("接受参数类型错误,请使用String类型的泛型参数"); - } - } - } else if (parameter.getType().getName().startsWith(BASE_PACKAGE)) { //返回一个类对象,该类对象标识此参数对象表示的参数的声明类型 - decrypt(arg); - } + Encrypt encrypt = method.getAnnotation(Encrypt.class); + if (encrypt == null) { + return point.proceed(); + } + //获取请求参数 + Object[] args = point.getArgs(); + if (Encrypt.Position.ALL.equals(encrypt.value()) || Encrypt.Position.IN.equals(encrypt.value())) { + decryptParams(args, method); } //正常执行业务,最后返回的返回值为Result Object proceed = point.proceed(args); + if (Encrypt.Position.ALL.equals(encrypt.value()) || Encrypt.Position.OUT.equals(encrypt.value())) { + Result error = encryptResult(proceed); + if (error != null) { + return error; + } + } + return proceed; + } + + /** + * 加密返回值 + * + * @param proceed 返回执 + * @return 加密结果 + */ + private Result encryptResult(Object proceed) { if (proceed instanceof Result) { Result result = (Result) proceed; Object data = result.getData(); @@ -91,29 +89,71 @@ public class EncryptAspect { return Result.error("加密异常!"); } } - return proceed; + return null; } + /** + * 解密参数 + * + * @param args 参数 + * @param method 方法 + * @throws Exception 异常 + */ + private void decryptParams(Object[] args, Method method) throws Exception { + //获取方法参数 Parameter对象集 参数修饰符、参数名、注解及注解类型 + Parameter[] parameters = method.getParameters(); + for (int i = 0; i < parameters.length; i++) { + Parameter parameter = parameters[i]; + //获取参数注解 + EncryptField encryptField = parameter.getAnnotation(EncryptField.class); + Object arg = args[i]; + if (null != encryptField) { + if (arg instanceof String) { + String decrypt = encryptService.decrypt((String) arg); + args[i] = decrypt; + } else if (arg instanceof List) { + try { + List list = (List) arg; + list.replaceAll(encryptService::decrypt); + args[i] = list; + } catch (Exception e) { + throw new CustomException("接受参数类型错误,请使用String类型的泛型参数"); + } + } + } else if (parameter.getType().getName().startsWith(BASE_PACKAGE)) { + //返回一个类对象,该类对象标识此参数对象表示的参数的声明类型 + decrypt(arg); + } + } + } - private void encrypt(Object data) throws Exception { + /** + * 加密 + * + * @param data 数据 + */ + private void encrypt(Object data) { if (data == null) { return; } Class argClass = data.getClass(); + List fieldList = new ArrayList<>(); if (argClass.getTypeName().startsWith(BASE_PACKAGE)) { - Field[] fields = argClass.getDeclaredFields(); - for (Field field : fields) { + getFields(argClass, fieldList); + for (Field field : fieldList) { EncryptField encryptField = field.getAnnotation(EncryptField.class); field.setAccessible(true); Object value = ReflectionUtils.getField(field, data); if (null == value) { continue; } - if (null != encryptField && value instanceof String) { + if (null != encryptField && value instanceof String + && (EncryptField.Position.ALL.equals(encryptField.value()) + || EncryptField.Position.IN.equals(encryptField.value()))) { String decrypt = encryptService.encrypt((String) value); ReflectionUtils.setField(field, data, decrypt); } else if (field.getType().getName().startsWith(BASE_PACKAGE)) { - if (!value.getClass().isEnum()){ + if (!value.getClass().isEnum()) { encrypt(value); } } else if (value instanceof Collection) { @@ -128,29 +168,49 @@ public class EncryptAspect { for (Object item : collection) { encrypt(item); } + } else if (data instanceof Map) { + Map map = (Map) data; + for (Object key : map.keySet()) { + Object value = map.get(key); + encrypt(key); + encrypt(value); + } } } private void decrypt(Object arg) throws Exception { Class argClass = arg.getClass(); - Field[] fields = argClass.getDeclaredFields(); - for (Field field : fields) { + List fieldList = new ArrayList<>(); + getFields(argClass, fieldList); + for (Field field : fieldList) { EncryptField encryptField = field.getAnnotation(EncryptField.class); field.setAccessible(true); Object value = ReflectionUtils.getField(field, arg); if (null == value) { continue; } - if (null != encryptField && value instanceof String) { + if (null != encryptField && value instanceof String + && (EncryptField.Position.ALL.equals(encryptField.value()) + || EncryptField.Position.OUT.equals(encryptField.value()))) { String decrypt = encryptService.decrypt((String) value); ReflectionUtils.setField(field, arg, decrypt); } else if (field.getType().getName().startsWith(BASE_PACKAGE)) { - if (!value.getClass().isEnum()){ + if (!value.getClass().isEnum()) { decrypt(value); } } } } + + private void getFields(Class argClass, List fieldList) { + if (argClass.getTypeName().startsWith(BASE_PACKAGE)) { + Field[] fields = argClass.getDeclaredFields(); + fieldList.addAll(Arrays.asList(fields)); + getFields(argClass.getSuperclass(), fieldList); + } + } + + } diff --git a/common/common-security/src/main/java/cn/fateverse/common/security/filter/AuthenticationTokenFilter.java b/common/common-security/src/main/java/cn/fateverse/common/security/filter/AuthenticationTokenFilter.java index 7c594c7..8310eea 100644 --- a/common/common-security/src/main/java/cn/fateverse/common/security/filter/AuthenticationTokenFilter.java +++ b/common/common-security/src/main/java/cn/fateverse/common/security/filter/AuthenticationTokenFilter.java @@ -1,6 +1,5 @@ package cn.fateverse.common.security.filter; -import cn.fateverse.common.core.utils.ObjectUtils; import cn.fateverse.common.security.service.TokenService; import cn.fateverse.common.security.entity.LoginUser; import cn.fateverse.common.security.utils.SecurityUtils; @@ -8,6 +7,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; +import org.springframework.util.ObjectUtils; import org.springframework.web.filter.OncePerRequestFilter; import javax.annotation.Resource; diff --git a/custom-query/custom-query-biz/pom.xml b/custom-query/custom-query-biz/pom.xml index f037425..4e393cf 100644 --- a/custom-query/custom-query-biz/pom.xml +++ b/custom-query/custom-query-biz/pom.xml @@ -76,6 +76,10 @@ cn.fateverse common-excel + + com.squareup.okhttp3 + okhttp + ${project.artifactId} diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/config/RestTemplateConfig.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/config/RestTemplateConfig.java new file mode 100644 index 0000000..3513760 --- /dev/null +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/config/RestTemplateConfig.java @@ -0,0 +1,53 @@ +package cn.fateverse.query.config; + +import okhttp3.ConnectionPool; +import okhttp3.OkHttpClient; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.http.client.OkHttp3ClientHttpRequestFactory; +import org.springframework.web.client.RestTemplate; + +import java.util.concurrent.TimeUnit; + +/** + * @author Clay + * @date 2024/4/22 10:28 + */ +@Configuration +public class RestTemplateConfig { + + + @Bean + public RestTemplate httpRestTemplate() { + ClientHttpRequestFactory factory = httpRequestFactory(); + RestTemplate restTemplate = new RestTemplate(factory); + // 可以添加消息转换 + //restTemplate.setMessageConverters(...); + // 可以增加拦截器 + //restTemplate.setInterceptors(...); + return restTemplate; + } + + public ClientHttpRequestFactory httpRequestFactory() { + return new OkHttp3ClientHttpRequestFactory(okHttpConfigClient()); + } + + public OkHttpClient okHttpConfigClient() { + return new OkHttpClient().newBuilder() + .connectionPool(pool()) + .connectTimeout(1, TimeUnit.SECONDS) + .readTimeout(3, TimeUnit.SECONDS) + .writeTimeout(3, TimeUnit.SECONDS) + .hostnameVerifier((hostname, session) -> true) + // 设置代理 +// .proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 8888))) + // 拦截器 +// .addInterceptor() + .build(); + } + + public ConnectionPool pool() { + return new ConnectionPool(2000, 300, TimeUnit.SECONDS); + } +} diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/constant/QueryConstant.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/constant/QueryConstant.java index 8c07ad9..efd8172 100644 --- a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/constant/QueryConstant.java +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/constant/QueryConstant.java @@ -6,9 +6,29 @@ package cn.fateverse.query.constant; */ public class QueryConstant { - + /** + * 自定义查询权限前缀 + */ public static final String PERMISSIONS_KEY = "custom:query:online:"; + /** + * 自定义接口Redis前缀key + */ public static final String PORTAL_KEY = "custom:query:portal:"; + /** + * 接口开发状态 + */ + public static final Integer PORTAL_DEV = 0; + + /** + * 接口发布状态 + */ + public static final Integer PORTAL_PUBLISH = 1; + + /** + * 接口内部使用 + */ + public static final Integer PORTAL_INWARD = 2; + } diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/controller/DataAdapterController.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/controller/DataAdapterController.java index f0a9cfd..b7c776b 100644 --- a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/controller/DataAdapterController.java +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/controller/DataAdapterController.java @@ -66,13 +66,11 @@ public class DataAdapterController { } @ApiOperation("获取数据源适配器详细信息") - @Encrypt @GetMapping("/{adapterId}") @PreAuthorize("@ss.hasPermission('query:adapter:info')") - public Result info(@PathVariable @EncryptField String adapterId) { + public Result info(@PathVariable Long adapterId) { ObjectUtils.checkPk(adapterId); - Long id = Long.valueOf(adapterId); - DataAdapterVo dataAdapter = dataAdapterService.searchById(id); + DataAdapterVo dataAdapter = dataAdapterService.searchById(adapterId); return Result.ok(dataAdapter); } diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/controller/PortalController.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/controller/PortalController.java index cac86e4..7b34fde 100644 --- a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/controller/PortalController.java +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/controller/PortalController.java @@ -5,7 +5,10 @@ import cn.fateverse.common.core.result.page.TableDataInfo; import cn.fateverse.common.core.utils.ObjectUtils; import cn.fateverse.common.decrypt.annotation.Encrypt; import cn.fateverse.common.decrypt.annotation.EncryptField; +import cn.fateverse.query.entity.dto.DataAdapterCodeDto; +import cn.fateverse.query.entity.dto.MockParam; import cn.fateverse.query.entity.dto.PortalDto; +import cn.fateverse.query.entity.dto.PortalPublish; import cn.fateverse.query.entity.query.PortalQuery; import cn.fateverse.query.entity.vo.PortalIdWrapper; import cn.fateverse.query.entity.vo.PortalVo; @@ -36,7 +39,7 @@ public class PortalController { } @ApiOperation("获取接口管理表详细信息") - @Encrypt + @Encrypt(Encrypt.Position.IN) @GetMapping("/{portalId}") @PreAuthorize("@ss.hasPermission('query:portal:info')") public Result info(@PathVariable @EncryptField String portalId) { @@ -47,6 +50,17 @@ public class PortalController { } + @ApiOperation("详情接口") + @Encrypt(Encrypt.Position.IN) + @GetMapping("/detail/{portalId}") + public Result detail(@PathVariable @EncryptField String portalId) { + ObjectUtils.checkPk(portalId); + Long value = Long.valueOf(portalId); + PortalVo portal = portalService.searchDetailById(value); + return Result.ok(portal); + } + + @ApiOperation("获取接口管理表列表") @GetMapping @Encrypt @@ -57,7 +71,7 @@ public class PortalController { } @ApiOperation("新增接口") - @Encrypt + @Encrypt(Encrypt.Position.OUT) @PostMapping @PreAuthorize("@ss.hasPermission('query:portal:add')") public Result add(@RequestBody @Validated PortalDto portalDto) { @@ -66,7 +80,7 @@ public class PortalController { } @ApiOperation("修改接口") - @Encrypt + @Encrypt(Encrypt.Position.OUT) @PutMapping @PreAuthorize("@ss.hasPermission('query:portal:edit')") public Result edit(@RequestBody @Validated PortalDto portalDto) { @@ -76,4 +90,75 @@ public class PortalController { } + @ApiOperation("模拟执行") + @PostMapping("/mock/execute") + @PreAuthorize("@ss.hasPermission('query:portal:execute')") + public Result mockExecute(@RequestBody @Validated MockParam mockParam) { + if (ObjectUtils.isEmpty(mockParam.getCode())) { + return Result.error("代码不能为空"); + } + Object result = portalService.mockExecute(mockParam); + return Result.ok(result); + } + + @ApiOperation("获取接口数据") + @PostMapping("/mock/data") + @PreAuthorize("@ss.hasPermission('query:portal:data')") + public Result mockData(@RequestBody @Validated MockParam mockParam) { + Object result = portalService.mockData(mockParam); + return Result.ok(result); + } + + @ApiOperation("保存代码") + @PostMapping("/save/code") + @PreAuthorize("@ss.hasPermission('query:portal:edit')") + public Result saveCode(@RequestBody @Validated DataAdapterCodeDto dataAdapterCodeDto) { + portalService.saveCode(dataAdapterCodeDto); + return Result.ok(); + } + + @ApiOperation("列表接口发布") + @PostMapping("/list/publish") + @Encrypt(Encrypt.Position.IN) + @PreAuthorize("@ss.hasPermission('query:portal:edit')") + public Result listPublish(@RequestBody @Validated PortalPublish portalPublish) { + portalService.publish(portalPublish, Boolean.TRUE); + return Result.ok(); + } + @ApiOperation("设计器接口发布") + @PostMapping("/publish") + @PreAuthorize("@ss.hasPermission('query:portal:edit')") + public Result publish(@RequestBody @Validated PortalPublish portalPublish) { + if (ObjectUtils.isEmpty(portalPublish.getCode())){ + return Result.error("代码不能为空!"); + } + portalService.publish(portalPublish, Boolean.FALSE); + return Result.ok(); + } + + + @ApiOperation("撤销发布") + @Encrypt + @PutMapping("/cancel/{portalId}") + @PreAuthorize("@ss.hasPermission('query:portal:edit')") + public Result cancel(@PathVariable @EncryptField String portalId) { + ObjectUtils.checkPk(portalId); + Long value = Long.valueOf(portalId); + portalService.cancel(value); + return Result.ok(); + } + + + @ApiOperation("删除接口") + @Encrypt + @DeleteMapping("/{portalId}") + @PreAuthorize("@ss.hasPermission('query:portal:remove')") + public Result remove(@PathVariable @EncryptField String portalId) { + ObjectUtils.checkPk(portalId); + Long value = Long.valueOf(portalId); + portalService.delete(value); + return Result.ok(); + } + + } diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/dubbo/DubboDispatchServletPublishImpl.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/dubbo/DubboDispatchServletPublishImpl.java index 3eeb9d2..c6bb27d 100644 --- a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/dubbo/DubboDispatchServletPublishImpl.java +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/dubbo/DubboDispatchServletPublishImpl.java @@ -1,7 +1,11 @@ package cn.fateverse.query.dubbo; import cn.fateverse.query.constant.QueryConstant; +import cn.fateverse.query.entity.Portal; +import cn.fateverse.query.entity.PortalMapping; import cn.fateverse.query.entity.bo.PortalBo; +import cn.fateverse.query.mapper.PortalMapper; +import cn.fateverse.query.mapper.PortalMappingMapper; import cn.fateverse.query.portal.service.HandlerMethodService; import lombok.extern.slf4j.Slf4j; import org.apache.dubbo.config.annotation.DubboService; @@ -9,6 +13,7 @@ import org.springframework.data.redis.core.RedisTemplate; import org.springframework.web.bind.annotation.RequestMethod; import javax.annotation.Resource; +import java.util.List; /** * @author Clay @@ -18,10 +23,14 @@ import javax.annotation.Resource; @DubboService(scope = "remote") public class DubboDispatchServletPublishImpl implements DubboDispatchServletPublish { - @Resource private HandlerMethodService methodService; + @Resource + private PortalMapper portalMapper; + + @Resource + private PortalMappingMapper portalMappingMapper; @Resource private RedisTemplate redisTemplate; @@ -30,7 +39,13 @@ public class DubboDispatchServletPublishImpl implements DubboDispatchServletPubl public Boolean publish(String path, String requestMethod) { PortalBo portalBo = redisTemplate.opsForValue().get(QueryConstant.PORTAL_KEY + path + ":" + requestMethod); if (portalBo == null) { - return Boolean.FALSE; + Portal portal = portalMapper.selectByPath(path, requestMethod); + if (portal == null) { + return Boolean.FALSE; + } + List portalMappings = portalMappingMapper.selectByPortalId(portal.getPortalId()); + portalBo = PortalBo.toPortalBo(portal, portalMappings); + redisTemplate.opsForValue().set(QueryConstant.PORTAL_KEY + portalBo.getPath() + ":" + portalBo.getRequestMethod(), portalBo); } try { log.info("registerMapping, path:{}, requestMethod:{}", path, requestMethod); diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/DataAdapter.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/DataAdapter.java index 6b3c62c..3e4b3f9 100644 --- a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/DataAdapter.java +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/DataAdapter.java @@ -69,15 +69,19 @@ public class DataAdapter extends BaseEntity { this.code = "\n" + "import java.util.*;\n" + "import java.util.stream.*;\n" + + "import com.alibaba.fastjson2.*;\n" + "\n" + "public class DataAdapter {\n" + "\n" + - " public static Object execute(List> data) {\n" + + " public static Object execute(Object data) {\n" + " return data;\n" + " }\n" + "}\n"; } else if (DataAdapterType.JAVA_SCRIPT.equals(type)) { //JavaScript代码初始化 + this.code = "function execute(data) {\n" + + "\n" + + "}"; } } diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/Portal.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/Portal.java index 87a7cbd..cd72111 100644 --- a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/Portal.java +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/Portal.java @@ -3,11 +3,11 @@ package cn.fateverse.query.entity; import cn.fateverse.common.core.annotaion.EnableAutoField; import cn.fateverse.common.core.entity.BaseEntity; import cn.fateverse.query.enums.PortalEnum; +import cn.fateverse.query.enums.PortalPremEnum; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import org.springframework.web.bind.annotation.RequestMethod; /** @@ -33,6 +33,16 @@ public class Portal extends BaseEntity { */ private Long queryId; + /** + * 菜单id + */ + private Long menuId; + + /** + * 接口id + */ + private Long interfaceId; + /** * 数据适配器id */ @@ -44,9 +54,9 @@ public class Portal extends BaseEntity { private String portalName; /** - * 是否匿名 + * 权限类型 */ - private Boolean anonymity; + private PortalPremEnum permissionType; /** * 接口类型 @@ -58,19 +68,21 @@ public class Portal extends BaseEntity { */ private String requestMethod; - + /** + * 是否创建数据适配器 + */ private Boolean createDataAdapter; + /** + * 是否分页 + */ + private Boolean page; + /** * 系统暴露地址 */ private String path; - /** - * 第三方接口地址 - */ - private String url; - /** * 状态 */ diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/PortalInterface.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/PortalInterface.java new file mode 100644 index 0000000..115b55d --- /dev/null +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/PortalInterface.java @@ -0,0 +1,34 @@ +package cn.fateverse.query.entity; + +import lombok.Data; + +/** + * 第三方接口信息 + * + * @author Clay + * @date 2024/4/26 11:17 + */ +@Data +public class PortalInterface { + + /** + * 接口id + */ + private Long interfaceId; + + /** + * 请求地址 + */ + private String url; + + /** + * 请求类型 + */ + private String contentType; + + /** + * 请求类型 + */ + private String requestMethod; + +} diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/PortalMapping.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/PortalMapping.java index d5cb4cc..2e2f400 100644 --- a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/PortalMapping.java +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/PortalMapping.java @@ -43,12 +43,26 @@ public class PortalMapping { * 映射值 自定义查询映射值为查询条件的id 第三方接口则为接口查询的key */ private String mappingValue; + /** + * 输入类型 + */ + private String inputType; + + + private Boolean required; + + /** + * 描述 + */ + private String description; public Boolean check() { if (ObjectUtils.isEmpty(mappingKey) || ObjectUtils.isEmpty(mappingValue) - || ObjectUtils.isEmpty(mappingType)){ + || ObjectUtils.isEmpty(mappingType) +// || ObjectUtils.isEmpty(inputType) + ) { return Boolean.FALSE; } return Boolean.TRUE; diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/bo/PortalBo.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/bo/PortalBo.java index b70e1b6..e83de0d 100644 --- a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/bo/PortalBo.java +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/bo/PortalBo.java @@ -22,11 +22,13 @@ import java.util.List; public class PortalBo implements Serializable { private Long portalId; private Long queryId; + private Long interfaceId; private Long adapterId; private PortalEnum type; private String requestMethod; + private Boolean createDataAdapter; + private Boolean page; private String path; - private String url; private Integer state; private List mappings; @@ -34,11 +36,13 @@ public class PortalBo implements Serializable { return PortalBo.builder() .portalId(portal.getPortalId()) .queryId(portal.getQueryId()) + .interfaceId(portal.getInterfaceId()) .adapterId(portal.getAdapterId()) .type(portal.getType()) .requestMethod(portal.getRequestMethod()) + .createDataAdapter(portal.getCreateDataAdapter()) + .page(portal.getPage()) .path(portal.getPath()) - .url(portal.getUrl()) .state(portal.getState()) .mappings(mappings) .build(); diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/dto/DataAdapterCodeDto.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/dto/DataAdapterCodeDto.java new file mode 100644 index 0000000..a07659e --- /dev/null +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/dto/DataAdapterCodeDto.java @@ -0,0 +1,21 @@ +package cn.fateverse.query.entity.dto; + +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * @author Clay + * @date 2024/4/24 8:57 + */ +@Data +public class DataAdapterCodeDto { + + @NotNull(message = "id不能为空") + private Long portalId; + + @NotBlank(message = "代码内容不能为空!") + private String code; + +} diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/dto/MockParam.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/dto/MockParam.java new file mode 100644 index 0000000..d8fc541 --- /dev/null +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/dto/MockParam.java @@ -0,0 +1,35 @@ +package cn.fateverse.query.entity.dto; + +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * @author Clay + * @date 2024/4/21 19:07 + */ +@Data +public class MockParam { + + @NotNull(message = "id不能为空") + private Long portalId; + + private String code; + + private Integer pageSize; + + private Integer pageNum; + + private List params; + + @Data + public static class Param { + + private String key; + + private Object value; + + private String type; + } +} diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/dto/PortalDto.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/dto/PortalDto.java index f110fd6..310a4ce 100644 --- a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/dto/PortalDto.java +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/dto/PortalDto.java @@ -3,7 +3,9 @@ package cn.fateverse.query.entity.dto; import cn.fateverse.common.core.utils.ObjectUtils; import cn.fateverse.query.entity.Portal; import cn.fateverse.query.entity.PortalMapping; +import cn.fateverse.query.enums.DataAdapterType; import cn.fateverse.query.enums.PortalEnum; +import cn.fateverse.query.enums.PortalPremEnum; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -49,11 +51,11 @@ public class PortalDto { private String portalName; /** - * 是否匿名 + * 权限类型 */ - @ApiModelProperty("是否匿名") - @NotNull(message = "是否匿名不能为空") - private Boolean anonymity; + @ApiModelProperty("权限类型") + @NotNull(message = "权限类型不能为空") + private PortalPremEnum permissionType; /** * 接口类型 @@ -70,6 +72,21 @@ public class PortalDto { @NotNull(message = "是否创建数据适配器不能为空!") private Boolean createDataAdapter; + @ApiModelProperty("请求地址") + private String url; + + @ApiModelProperty("请求类型") + private String contentType; + + + @ApiModelProperty("接口请求方法类型") + private String interfaceRequestMethod; + + /** + * 是否分页 + */ + private Boolean page; + /** * 系统暴露地址 */ @@ -77,13 +94,6 @@ public class PortalDto { @NotBlank(message = "系统暴露地址不能为空") private String path; - /** - * 第三方接口地址 - */ - @ApiModelProperty("第三方接口地址") - private String url; - - /** * 状态 */ @@ -96,10 +106,8 @@ public class PortalDto { @ApiModelProperty("备注") private String remark; - - @ApiModelProperty("数据适配器信息") - private DataAdapterDto dataAdapter; - + @ApiModelProperty("适配器代码类型") + private DataAdapterType adapterCodeType; @ApiModelProperty("映射关系") private List mappings; @@ -110,17 +118,17 @@ public class PortalDto { .queryId(queryId) .adapterId(adapterId) .portalName(portalName) - .anonymity(anonymity) + .permissionType(permissionType) .createDataAdapter(createDataAdapter) .requestMethod(requestMethod) + .page(page) .type(type) .path(path) - .url(url) .state(state) .build(); try { RequestMethod.valueOf(requestMethod); - }catch (Exception e){ + } catch (Exception e) { throw new RuntimeException("请求类型不支持!"); } if (!ObjectUtils.isEmpty(portalId)) { @@ -131,6 +139,9 @@ public class PortalDto { if (!mapping.check()) { throw new RuntimeException("映射关系不完全,请检查映射关系"); } + if (ObjectUtils.isEmpty(mapping.getRequired())) { + mapping.setRequired(Boolean.FALSE); + } } } portal.setRemark(remark); diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/dto/PortalPublish.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/dto/PortalPublish.java new file mode 100644 index 0000000..6703399 --- /dev/null +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/dto/PortalPublish.java @@ -0,0 +1,26 @@ +package cn.fateverse.query.entity.dto; + +import cn.fateverse.common.decrypt.annotation.EncryptField; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +/** + * @author Clay + * @date 2024/4/30 16:58 + */ +@Data +public class PortalPublish { + + @EncryptField + @NotBlank(message = "接口id不能为空") + private String portalId; + + private String code; + + + public Long getLongPortalId() { + return Long.valueOf(portalId); + } + +} diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/query/DataAdapterQuery.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/query/DataAdapterQuery.java index 5ad8d3c..2a65503 100644 --- a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/query/DataAdapterQuery.java +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/query/DataAdapterQuery.java @@ -31,7 +31,6 @@ public class DataAdapterQuery { @ApiModelProperty("数据适配器代码类型 Java or Js") private DataAdapterType type; - @ApiModelProperty("是否通用") private Boolean common; } \ No newline at end of file diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/query/PortalQuery.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/query/PortalQuery.java index 41b6a27..b407291 100644 --- a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/query/PortalQuery.java +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/query/PortalQuery.java @@ -1,6 +1,7 @@ -package cn.fateverse.query.entity.query; +package cn.fateverse.query.entity.query; import cn.fateverse.query.enums.PortalEnum; +import cn.fateverse.query.enums.PortalPremEnum; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; @@ -26,10 +27,10 @@ public class PortalQuery { private String portalName; /** - * 是否匿名 + * 权限类型 */ - @ApiModelProperty("是否匿名") - private Boolean anonymity; + @ApiModelProperty("权限类型") + private PortalPremEnum permissionType; /** * 接口类型 @@ -42,4 +43,6 @@ public class PortalQuery { */ @ApiModelProperty("系统暴露地址") private String path; + + private Integer state; } \ No newline at end of file diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/vo/PortalVo.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/vo/PortalVo.java index f514e5c..c3348d9 100644 --- a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/vo/PortalVo.java +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/vo/PortalVo.java @@ -2,6 +2,7 @@ package cn.fateverse.query.entity.vo; import cn.fateverse.query.entity.Portal; import cn.fateverse.query.entity.PortalMapping; +import com.fasterxml.jackson.annotation.JsonInclude; import io.swagger.annotations.ApiModel; import lombok.Data; import org.springframework.beans.BeanUtils; @@ -20,12 +21,34 @@ import java.util.List; @ApiModel("接口详细管理表Vo") public class PortalVo extends SimplePortalVo { + /** + * 查询类型 + */ private Integer queryType; + /** + * 是否创建数据适配器 + */ private Boolean createDataAdapter; + /** + * 是否分页 + */ + private Boolean page; + + private String url; + + /** + * 条件映射 + */ private List mappings; + /** + * 数据适配器信息 + */ + @JsonInclude(JsonInclude.Include.NON_NULL) + private DataAdapterVo dataAdapter; + public static PortalVo toPortalVo(Portal portal) { return toPortalVo(portal, null); } diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/vo/SimplePortalVo.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/vo/SimplePortalVo.java index 2df83c3..940ac16 100644 --- a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/vo/SimplePortalVo.java +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/entity/vo/SimplePortalVo.java @@ -3,14 +3,15 @@ package cn.fateverse.query.entity.vo; import cn.fateverse.common.core.annotaion.Excel; import cn.fateverse.common.decrypt.annotation.EncryptField; import cn.fateverse.query.entity.Portal; +import cn.fateverse.query.enums.DataAdapterType; import cn.fateverse.query.enums.PortalEnum; +import cn.fateverse.query.enums.PortalPremEnum; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import org.springframework.util.ObjectUtils; import java.util.Date; @@ -37,16 +38,14 @@ public class SimplePortalVo { * 自定义查询id */ @ApiModelProperty("自定义查询id") - @EncryptField - private String queryId; + private Long queryId; /** * 数据适配器id */ @ApiModelProperty("数据适配器id") - @EncryptField - private String adapterId; + private Long adapterId; /** * 接口名称 @@ -68,17 +67,20 @@ public class SimplePortalVo { /** * 数据适配器名称 */ - @ApiModelProperty("数据适配器名称") - @Excel("数据适配器名称") - private String adapterName; + @ApiModelProperty("数据适配器类型") + @Excel("数据适配器类型") + private DataAdapterType adapterCodeType; + + + private Boolean createDataAdapter; /** - * 是否匿名 + * 权限类型 */ - @ApiModelProperty("是否匿名") - @Excel("是否匿名") - private Boolean anonymity; + @ApiModelProperty("权限类型") + @Excel("权限类型") + private PortalPremEnum permissionType; /** * 接口类型 @@ -126,7 +128,10 @@ public class SimplePortalVo { SimplePortalVo portalVo = SimplePortalVo.builder() .portalId(String.valueOf(portal.getPortalId())) .portalName(portal.getPortalName()) - .anonymity(portal.getAnonymity()) + .permissionType(portal.getPermissionType()) + .queryId(portal.getQueryId()) + .adapterId(portal.getAdapterId()) + .createDataAdapter(portal.getCreateDataAdapter()) .type(portal.getType()) .path(portal.getPath()) .state(portal.getState()) @@ -136,12 +141,6 @@ public class SimplePortalVo { .build(); portalVo.setCreateTime(portal.getCreateTime()); portalVo.setUpdateTime(portal.getUpdateTime()); - if (!ObjectUtils.isEmpty(portal.getQueryId())) { - portalVo.setQueryId(String.valueOf(portal.getQueryId())); - } - if (!ObjectUtils.isEmpty(portal.getAdapterId())) { - portalVo.setAdapterId(String.valueOf(portal.getAdapterId())); - } return portalVo; } diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/enums/DataAdapterType.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/enums/DataAdapterType.java index a52aa44..fc4d238 100644 --- a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/enums/DataAdapterType.java +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/enums/DataAdapterType.java @@ -2,7 +2,7 @@ package cn.fateverse.query.enums; public enum DataAdapterType { - JAVA("java"), + JAVA("Java"), JAVA_SCRIPT("JavaScript"); diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/enums/PortalPremEnum.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/enums/PortalPremEnum.java new file mode 100644 index 0000000..ac5d3f0 --- /dev/null +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/enums/PortalPremEnum.java @@ -0,0 +1,22 @@ +package cn.fateverse.query.enums; + +/** + * @author Clay + * @date 2024/4/15 11:23 + */ +public enum PortalPremEnum { + + /** + * 匿名 + */ + ANONYMITY, + /** + * 第三方授权 + */ + EXTERNAL, + /** + * 内部使用 + */ + LOCAL; + +} diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/handler/adapter/AbstractDataAdapterHandler.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/handler/adapter/AbstractDataAdapterHandler.java new file mode 100644 index 0000000..7dff1bb --- /dev/null +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/handler/adapter/AbstractDataAdapterHandler.java @@ -0,0 +1,73 @@ +package cn.fateverse.query.handler.adapter; + +import cn.fateverse.common.code.model.EngineResult; +import cn.fateverse.query.entity.DataAdapter; +import cn.fateverse.query.handler.reader.EngineExecuteHandlerReader; +import cn.fateverse.query.mapper.DataAdapterMapper; +import org.springframework.util.ObjectUtils; + +/** + * @author Clay + * @date 2024/4/19 22:44 + */ +public abstract class AbstractDataAdapterHandler implements DataAdapterHandler { + + protected final DataAdapterMapper dataAdapterMapper; + + + protected final EngineExecuteHandlerReader handlerReader; + + + protected AbstractDataAdapterHandler(DataAdapterMapper dataAdapterMapper, EngineExecuteHandlerReader handlerReader) { + this.dataAdapterMapper = dataAdapterMapper; + this.handlerReader = handlerReader; + } + + protected Object execute(Long adapterId, Object data) { + if (ObjectUtils.isEmpty(adapterId)) { + return data; + } + //获取当当前接口对应的数据适配器 + DataAdapter dataAdapter = dataAdapterMapper.selectById(adapterId); + if (ObjectUtils.isEmpty(dataAdapter)) { + throw new RuntimeException("dataAdapter is null"); + } + handlerReader.preconditioning(dataAdapter); + Object result = handlerReader.execute(dataAdapter, data); + if (ObjectUtils.isEmpty(result)) { + throw new RuntimeException("执行结果错误"); + } + return result; + } + + + protected EngineResult mockExecute(Long adapterId, String code, Object data) { + //获取当当前接口对应的数据适配器 + DataAdapter dataAdapter = dataAdapterMapper.selectById(adapterId); + if (ObjectUtils.isEmpty(dataAdapter)) { + throw new RuntimeException("dataAdapter is null"); + } + dataAdapter.setCode(code); + handlerReader.preconditioning(dataAdapter); + EngineResult execute = handlerReader.mockExecute(dataAdapter, data); + if (ObjectUtils.isEmpty(execute)) { + throw new RuntimeException("执行结果错误"); + } + dataAdapterMapper.updateCode(dataAdapter); + return execute; + } + + + @Override + public boolean remove(Long adapterId) { + if (ObjectUtils.isEmpty(adapterId)) { + throw new RuntimeException("adapterId is null"); + } + DataAdapter dataAdapter = dataAdapterMapper.selectById(adapterId); + if (ObjectUtils.isEmpty(dataAdapter)) { + throw new RuntimeException("dataAdapter is null"); + } + return handlerReader.remove(dataAdapter); + } + +} diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/handler/adapter/DataAdapterHandler.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/handler/adapter/DataAdapterHandler.java index 32d4638..a2c12b2 100644 --- a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/handler/adapter/DataAdapterHandler.java +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/handler/adapter/DataAdapterHandler.java @@ -1,8 +1,10 @@ package cn.fateverse.query.handler.adapter; -import cn.fateverse.query.entity.DataAdapter; +import cn.fateverse.query.entity.dto.MockParam; import cn.fateverse.query.entity.bo.PortalBo; +import javax.servlet.http.HttpServletRequest; + /** * @author Clay * @date 2023-10-31 20:52 @@ -12,19 +14,27 @@ public interface DataAdapterHandler { /** * 模拟执行 * - * @param dataAdapter 数据适配器信息 - * @param portal + * @param portal 接口对象 + * @param mockParam 请求头 * @return 执行结果 */ - Object mockExecute(DataAdapter dataAdapter, PortalBo portal, Object param); + Object mockExecute(PortalBo portal, MockParam mockParam); /** * 真实执行 * - * @param dataAdapter 数据适配器信息 - * @param portal + * @param portal 接口对象 + * @param request * @return 执行结果 */ - Object execute(DataAdapter dataAdapter, PortalBo portal, Object param); + Object execute(PortalBo portal, HttpServletRequest request); + + /** + * 删除数据适配器 + * + * @param adapterId 数据适配器id + * @return 删除结果 + */ + boolean remove(Long adapterId); } diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/handler/adapter/impl/ExternalDataAdapterHandler.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/handler/adapter/impl/ExternalDataAdapterHandler.java new file mode 100644 index 0000000..ecd1750 --- /dev/null +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/handler/adapter/impl/ExternalDataAdapterHandler.java @@ -0,0 +1,129 @@ +package cn.fateverse.query.handler.adapter.impl; + +import cn.fateverse.common.core.exception.CustomException; +import cn.fateverse.query.entity.PortalInterface; +import cn.fateverse.query.entity.PortalMapping; +import cn.fateverse.query.entity.dto.MockParam; +import cn.fateverse.query.entity.bo.PortalBo; +import cn.fateverse.query.enums.PortalEnum; +import cn.fateverse.query.handler.adapter.AbstractDataAdapterHandler; +import cn.fateverse.query.handler.reader.EngineExecuteHandlerReader; +import cn.fateverse.query.mapper.DataAdapterMapper; +import cn.fateverse.query.mapper.PortalInterfaceMapper; +import com.alibaba.fastjson2.JSONObject; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Service; +import org.springframework.util.ObjectUtils; +import org.springframework.web.client.RestTemplate; + +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; + +/** + * @author Clay + * @date 2024/4/19 22:12 + */ +@Slf4j +@Service +public class ExternalDataAdapterHandler extends AbstractDataAdapterHandler { + + /** + * 请求对象 + */ + private final RestTemplate restTemplate; + + private final PortalInterfaceMapper portalInterfaceMapper; + + public ExternalDataAdapterHandler(RestTemplate restTemplate, + DataAdapterMapper dataAdapterMapper, + EngineExecuteHandlerReader handlerReader, + PortalInterfaceMapper portalInterfaceMapper) { + super(dataAdapterMapper, handlerReader); + this.restTemplate = restTemplate; + this.portalInterfaceMapper = portalInterfaceMapper; + } + + + @Override + public Object mockExecute(PortalBo portal, MockParam mockParam) { + if (!PortalEnum.EXTERNAL.equals(portal.getType())) { + return null; + } + PortalInterface portalInterface = portalInterfaceMapper.selectById(portal.getInterfaceId()); + if (ObjectUtils.isEmpty(portalInterface)) { + throw new CustomException("接口不存在"); + } + HttpHeaders headers = new HttpHeaders(); + MediaType type = MediaType.parseMediaType(portalInterface.getContentType()); + headers.setContentType(type); + Map requestParams = new HashMap<>(); + if (!ObjectUtils.isEmpty(mockParam.getParams())) { + for (MockParam.Param param : mockParam.getParams()) { + if (!ObjectUtils.isEmpty(param.getKey()) && !ObjectUtils.isEmpty(param.getValue())) { + requestParams.put(param.getKey(), param.getValue()); + } + } + } + JSONObject response = null; + switch (portalInterface.getRequestMethod()) { + case "GET": + response = restTemplate.getForObject(portalInterface.getUrl(), JSONObject.class, requestParams); + break; + case "POST": + response = restTemplate.postForObject(portalInterface.getUrl(), requestParams, JSONObject.class); + break; + default: + throw new CustomException("请求方式错误"); + } + if (ObjectUtils.isEmpty(portal.getAdapterId()) || !portal.getCreateDataAdapter()) { + return response; + } else { + return super.mockExecute(portal.getAdapterId(), mockParam.getCode(), response); + } + } + + @Override + public Object execute(PortalBo portal, HttpServletRequest request) { + if (!PortalEnum.EXTERNAL.equals(portal.getType())) { + return null; + } + PortalInterface portalInterface = portalInterfaceMapper.selectById(portal.getInterfaceId()); + if (ObjectUtils.isEmpty(portalInterface)) { + throw new CustomException("接口不存在"); + } + HttpHeaders headers = new HttpHeaders(); + MediaType type = MediaType.parseMediaType(portalInterface.getContentType()); + headers.setContentType(type); + Map requestParams = new HashMap<>(); + for (PortalMapping mapping : portal.getMappings()) { + String mappingValue = mapping.getMappingValue(); + String mappingKey = mapping.getMappingKey(); + if (mapping.getMappingType() == 0) { + requestParams.put(mappingKey, request.getParameter(mappingValue)); + } else if (mapping.getMappingType() == 1) { + headers.add(mappingKey, request.getHeader(mappingValue)); + } else { + requestParams.put(mappingKey, request.getParameter(mappingValue)); + } + } + JSONObject response = null; + switch (portalInterface.getRequestMethod()) { + case "GET": + response = restTemplate.getForObject(portalInterface.getUrl(), JSONObject.class, requestParams); + break; + case "POST": + response = restTemplate.postForObject(portalInterface.getUrl(), requestParams, JSONObject.class); + break; + default: + throw new CustomException("请求方式错误"); + } + if (ObjectUtils.isEmpty(portal.getAdapterId()) || !portal.getCreateDataAdapter()) { + return response; + } else { + return super.execute(portal.getAdapterId(), response); + } + } +} diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/handler/adapter/impl/LocalDataAdapterHandler.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/handler/adapter/impl/LocalDataAdapterHandler.java index d5cd0c3..7cfcc7a 100644 --- a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/handler/adapter/impl/LocalDataAdapterHandler.java +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/handler/adapter/impl/LocalDataAdapterHandler.java @@ -2,20 +2,23 @@ package cn.fateverse.query.handler.adapter.impl; import cn.fateverse.common.core.exception.CustomException; import cn.fateverse.common.core.result.page.TableDataInfo; -import cn.fateverse.query.entity.DataAdapter; +import cn.fateverse.query.entity.dto.MockParam; +import cn.fateverse.query.entity.PortalMapping; import cn.fateverse.query.entity.UniQuery; import cn.fateverse.query.entity.bo.PortalBo; -import cn.fateverse.query.entity.dto.SearchInfo; +import cn.fateverse.query.entity.dto.UniConDto; import cn.fateverse.query.enums.PortalEnum; -import cn.fateverse.query.handler.adapter.DataAdapterHandler; +import cn.fateverse.query.handler.adapter.AbstractDataAdapterHandler; import cn.fateverse.query.handler.reader.EngineExecuteHandlerReader; +import cn.fateverse.query.mapper.DataAdapterMapper; import cn.fateverse.query.mapper.UniQueryMapper; import cn.fateverse.query.service.DynamicDataSearchService; -import com.alibaba.fastjson2.JSON; -import com.alibaba.fastjson2.TypeReference; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import org.springframework.util.ObjectUtils; +import javax.servlet.http.HttpServletRequest; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -25,55 +28,86 @@ import java.util.Map; */ @Slf4j @Service -public class LocalDataAdapterHandler implements DataAdapterHandler { +public class LocalDataAdapterHandler extends AbstractDataAdapterHandler { private final UniQueryMapper uniQueryMapper; - - private final EngineExecuteHandlerReader handlerReader; - private final DynamicDataSearchService dynamicDataSearchService; public LocalDataAdapterHandler(UniQueryMapper uniQueryMapper, + DataAdapterMapper dataAdapterMapper, EngineExecuteHandlerReader handlerReader, DynamicDataSearchService dynamicDataSearchService) { + super(dataAdapterMapper, handlerReader); this.uniQueryMapper = uniQueryMapper; - this.handlerReader = handlerReader; this.dynamicDataSearchService = dynamicDataSearchService; } @Override - public Object mockExecute(DataAdapter dataAdapter, PortalBo portal, Object param) { + public Object mockExecute(PortalBo portal, MockParam mockParam) { if (portal.getType() != PortalEnum.LOCAL) { return null; } - handlerReader.preconditioning(dataAdapter); - if (null == param) { - throw new CustomException("参数对象不能为空"); + //自定义查询编辑查询对象 + List uniConList = new ArrayList<>(); + if (!ObjectUtils.isEmpty(mockParam.getParams())) { + for (MockParam.Param param : mockParam.getParams()) { + if (!ObjectUtils.isEmpty(param.getKey()) && !ObjectUtils.isEmpty(param.getValue())) { + UniConDto uniCon = new UniConDto(); + uniCon.setQuery(param.getValue()); + uniCon.setUcId(Long.parseLong(param.getKey())); + } + } } - if (!(param instanceof SearchInfo)) { - throw new CustomException("数据类型不匹配"); - } - SearchInfo info = (SearchInfo) param; UniQuery query = uniQueryMapper.selectSampleById(portal.getQueryId()); if (null == query) { throw new CustomException("数据源为空!"); } //根据设置的参数动态调整当前是否需要分页操作 - TableDataInfo> tableDataInfo = dynamicDataSearchService.searchData(info.getList(), query, null, Boolean.TRUE); - return handlerReader.execute(dataAdapter, tableDataInfo.getRows(), true); + TableDataInfo> tableDataInfo = dynamicDataSearchService.searchData(uniConList, query, null, Boolean.TRUE); + if (ObjectUtils.isEmpty(portal.getAdapterId()) || !portal.getCreateDataAdapter()) { + return tableDataInfo.getRows(); + } else { + return super.mockExecute(portal.getAdapterId(), mockParam.getCode(), tableDataInfo.getRows()); + } } @Override - public Object execute(DataAdapter dataAdapter, PortalBo portal, Object param) { + public Object execute(PortalBo portal, HttpServletRequest request) { if (portal.getType() != PortalEnum.LOCAL) { return null; } - handlerReader.preconditioning(dataAdapter); - List> data = JSON.parseObject(dataAdapter.getMockData(), new TypeReference>>() { - }); - return handlerReader.execute(dataAdapter, data, false); + //自定义查询编辑查询对象 + List uniConList = new ArrayList<>(); + //根据映射关系从request中获取请求参数 + for (PortalMapping portalMapping : portal.getMappings()) { + UniConDto uniCon = new UniConDto(); + String mappingValue = portalMapping.getMappingValue(); + String mappingKey = portalMapping.getMappingKey(); + uniCon.setUcId(Long.parseLong(mappingKey)); + if (portalMapping.getMappingType() == 0) { + uniCon.setQuery(request.getParameter(mappingValue)); + } else if (portalMapping.getMappingType() == 1) { + uniCon.setQuery(request.getHeaders(mappingValue)); + } else { + uniCon.setQuery(request.getParameter(mappingValue)); + } + uniConList.add(uniCon); + } + UniQuery query = uniQueryMapper.selectSampleById(portal.getQueryId()); + if (null == query) { + throw new CustomException("数据源为空!"); + } + //根据设置的参数动态调整当前是否需要分页操作 + TableDataInfo> tableDataInfo = dynamicDataSearchService.searchData(uniConList, query, null, Boolean.TRUE); + if (portal.getCreateDataAdapter()) { + return super.execute(portal.getAdapterId(), tableDataInfo.getRows()); + } else { + return tableDataInfo.getRows(); + } } + + } diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/handler/engine/EngineExecuteHandler.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/handler/engine/EngineExecuteHandler.java index 708b751..1eb1b42 100644 --- a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/handler/engine/EngineExecuteHandler.java +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/handler/engine/EngineExecuteHandler.java @@ -1,5 +1,6 @@ package cn.fateverse.query.handler.engine; +import cn.fateverse.common.code.model.EngineResult; import cn.fateverse.query.entity.DataAdapter; public interface EngineExecuteHandler { @@ -10,10 +11,18 @@ public interface EngineExecuteHandler { * * @param dataAdapter 数据适配器 * @param data 数据列表 - * @param development * @return JSONObject对象 */ - Object execute(DataAdapter dataAdapter, Object data, boolean development); + Object execute(DataAdapter dataAdapter, Object data); + + /** + * 模拟执行方法 + * + * @param dataAdapter 数据适配器 + * @param data 数据列表 + * @return JSONObject对象 + */ + EngineResult mockExecute(DataAdapter dataAdapter, Object data); /** * 预处理数据适配器 @@ -25,8 +34,10 @@ public interface EngineExecuteHandler { /** * 删除数据适配器 + * * @param dataAdapter 数据适配器 * @return 删除结果 */ Boolean remove(DataAdapter dataAdapter); + } diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/handler/engine/impl/JavaEngineExecuteHandler.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/handler/engine/impl/JavaEngineExecuteHandler.java index 357f509..81b6816 100644 --- a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/handler/engine/impl/JavaEngineExecuteHandler.java +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/handler/engine/impl/JavaEngineExecuteHandler.java @@ -1,6 +1,7 @@ package cn.fateverse.query.handler.engine.impl; import cn.fateverse.common.code.engine.JavaCodeEngine; +import cn.fateverse.common.code.model.EngineResult; import cn.fateverse.common.core.exception.CustomException; import cn.fateverse.query.entity.DataAdapter; import cn.fateverse.query.enums.DataAdapterType; @@ -8,7 +9,6 @@ import cn.fateverse.query.handler.engine.EngineExecuteHandler; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; -import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -31,12 +31,21 @@ public class JavaEngineExecuteHandler implements EngineExecuteHandler { @Override - public Object execute(DataAdapter dataAdapter, Object data, boolean development) { - if (!DataAdapterType.JAVA.equals(dataAdapter.getType())){ + public Object execute(DataAdapter dataAdapter, Object data) { + if (!DataAdapterType.JAVA.equals(dataAdapter.getType())) { return null; } return javaCodeEngine.execute(dataAdapter.getExecuteCode(), getClassName(dataAdapter), - "execute", new Class[]{List.class}, new Object[]{data}, development); + "execute", new Object[]{data}); + } + + @Override + public EngineResult mockExecute(DataAdapter dataAdapter, Object data) { + if (!DataAdapterType.JAVA.equals(dataAdapter.getType())) { + return null; + } + return javaCodeEngine.mockExecute(dataAdapter.getExecuteCode(), getClassName(dataAdapter), + "execute", new Object[]{data}); } private static String getClassName(DataAdapter dataAdapter) { @@ -52,7 +61,8 @@ public class JavaEngineExecuteHandler implements EngineExecuteHandler { String modifiedCode = modifiedCode(dataAdapter.getCode()); String replacedCode = replacedClass(modifiedCode, getClassName(dataAdapter)); String IMPORT_CODE = "import java.util.*;\n" + - "import java.util.stream.*;\n"; + "import java.util.stream.*;\n" + + "import com.alibaba.fastjson2.*;"; dataAdapter.setExecuteCode(IMPORT_CODE + replacedCode); return Boolean.TRUE; } diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/handler/engine/impl/JavaScriptEngineExecuteHandler.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/handler/engine/impl/JavaScriptEngineExecuteHandler.java index 945ea28..52113d6 100644 --- a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/handler/engine/impl/JavaScriptEngineExecuteHandler.java +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/handler/engine/impl/JavaScriptEngineExecuteHandler.java @@ -1,12 +1,17 @@ package cn.fateverse.query.handler.engine.impl; import cn.fateverse.common.code.engine.JavaScriptEngine; +import cn.fateverse.common.code.model.EngineResult; +import cn.fateverse.common.core.exception.CustomException; import cn.fateverse.query.entity.DataAdapter; import cn.fateverse.query.enums.DataAdapterType; import cn.fateverse.query.handler.engine.EngineExecuteHandler; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + /** * JavaScript 代码执行器 * @@ -18,23 +23,49 @@ import org.springframework.stereotype.Component; public class JavaScriptEngineExecuteHandler implements EngineExecuteHandler { @Override - public Object execute(DataAdapter dataAdapter, Object data, boolean development) { + public Object execute(DataAdapter dataAdapter, Object data) { if (!DataAdapterType.JAVA_SCRIPT.equals(dataAdapter.getType())) { return null; } - return JavaScriptEngine.executeScript(dataAdapter.getExecuteCode(), "execute", data); + return JavaScriptEngine.execute(dataAdapter.getExecuteCode(), "execute" + dataAdapter.getAdapterId(), data); + } + + @Override + public EngineResult mockExecute(DataAdapter dataAdapter, Object data) { + if (!DataAdapterType.JAVA_SCRIPT.equals(dataAdapter.getType())) { + return null; + } + return JavaScriptEngine.mockExecute(dataAdapter.getExecuteCode(), "execute" + dataAdapter.getAdapterId(), data); + } @Override public Boolean preconditioning(DataAdapter dataAdapter) { - if (DataAdapterType.JAVA_SCRIPT.equals(dataAdapter.getType())) { - return Boolean.TRUE; + if (!DataAdapterType.JAVA_SCRIPT.equals(dataAdapter.getType())) { + return Boolean.FALSE; } - return Boolean.FALSE; + String code = dataAdapter.getCode(); + // 正则表达式匹配类定义 + String regex = "function .*? "; + Pattern pattern = Pattern.compile(regex); + Matcher matcher = pattern.matcher(code); + if (matcher.find()) { + // 执行替换操作 + String replacedCode = code.replaceFirst(regex, "function execute" + dataAdapter.getAdapterId() + "(data) "); + dataAdapter.setExecuteCode(replacedCode); + } else { + throw new CustomException("请勿修改类定义"); + } + return Boolean.TRUE; } @Override public Boolean remove(DataAdapter dataAdapter) { - return Boolean.FALSE; + if (!DataAdapterType.JAVA_SCRIPT.equals(dataAdapter.getType())) { + return Boolean.FALSE; + } + JavaScriptEngine.remove("execute" + dataAdapter.getAdapterId()); + return Boolean.TRUE; } + } diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/handler/reader/DataAdapterHandlerReader.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/handler/reader/DataAdapterHandlerReader.java index 4975f8c..6ff1a29 100644 --- a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/handler/reader/DataAdapterHandlerReader.java +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/handler/reader/DataAdapterHandlerReader.java @@ -2,12 +2,13 @@ package cn.fateverse.query.handler.reader; import cn.fateverse.common.core.exception.CustomException; -import cn.fateverse.query.entity.DataAdapter; +import cn.fateverse.query.entity.dto.MockParam; import cn.fateverse.query.entity.bo.PortalBo; import cn.fateverse.query.handler.adapter.DataAdapterHandler; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; +import javax.servlet.http.HttpServletRequest; import java.util.List; /** @@ -28,9 +29,9 @@ public class DataAdapterHandlerReader { } - public Object mockExecute(DataAdapter dataAdapter, PortalBo portal, Object params) { + public Object mockExecute(PortalBo portal, MockParam mockParam) { for (DataAdapterHandler dataAdapterHandler : handlerList) { - Object result = dataAdapterHandler.mockExecute(dataAdapter, portal, params); + Object result = dataAdapterHandler.mockExecute(portal, mockParam); if (result != null) { return result; } @@ -39,9 +40,9 @@ public class DataAdapterHandlerReader { } - public Object execute(DataAdapter dataAdapter, PortalBo portal, Object params) { + public Object execute(PortalBo portal, HttpServletRequest request) { for (DataAdapterHandler dataAdapterHandler : handlerList) { - Object result = dataAdapterHandler.execute(dataAdapter, portal, params); + Object result = dataAdapterHandler.execute(portal, request); if (result != null) { return result; } @@ -49,5 +50,15 @@ public class DataAdapterHandlerReader { throw new CustomException("当前数据源类型不支持!"); } + public Boolean remove(Long adaptorId) { + for (DataAdapterHandler dataAdapterHandler : handlerList) { + boolean result = dataAdapterHandler.remove(adaptorId); + if (result) { + return true; + } + } + return false; + } + } diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/handler/reader/EngineExecuteHandlerReader.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/handler/reader/EngineExecuteHandlerReader.java index 7e84e5e..06b98d2 100644 --- a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/handler/reader/EngineExecuteHandlerReader.java +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/handler/reader/EngineExecuteHandlerReader.java @@ -1,5 +1,6 @@ package cn.fateverse.query.handler.reader; +import cn.fateverse.common.code.model.EngineResult; import cn.fateverse.query.entity.DataAdapter; import cn.fateverse.query.handler.engine.EngineExecuteHandler; import lombok.extern.slf4j.Slf4j; @@ -47,11 +48,11 @@ public class EngineExecuteHandlerReader { * @param data 数据列表 * @return 执行结果 */ - public Object execute(DataAdapter dataAdapter, Object data, boolean development) { + public Object execute(DataAdapter dataAdapter, Object data) { // 遍历引擎执行处理器列表 for (EngineExecuteHandler engineExecuteHandler : handlerList) { // 执行数据适配器的处理方法 - Object result = engineExecuteHandler.execute(dataAdapter, data, development); + Object result = engineExecuteHandler.execute(dataAdapter, data); if (result != null) { return result; } @@ -59,6 +60,22 @@ public class EngineExecuteHandlerReader { // 若未找到匹配的数据适配器处理器,则返回null return null; } + public EngineResult mockExecute(DataAdapter dataAdapter, Object data) { + // 遍历引擎执行处理器列表 + for (EngineExecuteHandler engineExecuteHandler : handlerList) { + // 执行数据适配器的处理方法 + EngineResult result = engineExecuteHandler.mockExecute(dataAdapter, data); + if (result != null) { + return result; + } + } + // 若未找到匹配的数据适配器处理器,则返回null + return null; + } + + + + public Boolean remove(DataAdapter dataAdapter) { diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/mapper/DataAdapterMapper.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/mapper/DataAdapterMapper.java index 02e293d..f469b42 100644 --- a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/mapper/DataAdapterMapper.java +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/mapper/DataAdapterMapper.java @@ -48,6 +48,14 @@ public interface DataAdapterMapper { */ int update(DataAdapter dataAdapter); + /** + * 更新代码 + * + * @param dataAdapter 数据适配器 + * @return 结果 + */ + int updateCode(DataAdapter dataAdapter); + /** * 删除数据源适配器 * diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/mapper/PortalInterfaceMapper.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/mapper/PortalInterfaceMapper.java new file mode 100644 index 0000000..006debd --- /dev/null +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/mapper/PortalInterfaceMapper.java @@ -0,0 +1,44 @@ +package cn.fateverse.query.mapper; + +import cn.fateverse.query.entity.PortalInterface; + +/** + * @author Clay + * @date 2024/4/26 11:23 + */ +public interface PortalInterfaceMapper { + + /** + * 根据id查询 + * + * @param interfaceId 接口id + * @return 接口信息 + */ + PortalInterface selectById(Long interfaceId); + + /** + * 新增 + * + * @param portalInterface 接口信息 + * @return 影响行数 + */ + Integer insert(PortalInterface portalInterface); + + /** + * 修改 + * + * @param portalInterface 接口信息 + * @return 影响行数 + */ + Integer update(PortalInterface portalInterface); + + /** + * 删除 + * + * @param interfaceId 接口id + * @return 影响行数 + */ + Integer deleteById(Long interfaceId); + + +} diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/mapper/PortalMapper.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/mapper/PortalMapper.java index 6e8961c..41c97e9 100644 --- a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/mapper/PortalMapper.java +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/mapper/PortalMapper.java @@ -48,4 +48,28 @@ public interface PortalMapper { * @return 更新数量 */ int insert(Portal portal); + + /** + * 修改接口 + * + * @param portal 接口信息 + * @return 更新数量 + */ + int update(Portal portal); + + /** + * 更新状态 + * + * @param portalId 接口id + * @param state 状态 + */ + void updateState(@Param("portalId") Long portalId, @Param("state") Integer state); + + /** + * 删除 + * + * @param portalId id + * @return 删除行数 + */ + int deleteById(Long portalId); } diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/portal/PortalDispatchServlet.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/portal/PortalDispatchServlet.java index fe80175..b0f87d6 100644 --- a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/portal/PortalDispatchServlet.java +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/portal/PortalDispatchServlet.java @@ -3,14 +3,10 @@ package cn.fateverse.query.portal; import cn.fateverse.common.core.result.Result; import cn.fateverse.common.security.utils.ResponseRender; import cn.fateverse.query.constant.QueryConstant; -import cn.fateverse.query.entity.DataAdapter; import cn.fateverse.query.entity.Portal; import cn.fateverse.query.entity.PortalMapping; import cn.fateverse.query.entity.bo.PortalBo; -import cn.fateverse.query.entity.dto.SearchInfo; -import cn.fateverse.query.entity.dto.UniConDto; import cn.fateverse.query.handler.reader.DataAdapterHandlerReader; -import cn.fateverse.query.mapper.DataAdapterMapper; import cn.fateverse.query.mapper.PortalMapper; import cn.fateverse.query.mapper.PortalMappingMapper; import org.springframework.data.redis.core.RedisTemplate; @@ -20,7 +16,6 @@ import org.springframework.stereotype.Component; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.util.ArrayList; import java.util.List; /** @@ -35,19 +30,14 @@ public class PortalDispatchServlet { private final PortalMapper portalMapper; - private final DataAdapterMapper dataAdapterMapper; - private final PortalMappingMapper portalMappingMapper; private final DataAdapterHandlerReader dataAdapterHandler; - public PortalDispatchServlet(PortalMapper portalMapper, - DataAdapterMapper dataAdapterMapper, PortalMappingMapper portalMappingMapper, DataAdapterHandlerReader dataAdapterHandler) { this.portalMapper = portalMapper; - this.dataAdapterMapper = dataAdapterMapper; this.portalMappingMapper = portalMappingMapper; this.dataAdapterHandler = dataAdapterHandler; } @@ -70,34 +60,8 @@ public class PortalDispatchServlet { portalBo = PortalBo.toPortalBo(portal, portalMappings); redisTemplate.opsForValue().set(QueryConstant.PORTAL_KEY + portalBo.getPath() + ":" + portalBo.getRequestMethod(), portalBo); } - //自定义查询编辑查询对象 - SearchInfo searchInfo = new SearchInfo(); - List uniConList = new ArrayList<>(); - //根据映射关系从request中获取请求参数 - for (PortalMapping portalMapping : portalBo.getMappings()) { - UniConDto uniCon = new UniConDto(); - String mappingValue = portalMapping.getMappingValue(); - String mappingKey = portalMapping.getMappingKey(); - uniCon.setUcId(Long.parseLong(mappingValue)); - if (portalMapping.getMappingType() == 0) { - uniCon.setQuery(request.getParameter(mappingKey)); - } else if (portalMapping.getMappingType() == 1) { - uniCon.setQuery(request.getHeaders(mappingKey)); - } else { - uniCon.setQuery(request.getParameter(mappingKey)); - } - uniConList.add(uniCon); - } - searchInfo.setList(uniConList); - //获取当当前接口对应的数据适配器 - DataAdapter dataAdapter = dataAdapterMapper.selectById(portalBo.getAdapterId()); //进行数据适配器的执行逻辑 - Object result = null; - if (portalBo.getState() == 1 || portalBo.getState() == 2) { - result = dataAdapterHandler.execute(dataAdapter, portalBo, searchInfo); - } else { - result = dataAdapterHandler.mockExecute(dataAdapter, portalBo, searchInfo); - } + Object result = dataAdapterHandler.execute(portalBo, request); //将返回结果放入response ResponseRender.renderString(response, Result.ok(result)); } diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/portal/service/DispatchSyncService.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/portal/service/DispatchSyncService.java index 89d2705..9c61390 100644 --- a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/portal/service/DispatchSyncService.java +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/portal/service/DispatchSyncService.java @@ -14,6 +14,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.dubbo.config.annotation.DubboReference; import org.apache.dubbo.rpc.cluster.specifyaddress.Address; import org.apache.dubbo.rpc.cluster.specifyaddress.UserSpecifiedAddressUtil; +import org.bouncycastle.jcajce.provider.asymmetric.RSA; import org.springframework.context.event.EventListener; import org.springframework.core.env.Environment; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; @@ -122,24 +123,35 @@ public class DispatchSyncService { } //如果为false,则将当前任务重新放入到队列中,等待下一次执行 if (state == null || !state) { - queue.add(this); + retry(); } } catch (NacosException e) { log.error("NacosException: {}", e.getMessage()); //如果发生异常也是 - //todo 后续可以添加当前任务报错次数的处理 - queue.add(this); + retry(); } finally { //将指定的地址恢复 UserSpecifiedAddressUtil.setAddress(null); } } + + /** + * 进行重试 + */ + private void retry() { + retryCount++; + if (retryCount > 5) { + log.error("任务超过最大重试次数!"); + } + queue.add(this); + } }; //像阻塞队列中添加任务 queue.add(task); } } } catch (NacosException e) { + log.error("NacosException: {}", e.getMessage()); throw new RuntimeException(e); } } @@ -168,6 +180,8 @@ public class DispatchSyncService { protected final String requestMethod; + protected Integer retryCount = 0; + private Task(String ip, int port, String path, Boolean publish, String requestMethod) { this.ip = ip; this.port = port; diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/portal/service/HandlerMethodService.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/portal/service/HandlerMethodService.java index 0ad8866..15a8857 100644 --- a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/portal/service/HandlerMethodService.java +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/portal/service/HandlerMethodService.java @@ -2,28 +2,12 @@ package cn.fateverse.query.portal.service; import cn.fateverse.common.core.exception.CustomException; import cn.fateverse.common.core.utils.SpringContextHolder; -import cn.fateverse.query.dubbo.DubboDispatchServletPublish; import cn.fateverse.query.portal.PortalDispatchServlet; -import cn.fateverse.query.portal.config.DubboServiceBean; import cn.fateverse.query.portal.event.DispatchSyncEvent; -import com.alibaba.cloud.nacos.NacosDiscoveryProperties; -import com.alibaba.cloud.nacos.NacosServiceManager; -import com.alibaba.cloud.nacos.registry.NacosRegistration; -import com.alibaba.nacos.api.PropertyKeyConst; -import com.alibaba.nacos.api.exception.NacosException; -import com.alibaba.nacos.api.naming.NamingService; -import com.alibaba.nacos.api.naming.pojo.Instance; import lombok.extern.slf4j.Slf4j; -import org.apache.dubbo.config.annotation.DubboReference; -import org.apache.dubbo.rpc.RpcContext; -import org.apache.dubbo.rpc.RpcContextAttachment; -import org.apache.dubbo.rpc.cluster.specifyaddress.Address; -import org.apache.dubbo.rpc.cluster.specifyaddress.UserSpecifiedAddressUtil; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; -import org.springframework.core.env.Environment; -import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Component; import org.springframework.util.ObjectUtils; import org.springframework.web.bind.annotation.RequestMethod; @@ -32,12 +16,7 @@ import org.springframework.web.servlet.mvc.method.RequestMappingInfo; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; import java.lang.reflect.Method; -import java.util.List; import java.util.Map; -import java.util.Optional; -import java.util.Properties; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.BlockingQueue; /** * @author Clay @@ -49,7 +28,7 @@ public class HandlerMethodService implements ApplicationContextAware { public static final String CUSTOM_INTERFACE = "customInterface:"; - private RequestMappingHandlerMapping mapping; + private RequestMappingHandlerMapping handlerMapping; private Method mappingMethod; @@ -73,7 +52,7 @@ public class HandlerMethodService implements ApplicationContextAware { @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { //获取到web mvc的接口存储mapping - mapping = (RequestMappingHandlerMapping) applicationContext.getBean("requestMappingHandlerMapping"); + handlerMapping = (RequestMappingHandlerMapping) applicationContext.getBean("requestMappingHandlerMapping"); } /** @@ -92,12 +71,12 @@ public class HandlerMethodService implements ApplicationContextAware { .consumes(empty) .produces(empty) .mappingName(CUSTOM_INTERFACE + path); - RequestMappingInfo requestMappingInfo = builder.options(mapping.getBuilderConfiguration()).build(); - Map handlerMethods = mapping.getHandlerMethods(); + RequestMappingInfo requestMappingInfo = builder.options(handlerMapping.getBuilderConfiguration()).build(); + Map handlerMethods = handlerMapping.getHandlerMethods(); if (handlerMethods.containsKey(requestMappingInfo)) { throw new CustomException("path is exist"); } - mapping.registerMapping(requestMappingInfo, "portalDispatchServlet", mappingMethod); + handlerMapping.registerMapping(requestMappingInfo, "portalDispatchServlet", mappingMethod); // 判断是否需要发起同步 if (sync) { //使用事件监听机制,避免循环注入 @@ -112,12 +91,12 @@ public class HandlerMethodService implements ApplicationContextAware { * @param requestMethod 请求类型 */ public void unregisterMapping(String path, RequestMethod requestMethod, Boolean sync) { - Map handlerMethods = mapping.getHandlerMethods(); + Map handlerMethods = handlerMapping.getHandlerMethods(); for (RequestMappingInfo mappingInfo : handlerMethods.keySet()) { if (!ObjectUtils.isEmpty(mappingInfo.getName()) && (CUSTOM_INTERFACE + path).equals(mappingInfo.getName()) && mappingInfo.getMethodsCondition().getMethods().contains(requestMethod)) { - mapping.unregisterMapping(mappingInfo); + handlerMapping.unregisterMapping(mappingInfo); if (sync) { SpringContextHolder.publishEvent(new DispatchSyncEvent(path, requestMethod.name(), Boolean.FALSE)); } diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/service/DynamicDataSearchService.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/service/DynamicDataSearchService.java index d9221bc..9117eac 100644 --- a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/service/DynamicDataSearchService.java +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/service/DynamicDataSearchService.java @@ -71,7 +71,9 @@ public class DynamicDataSearchService { } else { uniConList = uniConMapper.selectByQueryIdAndUcIdList(query.getId(), ids); } - uniConList = uniConList.stream().filter(uniCon -> null != queryMap.get(uniCon.getUcId())).peek(uniCon -> uniCon.setUcMock(queryMap.get(uniCon.getUcId()))).collect(Collectors.toList()); + uniConList = uniConList.stream().filter(uniCon -> null != queryMap.get(uniCon.getUcId())) + .peek(uniCon -> uniCon.setUcMock(queryMap.get(uniCon.getUcId()))) + .collect(Collectors.toList()); if (query.getType() == 1) { SqlSelect select = new SqlSelect(); select.setSelectSql(query.getUqSql()); diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/service/PortalService.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/service/PortalService.java index 77fa46f..7661e93 100644 --- a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/service/PortalService.java +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/service/PortalService.java @@ -1,7 +1,10 @@ package cn.fateverse.query.service; import cn.fateverse.common.core.result.page.TableDataInfo; +import cn.fateverse.query.entity.dto.DataAdapterCodeDto; +import cn.fateverse.query.entity.dto.MockParam; import cn.fateverse.query.entity.dto.PortalDto; +import cn.fateverse.query.entity.dto.PortalPublish; import cn.fateverse.query.entity.query.PortalQuery; import cn.fateverse.query.entity.vo.PortalIdWrapper; import cn.fateverse.query.entity.vo.PortalVo; @@ -21,6 +24,14 @@ public interface PortalService { */ PortalVo searchById(Long portalId); + /** + * 根据id查询详情 + * + * @param portalId id + * @return 结果 + */ + PortalVo searchDetailById(Long portalId); + /** * 查询接口列表 * @@ -29,6 +40,30 @@ public interface PortalService { */ TableDataInfo searchList(PortalQuery query); + /** + * 模拟执行 + * + * @param mockParam 执行数据 + * @return 执行结果 + */ + Object mockExecute(MockParam mockParam); + + + /** + * 获取到模拟数据 + * + * @param mockParam 模拟参数 + * @return 执行结果 + */ + Object mockData(MockParam mockParam); + + /** + * 保存代码 + * + * @param dataAdapterCodeDto 数据适配器代码 + */ + void saveCode(DataAdapterCodeDto dataAdapterCodeDto); + /** * 保存接口信息 * @@ -44,4 +79,27 @@ public interface PortalService { * @return 修改完成后接口id和数据适配器id */ PortalIdWrapper edit(PortalDto portalDto); + + /** + * 发布接口 + * + * @param portalPublish 发布接口对象 + * @param isList 是否为list发布 + */ + void publish(PortalPublish portalPublish, Boolean isList); + + /** + * 取消发布 + * + * @param portalId 接口id + */ + void cancel(Long portalId); + + /** + * 删除接口信息 + * + * @param portalId 接口id + */ + void delete(Long portalId); + } diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/service/impl/DataAdapterServiceImpl.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/service/impl/DataAdapterServiceImpl.java index 2f0adf5..9f1f81c 100644 --- a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/service/impl/DataAdapterServiceImpl.java +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/service/impl/DataAdapterServiceImpl.java @@ -50,6 +50,7 @@ public class DataAdapterServiceImpl implements DataAdapterService { @Override public TableDataInfo searchList(DataAdapterQuery query) { PageUtils.startPage(); + query.setCommon(true); List list = dataAdapterMapper.selectList(query); return PageUtils.convertDataTable(list, DataAdapterVo::toDataAdapterVo); } @@ -87,6 +88,8 @@ public class DataAdapterServiceImpl implements DataAdapterService { @Transactional(rollbackFor = Exception.class) public int save(DataAdapterDto dataAdapter) { DataAdapter info = dataAdapter.toDataAdapter(); + info.setCommon(Boolean.TRUE); + info.init(); info.setCreateBy(SecurityUtils.getUsername()); return dataAdapterMapper.insert(info); } diff --git a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/service/impl/PortalServiceImpl.java b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/service/impl/PortalServiceImpl.java index b41e856..e65d457 100644 --- a/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/service/impl/PortalServiceImpl.java +++ b/custom-query/custom-query-biz/src/main/java/cn/fateverse/query/service/impl/PortalServiceImpl.java @@ -3,24 +3,25 @@ package cn.fateverse.query.service.impl; import cn.fateverse.common.core.exception.CustomException; import cn.fateverse.common.core.result.page.TableDataInfo; import cn.fateverse.common.mybatis.utils.PageUtils; +import cn.fateverse.query.entity.*; import cn.fateverse.query.entity.bo.PortalBo; +import cn.fateverse.query.entity.dto.DataAdapterCodeDto; +import cn.fateverse.query.entity.dto.MockParam; +import cn.fateverse.query.entity.dto.PortalPublish; +import cn.fateverse.query.entity.vo.DataAdapterVo; import cn.fateverse.query.entity.vo.PortalIdWrapper; +import cn.fateverse.query.enums.DataAdapterType; +import cn.fateverse.query.enums.PortalPremEnum; +import cn.fateverse.query.handler.reader.DataAdapterHandlerReader; +import cn.fateverse.query.handler.reader.EngineExecuteHandlerReader; +import cn.fateverse.query.mapper.*; import cn.fateverse.query.portal.service.HandlerMethodService; import cn.fateverse.query.constant.QueryConstant; -import cn.fateverse.query.entity.DataAdapter; -import cn.fateverse.query.entity.Portal; -import cn.fateverse.query.entity.PortalMapping; -import cn.fateverse.query.entity.UniQuery; -import cn.fateverse.query.entity.dto.DataAdapterDto; import cn.fateverse.query.entity.dto.PortalDto; import cn.fateverse.query.entity.query.PortalQuery; import cn.fateverse.query.entity.vo.PortalVo; import cn.fateverse.query.entity.vo.SimplePortalVo; import cn.fateverse.query.enums.PortalEnum; -import cn.fateverse.query.mapper.DataAdapterMapper; -import cn.fateverse.query.mapper.PortalMapper; -import cn.fateverse.query.mapper.PortalMappingMapper; -import cn.fateverse.query.mapper.UniQueryMapper; import cn.fateverse.query.service.PortalService; import lombok.extern.slf4j.Slf4j; import org.springframework.data.redis.core.RedisTemplate; @@ -32,7 +33,6 @@ import org.springframework.web.bind.annotation.RequestMethod; import javax.annotation.Resource; import java.util.*; -import java.util.function.Function; import java.util.stream.Collectors; /** @@ -57,19 +57,41 @@ public class PortalServiceImpl implements PortalService { private final PortalMappingMapper portalMappingMapper; + private final PortalInterfaceMapper portalInterfaceMapper; + + + private final DataAdapterHandlerReader handlerReader; + + private final EngineExecuteHandlerReader executeHandlerReader; + public PortalServiceImpl(PortalMapper portalMapper, UniQueryMapper queryMapper, DataAdapterMapper adapterMapper, PortalMappingMapper portalMappingMapper, ThreadPoolTaskExecutor taskExecuteExecutor, - HandlerMethodService methodService) { + HandlerMethodService methodService, + PortalInterfaceMapper portalInterfaceMapper, + DataAdapterHandlerReader handlerReader, + EngineExecuteHandlerReader executeHandlerReader) { this.portalMapper = portalMapper; this.queryMapper = queryMapper; this.adapterMapper = adapterMapper; this.portalMappingMapper = portalMappingMapper; this.methodService = methodService; + this.portalInterfaceMapper = portalInterfaceMapper; + this.handlerReader = handlerReader; + this.executeHandlerReader = executeHandlerReader; taskExecuteExecutor.execute(() -> { - List portalList = portalMapper.selectList(new PortalQuery()); + PortalQuery query = new PortalQuery(); +// query.setState(QueryConstant.PORTAL_PUBLISH); + List portalList = portalMapper.selectList(query); + if (ObjectUtils.isEmpty(portalList)) { + log.info("portal is empty!"); + return; + } + portalList = portalList.stream() + .filter(portal -> PortalPremEnum.ANONYMITY.equals(portal.getPermissionType()) || PortalPremEnum.EXTERNAL.equals(portal.getPermissionType())) + .collect(Collectors.toList()); if (ObjectUtils.isEmpty(portalList)) { log.info("portal is empty!"); return; @@ -103,6 +125,9 @@ public class PortalServiceImpl implements PortalService { @Override public PortalVo searchById(Long portalId) { Portal portal = portalMapper.selectById(portalId); + if (!QueryConstant.PORTAL_DEV.equals(portal.getState())) { + throw new CustomException("当前状态不允许查询"); + } PortalVo portalVo = PortalVo.toPortalVo(portal); List portalMappings = portalMappingMapper.selectByPortalId(portalId); if (ObjectUtils.isEmpty(portalMappings)) { @@ -110,12 +135,39 @@ public class PortalServiceImpl implements PortalService { } if (PortalEnum.LOCAL.equals(portal.getType())) { UniQuery uniQuery = queryMapper.selectById(portal.getQueryId()); - portalVo.setQueryType(uniQuery.getType()); + if (!ObjectUtils.isEmpty(uniQuery)) { + portalVo.setQueryType(uniQuery.getType()); + } + } else { + PortalInterface portalInterface = portalInterfaceMapper.selectById(portal.getInterfaceId()); + if (!ObjectUtils.isEmpty(portalInterface)) { + portalVo.setUrl(portalInterface.getUrl()); + } + } + if (portal.getCreateDataAdapter()) { + DataAdapter dataAdapter = adapterMapper.selectById(portal.getAdapterId()); + if (!ObjectUtils.isEmpty(dataAdapter)) { + portalVo.setAdapterCodeType(dataAdapter.getType()); + } } portalVo.setMappings(portalMappings); return portalVo; } + @Override + public PortalVo searchDetailById(Long portalId) { + PortalVo portalVo = searchById(portalId); + if (!ObjectUtils.isEmpty(portalVo.getAdapterId()) && portalVo.getCreateDataAdapter()) { + DataAdapter dataAdapter = adapterMapper.selectById(portalVo.getAdapterId()); + if (ObjectUtils.isEmpty(dataAdapter)) { + return portalVo; + } + DataAdapterVo dataAdapterVo = DataAdapterVo.toDataAdapterVo(dataAdapter); + portalVo.setDataAdapter(dataAdapterVo); + } + return portalVo; + } + @Override public TableDataInfo searchList(PortalQuery query) { PageUtils.startPage(); @@ -142,11 +194,11 @@ public class PortalServiceImpl implements PortalService { } } //映射数据适配器名称 - Map adapterMap = new HashMap<>(); + Map adapterMap = new HashMap<>(); if (!ObjectUtils.isEmpty(adapterIds)) { List adapterList = adapterMapper.selectListByIds(adapterIds); for (DataAdapter adapter : adapterList) { - adapterMap.put(adapter.getAdapterId(), adapter.getAdapterName()); + adapterMap.put(adapter.getAdapterId(), adapter.getType()); } } //映射重组 @@ -157,26 +209,66 @@ public class PortalServiceImpl implements PortalService { simplePortalVo.setQueryName(uniQuery.getUqName()); simplePortalVo.setQueryType(uniQuery.getType()); } - simplePortalVo.setAdapterName(adapterMap.getOrDefault(portal.getAdapterId(), null)); + simplePortalVo.setAdapterCodeType(adapterMap.getOrDefault(portal.getAdapterId(), null)); return simplePortalVo; }); } + @Override + public Object mockExecute(MockParam mockParam) { + Portal portal = portalMapper.selectById(mockParam.getPortalId()); + if (!QueryConstant.PORTAL_DEV.equals(portal.getState())) { + throw new CustomException("当前状态不允许执行"); + } + PortalBo portalBo = PortalBo.toPortalBo(portal, null); + return handlerReader.mockExecute(portalBo, mockParam); + } + + + @Override + public Object mockData(MockParam mockParam) { + Portal portal = portalMapper.selectById(mockParam.getPortalId()); + PortalBo portalBo = PortalBo.toPortalBo(portal, null); + portalBo.setCreateDataAdapter(false); + return handlerReader.mockExecute(portalBo, mockParam); + } + + @Override + public void saveCode(DataAdapterCodeDto dataAdapterCodeDto) { + Portal portal = portalMapper.selectById(dataAdapterCodeDto.getPortalId()); + if (ObjectUtils.isEmpty(portal)) { + throw new CustomException("未找到对应的接口"); + } + if (!QueryConstant.PORTAL_DEV.equals(portal.getState())) { + throw new CustomException("当前状态不允许保存"); + } + if (ObjectUtils.isEmpty(portal.getAdapterId()) || !portal.getCreateDataAdapter()) { + throw new CustomException("未找到数据适配器"); + } + DataAdapter dataAdapter = new DataAdapter(); + dataAdapter.setAdapterId(portal.getAdapterId()); + dataAdapter.setCode(dataAdapterCodeDto.getCode()); + adapterMapper.update(dataAdapter); + } @Override @Transactional(rollbackFor = Exception.class) public PortalIdWrapper save(PortalDto portalDto) { + checkPortalType(portalDto); Portal portal = portalDto.toPortal(); - checkPortalType(portal); Portal old = portalMapper.selectByPath(portal.getPath(), portal.getRequestMethod()); if (!ObjectUtils.isEmpty(old)) { throw new CustomException("系统中存在当前请求路径"); } - UniQuery uniQuery = queryMapper.selectById(portal.getQueryId()); - if (ObjectUtils.isEmpty(uniQuery)) { - throw new CustomException("未找到对应的查询接口!"); + if (PortalEnum.EXTERNAL.equals(portal.getType())) { + createPortalInterface(portalDto, portal); + } else { + UniQuery uniQuery = queryMapper.selectById(portal.getQueryId()); + if (ObjectUtils.isEmpty(uniQuery)) { + throw new CustomException("未找到对应的查询接口!"); + } } - portal.setState(0); + portal.setState(QueryConstant.PORTAL_DEV); // 判断是否需要创建数据适配器 if (portal.getCreateDataAdapter()) { createDataAdapter(portalDto, portal); @@ -203,14 +295,17 @@ public class PortalServiceImpl implements PortalService { } @Override + @Transactional(rollbackFor = Exception.class) public PortalIdWrapper edit(PortalDto portalDto) { + checkPortalType(portalDto); Portal portal = portalDto.toPortal(); - checkPortalType(portal); Portal old = portalMapper.selectByPath(portal.getPath(), portal.getRequestMethod()); + if (!QueryConstant.PORTAL_DEV.equals(old.getState())) { + throw new CustomException("当前状态不允许修改"); + } if (!ObjectUtils.isEmpty(old) && !old.getPortalId().equals(portal.getPortalId())) { throw new CustomException("系统中存在当前请求路径"); } - if (portal.getCreateDataAdapter() != old.getCreateDataAdapter()) { if (portal.getCreateDataAdapter()) { createDataAdapter(portalDto, portal); @@ -218,51 +313,92 @@ public class PortalServiceImpl implements PortalService { adapterMapper.deleteById(old.getAdapterId()); } } - PortalBo portalBo = PortalBo.toPortalBo(portal, portalDto.getMappings()); - //存在接口路径或者请求类型不同则需要重新发布 - if (!old.getPath().equals(portal.getPath()) - || !old.getRequestMethod().equals(portal.getRequestMethod())) { - //先卸载接口,需要进行数据同步 - unpublishPortal(old, true); - //注册新的映射 - methodService.registerMapping(portalBo.getPath(), RequestMethod.valueOf(portalBo.getRequestMethod()), true); + if (!old.getType().equals(portal.getType())) { + if (PortalEnum.LOCAL.equals(portal.getType())) { + portalInterfaceMapper.deleteById(old.getInterfaceId()); + } else { + createPortalInterface(portalDto, portal); + } + } else { + if (PortalEnum.EXTERNAL.equals(portal.getType())) { + PortalInterface portalInterface = new PortalInterface(); + portalInterface.setInterfaceId(old.getInterfaceId()); + portalInterface.setContentType(portalDto.getContentType()); + portalInterface.setRequestMethod(portalDto.getInterfaceRequestMethod()); + portalInterface.setUrl(portalDto.getUrl()); + portalInterfaceMapper.update(portalInterface); + } + } + portalMappingMapper.deleteByPortalId(portal.getPortalId()); + portalMapper.update(portal); + if (!ObjectUtils.isEmpty(portalDto.getMappings())) { + List mappings = portalDto.getMappings(); + for (PortalMapping mapping : mappings) { + mapping.setPortalId(portal.getPortalId()); + } + portalMappingMapper.insertBatch(mappings); } - //修改Redis中的数据信息 - redisTemplate.opsForValue().set(QueryConstant.PORTAL_KEY + portalBo.getPath() + ":" + portalBo.getRequestMethod(), portalBo); //返回接口id和适配器id return PortalIdWrapper.builder() .portalId(String.valueOf(portal.getPortalId())) .adapterId(String.valueOf(portal.getAdapterId())) .build(); - } - private boolean mappingCheckEquals(List oldPortalMappingList, List mappings) { - if (ObjectUtils.isEmpty(oldPortalMappingList) && ObjectUtils.isEmpty(mappings)) { - return true; + @Override + public void cancel(Long portalId) { + Portal portal = portalMapper.selectById(portalId); + if (ObjectUtils.isEmpty(portal)) { + return; } - if (ObjectUtils.isEmpty(oldPortalMappingList) || ObjectUtils.isEmpty(mappings)) { - return false; + if (QueryConstant.PORTAL_DEV.equals(portal.getState())) { + throw new CustomException("当前状态错误"); } - Optional optional = mappings.stream().filter(ObjectUtils::isEmpty).findAny(); - if (optional.isEmpty()) { - return false; + portalMapper.updateState(portalId, QueryConstant.PORTAL_DEV); + if (QueryConstant.PORTAL_PUBLISH.equals(portal.getState())) { + unpublishPortal(portal, Boolean.TRUE); } - if (oldPortalMappingList.size() == mappings.size()) { - Map oldPortalMappingMap = oldPortalMappingList.stream() - .collect(Collectors.toMap(PortalMapping::getMappingId, Function.identity())); - Map portalMappingMap = mappings.stream() - .collect(Collectors.toMap(PortalMapping::getMappingId, Function.identity())); - for (Long mappingId : oldPortalMappingMap.keySet()) { - PortalMapping portalMapping = portalMappingMap.get(mappingId); - if (ObjectUtils.isEmpty(portalMapping)) { - return false; - } - } - } - return false; } + + @Override + public void publish(PortalPublish portalPublish, Boolean isList) { + Long portalId = portalPublish.getLongPortalId(); + Portal portal = portalMapper.selectById(portalId); + List mappings = portalMappingMapper.selectByPortalId(portalId); + if (!isList && portal.getCreateDataAdapter() && !ObjectUtils.isEmpty(portal.getAdapterId())) { + DataAdapter dataAdapter = adapterMapper.selectById(portal.getAdapterId()); + dataAdapter.setCode(portalPublish.getCode()); + adapterMapper.updateCode(dataAdapter); + } + portalMapper.updateState(portalId, QueryConstant.PORTAL_PUBLISH); + if (PortalPremEnum.EXTERNAL.equals(portal.getPermissionType()) || PortalPremEnum.ANONYMITY.equals(portal.getPermissionType())) { + publishPortal(portal, mappings, Boolean.TRUE); + } + } + + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Long portalId) { + Portal portal = portalMapper.selectById(portalId); + if (ObjectUtils.isEmpty(portal)) { + return; + } + if (!QueryConstant.PORTAL_DEV.equals(portal.getState())) { + throw new CustomException("当前状态不允许删除"); + } + if (portal.getCreateDataAdapter()) { + adapterMapper.deleteById(portal.getAdapterId()); + } + portalMappingMapper.deleteByPortalId(portalId); + if (PortalEnum.EXTERNAL.equals(portal.getType())) { + portalInterfaceMapper.deleteById(portal.getInterfaceId()); + } + portalMapper.deleteById(portalId); + } + + /** * 发布接口 * @@ -294,15 +430,15 @@ public class PortalServiceImpl implements PortalService { * @param portal 接口信息 */ private void createDataAdapter(PortalDto portalDto, Portal portal) { - DataAdapterDto dataAdapterDto = portalDto.getDataAdapter(); - if (ObjectUtils.isEmpty(dataAdapterDto)) { + if (ObjectUtils.isEmpty(portalDto.getAdapterCodeType())) { throw new CustomException("数据适配器为空!"); } - DataAdapter dataAdapter = dataAdapterDto.toDataAdapter(); + DataAdapter dataAdapter = new DataAdapter(); + dataAdapter.setType(portalDto.getAdapterCodeType()); if (ObjectUtils.isEmpty(dataAdapter.getType())) { throw new CustomException("请选择数据适配器类型!"); } - dataAdapter.setAdapterName(portal.getPortalName() + "专用数据适配器!"); + dataAdapter.setAdapterName(portal.getPortalName() + "专用"); dataAdapter.setCommon(Boolean.FALSE); //初始化对应的数据适配器 dataAdapter.init(); @@ -312,19 +448,40 @@ public class PortalServiceImpl implements PortalService { portal.setAdapterId(dataAdapter.getAdapterId()); } + /** + * 创建第三方接口 + * + * @param portalDto 接口dto对象 + * @param portal 接口对象 + */ + private void createPortalInterface(PortalDto portalDto, Portal portal) { + PortalInterface portalInterface = new PortalInterface(); + portalInterface.setContentType(portalDto.getContentType()); + portalInterface.setRequestMethod(portalDto.getInterfaceRequestMethod()); + portalInterface.setUrl(portalDto.getUrl()); + portalInterfaceMapper.insert(portalInterface); + portal.setInterfaceId(portalInterface.getInterfaceId()); + } + + /** * 检查接口类型是否正确 * - * @param portal 接口信息 + * @param portalDto 接口信息 */ - private void checkPortalType(Portal portal) { - if (PortalEnum.LOCAL.equals(portal.getType())) { - if (ObjectUtils.isEmpty(portal.getQueryId())) { + private void checkPortalType(PortalDto portalDto) { + if (PortalEnum.LOCAL.equals(portalDto.getType())) { + if (ObjectUtils.isEmpty(portalDto.getQueryId())) { throw new CustomException("请选择查询接口!"); } - portal.setUrl(null); - } else if (PortalEnum.EXTERNAL.equals(portal.getType())) { - if (ObjectUtils.isEmpty(portal.getUrl())) { + } else if (PortalEnum.EXTERNAL.equals(portalDto.getType())) { + if (ObjectUtils.isEmpty(portalDto.getContentType())) { + throw new CustomException("外部接口请求类型不能为空"); + } + if (ObjectUtils.isEmpty(portalDto.getInterfaceRequestMethod())) { + throw new CustomException("外部接口请求方法不能为空"); + } + if (ObjectUtils.isEmpty(portalDto.getUrl())) { throw new CustomException("第三方接口地址不能为空!"); } } else { diff --git a/custom-query/custom-query-biz/src/main/resources/mapper/DataAdapterMapper.xml b/custom-query/custom-query-biz/src/main/resources/mapper/DataAdapterMapper.xml index 0b9ac8b..cff9939 100644 --- a/custom-query/custom-query-biz/src/main/resources/mapper/DataAdapterMapper.xml +++ b/custom-query/custom-query-biz/src/main/resources/mapper/DataAdapterMapper.xml @@ -20,9 +20,10 @@ select adapter_id, adapter_name, - `type`, + type, common, code, + execute_code, mock_data, create_by, create_time, @@ -35,8 +36,10 @@ @@ -58,7 +61,7 @@ insert into data_adapter adapter_name, - `type`, + type, common, code, mock_data, @@ -80,7 +83,7 @@ update data_adapter adapter_name = #{adapterName}, - `type` = #{type}, + type = #{type}, code = #{code}, mock_data = #{mockData}, update_by = #{updateBy}, @@ -89,6 +92,18 @@ where adapter_id = #{adapterId} + + update data_adapter + + code = #{code}, + execute_code = #{code}, + mock_data = #{mockData}, + update_by = #{updateBy}, + update_time = #{updateTime}, + + where adapter_id = #{adapterId} + + delete from data_adapter diff --git a/custom-query/custom-query-biz/src/main/resources/mapper/PortalInterfaceMapper.xml b/custom-query/custom-query-biz/src/main/resources/mapper/PortalInterfaceMapper.xml new file mode 100644 index 0000000..f24051c --- /dev/null +++ b/custom-query/custom-query-biz/src/main/resources/mapper/PortalInterfaceMapper.xml @@ -0,0 +1,32 @@ + + + + + + + + insert into portal_interface (interface_id, url, content_type, request_method) + values (#{interfaceId}, #{url}, #{contentType}, #{requestMethod}) + + + + update portal_interface + set content_type = #{contentType}, + url = #{url}, + request_method = #{requestMethod} + where interface_id = #{interfaceId} + + + + delete + from portal_interface + where interface_id = #{interfaceId} + + + \ No newline at end of file diff --git a/custom-query/custom-query-biz/src/main/resources/mapper/PortalMapper.xml b/custom-query/custom-query-biz/src/main/resources/mapper/PortalMapper.xml index a88c432..22f4273 100644 --- a/custom-query/custom-query-biz/src/main/resources/mapper/PortalMapper.xml +++ b/custom-query/custom-query-biz/src/main/resources/mapper/PortalMapper.xml @@ -7,14 +7,16 @@ select portal_id, query_id, + menu_id, + interface_id, adapter_id, portal_name, - anonymity, + permission_type, type, request_method, create_data_adapter, + page, path, - url, state, create_by, create_time, @@ -23,7 +25,6 @@ remark from portal - - and portal_name like concat('%', #{portalName}, '%') - and anonymity = #{anonymity} + and portal_name like concat('%', #{portalName}, '%') + + and permission_type = #{permissionType} and type = #{type} + and state = #{state} and path like concat('%', #{path}, '%') @@ -49,13 +52,14 @@ query_id, adapter_id, + interface_id, portal_name, - anonymity, + permission_type, type, + page, request_method, create_data_adapter, path, - url, state, create_by, create_time, @@ -63,16 +67,48 @@ #{queryId}, #{adapterId}, + #{interfaceId}, #{portalName}, - #{anonymity}, + #{permissionType}, #{type}, + #{page}, #{requestMethod}, #{createDataAdapter}, #{path}, - #{url}, #{state}, #{createBy}, #{createTime}, + + + update portal + + query_id = #{queryId}, + adapter_id = #{adapterId}, + interface_id = #{interfaceId}, + portal_name = #{portalName}, + permission_type = #{permissionType}, + type = #{type}, + type = #{page}, + request_method = #{requestMethod}, + create_data_adapter = #{createDataAdapter}, + path = #{path}, + update_by = #{updateBy}, + update_time = #{updateTime}, + + where portal_id = #{portalId} + + + + update portal + set state = #{state} + where portal_id = #{portalId} + + + + delete + from portal + where portal_id = #{portalId} + \ No newline at end of file diff --git a/custom-query/custom-query-biz/src/main/resources/mapper/PortalMappingMapper.xml b/custom-query/custom-query-biz/src/main/resources/mapper/PortalMappingMapper.xml index 9f6d8ab..ae5395d 100644 --- a/custom-query/custom-query-biz/src/main/resources/mapper/PortalMappingMapper.xml +++ b/custom-query/custom-query-biz/src/main/resources/mapper/PortalMappingMapper.xml @@ -4,7 +4,14 @@ "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> - select mapping_id, portal_id, mapping_key, mapping_type, mapping_value + select mapping_id, + portal_id, + mapping_key, + mapping_type, + mapping_value, + input_type, + required, + description from portal_mapping @@ -21,12 +28,13 @@ - - insert into portal_mapping (portal_id, mapping_key, mapping_type, mapping_value) + insert into portal_mapping (portal_id, mapping_key, mapping_type, mapping_value, input_type, required, + description) values - (#{item.portalId}, #{item.mappingKey}, #{item.mappingType}, #{item.mappingValue}) + (#{item.portalId}, #{item.mappingKey}, #{item.mappingType}, #{item.mappingValue}, #{item.inputType}, + #{item.required},#{item.description}) diff --git a/custom-query/custom-query-biz/src/test/java/cn/fateverse/query/ConsoleCapture.java b/custom-query/custom-query-biz/src/test/java/cn/fateverse/query/ConsoleCapture.java new file mode 100644 index 0000000..fae08b2 --- /dev/null +++ b/custom-query/custom-query-biz/src/test/java/cn/fateverse/query/ConsoleCapture.java @@ -0,0 +1,32 @@ +package cn.fateverse.query; + +import java.io.*; + + public class ConsoleCapture { + public static String captureOutput(Runnable codeToRun) throws IOException { + PrintStream originalOut = System.out; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintStream capturingOut = new PrintStream(baos); + + try { + System.setOut(capturingOut); + codeToRun.run(); + } finally { + System.setOut(originalOut); + } + + return baos.toString(); + } + + // 使用示例 + public static void main(String[] args) throws IOException { + String capturedText = captureOutput(() -> { + System.out.println("Hello, Console!"); + System.out.println("This is being captured."); + }); + + System.out.println("Captured output:"); + System.out.println(capturedText); + } + } + \ No newline at end of file diff --git a/custom-query/custom-query-biz/src/test/java/cn/fateverse/query/DataAdapter.java b/custom-query/custom-query-biz/src/test/java/cn/fateverse/query/DataAdapter.java deleted file mode 100644 index 2d5ab74..0000000 --- a/custom-query/custom-query-biz/src/test/java/cn/fateverse/query/DataAdapter.java +++ /dev/null @@ -1,14 +0,0 @@ -package cn.fateverse.query; - -import java.util.*; -import java.util.stream.*; - -public class DataAdapter { - - public static Object execute(List> data) { - for (Map objectMap : data) { - objectMap.remove("oper_location"); - } - return data; - } -} \ No newline at end of file diff --git a/custom-query/custom-query-biz/src/test/java/cn/fateverse/query/DataAdapter1100.java b/custom-query/custom-query-biz/src/test/java/cn/fateverse/query/DataAdapter1100.java new file mode 100644 index 0000000..1f8b529 --- /dev/null +++ b/custom-query/custom-query-biz/src/test/java/cn/fateverse/query/DataAdapter1100.java @@ -0,0 +1,16 @@ +package cn.fateverse.query; + +/** + * @author Clay + * @date 2024/4/22 18:59 + */ +public class DataAdapter1100 { + + public static Object execute(String data) { + for (int i = 0; i < 1000; i++) { + System.out.println(i); + } + return "qwewe"; + } + +} diff --git a/custom-query/custom-query-biz/src/test/java/cn/fateverse/query/JavaScriptParamTest.java b/custom-query/custom-query-biz/src/test/java/cn/fateverse/query/JavaScriptParamTest.java new file mode 100644 index 0000000..ff04661 --- /dev/null +++ b/custom-query/custom-query-biz/src/test/java/cn/fateverse/query/JavaScriptParamTest.java @@ -0,0 +1,77 @@ +package cn.fateverse.query; + +import cn.fateverse.common.code.engine.JavaScriptEngine; +import cn.fateverse.common.code.model.EngineResult; +import com.alibaba.fastjson2.JSONObject; +import org.graalvm.polyglot.Context; +import org.graalvm.polyglot.Value; +import org.junit.jupiter.api.Test; + +import javax.script.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; + +/** + * @author Clay + * @date 2024/4/23 9:42 + */ +public class JavaScriptParamTest { + + + static String finalCode = "function execute1(data) {\n" + + " let res = [data.length];\n" + + " for (let i = 0; i < data.length; i++) {\n" + + " console.log(data[i])\n" + + " console.log(data[i].foo)\n" + + " res[i] = data[i].foo\n" + + " }\n" + + " return res;\n" + + "}"; + + @Test + public void testParam() { + List list = new ArrayList<>(); + for (int i = 0; i < 10; i++) { + + Map param = new HashMap<>(); + param.put("foo", "sdsdsdsds"); + list.add(param); + } + + ScriptEngineManager engineManager = new ScriptEngineManager(); + ScriptEngine jsEngine = engineManager.getEngineByName("graal.js"); + Context context = Context.newBuilder() + .allowAllAccess(true) + .build(); +// Context context = Context.create(); + context.eval("js", finalCode); + + Value executeFunction = context.getBindings("js").getMember("execute1"); + Value javaObjectAsValue = Value.asValue(list); + Value result = executeFunction.execute(javaObjectAsValue); + System.out.println(result); + + } + + + @Test + public void testParam2() throws Exception { + + ScriptEngineManager engineManager = new ScriptEngineManager(); + ScriptEngine jsEngine = engineManager.getEngineByName("graal.js"); + Invocable funcCall = (Invocable) jsEngine; + Bindings bindings = jsEngine.getBindings(ScriptContext.ENGINE_SCOPE); + bindings.put("polyglot.js.allowHostAccess", true); + bindings.put("polyglot.js.allowHostClassLookup", (Predicate) s -> true); + + jsEngine.eval(finalCode); + JSONObject jsonObject = new JSONObject(); + jsonObject.put("foo", "sdsdsdsds"); + Object res= funcCall.invokeFunction("execute1", jsonObject); + + } + +} diff --git a/custom-query/custom-query-biz/src/test/java/cn/fateverse/query/JavaScriptTest.java b/custom-query/custom-query-biz/src/test/java/cn/fateverse/query/JavaScriptTest.java new file mode 100644 index 0000000..50ae687 --- /dev/null +++ b/custom-query/custom-query-biz/src/test/java/cn/fateverse/query/JavaScriptTest.java @@ -0,0 +1,122 @@ +package cn.fateverse.query; + +import cn.fateverse.common.code.config.JavaCodeProperties; +import cn.fateverse.common.code.engine.JavaCodeEngine; +import cn.fateverse.common.code.engine.JavaScriptEngine; +import cn.fateverse.common.code.model.EngineResult; + +import java.util.concurrent.FutureTask; + + +/** + * @author Clay + * @date 2024/4/22 16:04 + */ +public class JavaScriptTest { + public static void main(String[] args) throws Exception { + String code = "function execute(data) {\n" + + " console.log(data)\n" + + " console.log(\"test console!\")\n" + + " let add = (a, b) => a + b; // 使用箭头函数\n" + + " console.log(\"Adding 5 and 3:\", add(5, 3));\n\n" + + " for (let i = 0; i < 1000; i++) {\n" + + " console.log(i)\n" + + " }" + + " return \"success\";\n" + + "}"; + + + JavaCodeProperties properties = new JavaCodeProperties(); + properties.setClassPath("C:\\home\\clay\\code\\"); + JavaCodeEngine javaCodeEngine = new JavaCodeEngine(properties); + + +// EngineResult executeScript = JavaScriptEngine.executeScript(code, "execute", "测试控制台输出"); + + String finalCode = "function execute(data) {\n" + + " console.log(data)\n" + + " console.log(\"test console!\")\n" + + " let add = (a, b) => a + b; // 使用箭头函数\n" + + " console.log(\"Adding 5 and 3:\", add(5, 3));\n\n" + + " for (let i = 0; i < 1000; i++) {\n" + + " console.log(i)\n" + + " }" + + " return \"success\";\n" + + "}"; + FutureTask engineResultFutureTask = new FutureTask<>(() -> { + return JavaScriptEngine.execute(finalCode, "execute", false, "测试控制台输出"); + }); + + + String finalCode1 = "import java.util.*;\n" + + "import java.util.stream.*;\n" + + "\n" + + "public class DataAdapter100 {" + + "\n" + + " public static Object execute(String data) {\n" + + " for (int i = 0; i < 1000; i++) {\n" + + " System.out.println(i);\n" + + " }\n" + + " return \"qwewe\";\n" + + " }" + + "}\n"; + FutureTask engineResultFutureTask1 = new FutureTask<>(() -> { + return javaCodeEngine.execute(finalCode1, "DataAdapter100", "execute", new Class[]{String.class}, new Object[]{"test"}, true); + }); + new Thread(engineResultFutureTask).start(); + new Thread(engineResultFutureTask1).start(); +// EngineResult execute = javaCodeEngine.execute(code, "DataAdapter100", "execute", new Class[]{String.class}, new Object[]{"test"}, true); + + + EngineResult x = engineResultFutureTask.get(); + EngineResult x1 = engineResultFutureTask1.get(); + System.out.println(x); + System.out.println(x1); + + +// EngineResult capture = MultiThreadedCapture.capture(() -> { +// ScriptEngine engine = new ScriptEngineManager().getEngineByName("graal.js"); +// Invocable inv = (Invocable) engine; +// try { +// engine.eval(finalCode); +// return inv.invokeFunction("execute", "args"); +// } catch (ScriptException | NoSuchMethodException e) { +// throw new RuntimeException(e); +// } +// }); +// System.out.println(capture); +// EngineResult objectEngineResult = JavaScriptEngine.executeScript(finalCode, "execute", "测试控制台输出"); +// +// ByteArrayOutputStream baos = new ByteArrayOutputStream(); +// PrintStream oldOut = System.out; +// System.setOut(new PrintStream(baos)); + + +// EngineResult capture = MultiThreadedCapture.capture(() -> { +// int someNumber = 42; +// System.out.println(someNumber); +// return null; +// }); + + + // 执行产生数值输出的代码 +// System.out.println(objectEngineResult); +// ScriptEngine engine = JavaScriptEngine.getEngine(); +// Invocable inv = (Invocable) engine; +// engine.eval(finalCode); +// inv.invokeFunction("execute", "args"); +// System.out.println(capture); + +// MultiThreadedCapture.executor.shutdown(); + // 恢复标准输出流 +// System.setOut(oldOut); +// +// System.setOut(oldOut); +// // 从捕获的字节数组输出流中获取打印的文本 +// String capturedOutput = baos.toString(); +// System.out.println("Captured output: " + capturedOutput); + + } + + +} diff --git a/custom-query/custom-query-biz/src/test/java/cn/fateverse/query/Main.java b/custom-query/custom-query-biz/src/test/java/cn/fateverse/query/Main.java new file mode 100644 index 0000000..9749c38 --- /dev/null +++ b/custom-query/custom-query-biz/src/test/java/cn/fateverse/query/Main.java @@ -0,0 +1,38 @@ +package cn.fateverse.query; + +import org.graalvm.polyglot.Context; +import org.graalvm.polyglot.Value; + +public class Main { + public static void main(String[] args) { + // 创建 GraalVM 上下文 + Context context = Context.create(); + + // 定义一个 JavaScript 函数 + String script = "function execute(data) {\n" + + " console.log(data)\n" + + " console.log(\"test console!\")\n" + + " let add = (a, b) => a + b; // 使用箭头函数\n" + + " console.log(\"Adding 5 and 3:\", add(5, 3));\n\n" + + " for (let i = 0; i < 1000; i++) {\n" + + " console.log(i)\n" + + " }" + + " return \"success\";\n" + + "}"; + + // 编译 JavaScript 函数 + context.eval("js", script); + + // 获取函数对象 + Value addFunction = context.getBindings("js").getMember("execute"); + + // 执行函数并传入参数 + Value result = addFunction.execute("测试"); + Value result2 = addFunction.execute("测试"); + // 获取返回值 +// int sum = result.asInt(); + + // 输出结果 + System.out.println("Sum: "); // 输出:Sum: 5 + } +} diff --git a/custom-query/custom-query-biz/src/test/java/cn/fateverse/query/SystemOut.java b/custom-query/custom-query-biz/src/test/java/cn/fateverse/query/SystemOut.java new file mode 100644 index 0000000..5b6e8e2 --- /dev/null +++ b/custom-query/custom-query-biz/src/test/java/cn/fateverse/query/SystemOut.java @@ -0,0 +1,45 @@ +package cn.fateverse.query; + +import cn.fateverse.common.code.engine.JavaScriptEngine; +import cn.fateverse.common.code.model.EngineResult; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; + +public class SystemOut { + public static void outTest() { + ByteArrayOutputStream baoStream = new ByteArrayOutputStream(1024); + PrintStream cacheStream = new PrintStream(baoStream);//临时输出 + PrintStream oldStream = System.out;//缓存系统输出 + System.setOut(cacheStream); + System.out.print("...");//不会打印到控制台 + String result = baoStream.toString();//存放控制台输出的字符串 + System.setOut(oldStream);//还原到系统输出 + System.out.println("result"); + } + + public static void main(String[] args) { +// outTest(); + + String finalCode = "function execute1(data) {\n" + + " console.log(data)\n" + + " console.log(\"test console!\")\n" + + " let add = (a, b) => a + b; // 使用箭头函数\n" + + " console.log(\"Adding 5 and 3:\", add(5, 3));\n\n" + + " for (let i = 0; i < 1000; i++) {\n" + + " console.log(i)\n" + + " }" + + " return \"success\";\n" + + "}"; +// String finalCode = "function myFunction() { return 'Hello, world!'; }"; + long start1 = System.currentTimeMillis(); + EngineResult execute = JavaScriptEngine.execute(finalCode, "execute1", false, "测试控制台输出"); + long start2 = System.currentTimeMillis(); + EngineResult execute1 = JavaScriptEngine.execute(finalCode, "execute1", false, "测试控制台输出"); + long start3 = System.currentTimeMillis(); + System.out.println("耗时1:" + (start2 - start1) + "ms"); + System.out.println("耗时2:" + (start3 - start2) + "ms"); + System.out.println(execute); + + } +} \ No newline at end of file diff --git a/start.sh b/start.sh index 40e1080..3fffc9c 100644 --- a/start.sh +++ b/start.sh @@ -31,13 +31,13 @@ batch=${DRONE_COMMIT_BRANCH} ignoreArr=("monitor","sentinel-dashboard-pro","sentinel-dashboard") -#if [[ "${ignoreArr[*]}" =~ "${batch}" ]]; then -# JAVA_AGENT="-javaagent:/home/clay/skywalking-agent/skywalking-agent.jar -Dskywalking.agent.service_name=$DRONE_COMMIT_BRANCH -Dskywalking.trace.ignore_path=/actuator/** -Dskywalking.collector.backend_service=10.7.89.101:11800 --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dio.netty.tryReflectionSetAccessible=true" -# nohup java -jar $JAVA_AGENT $JAVA_OPTS $JAVA_MEM_OPTS $DRONE_COMMIT_BRANCH.jar --spring.profiles.active=pro --server.port=8080 >./logs/spring.log 2>&1 & -#else -# echo "exist"; -# nohup java -jar $JAVA_OPTS $JAVA_MEM_OPTS $DRONE_COMMIT_BRANCH.jar --spring.profiles.active=pro --server.port=8080 >./logs/spring.log 2>&1 & -#fi +if [[ "${ignoreArr[*]}" =~ "${batch}" ]]; then + JAVA_AGENT="-javaagent:/home/clay/skywalking-agent/skywalking-agent.jar -Dskywalking.agent.service_name=$DRONE_COMMIT_BRANCH -Dskywalking.trace.ignore_path=/actuator/** -Dskywalking.collector.backend_service=10.7.125.151:11800 --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dio.netty.tryReflectionSetAccessible=true" + nohup java -jar $JAVA_AGENT $JAVA_OPTS $JAVA_MEM_OPTS $DRONE_COMMIT_BRANCH.jar --spring.profiles.active=pro --server.port=8080 >./logs/spring.log 2>&1 & +else + echo "exist"; + nohup java -jar $JAVA_OPTS $JAVA_MEM_OPTS $DRONE_COMMIT_BRANCH.jar --spring.profiles.active=pro --server.port=8080 >./logs/spring.log 2>&1 & +fi nohup java -jar $JAVA_OPTS $JAVA_MEM_OPTS $DRONE_COMMIT_BRANCH.jar --spring.profiles.active=pro --server.port=8080 >./logs/spring.log 2>&1 & diff --git a/workflow/src/main/java/cn/fateverse/workflow/process/TriggerService.java b/workflow/src/main/java/cn/fateverse/workflow/process/TriggerService.java index 5db6c3c..3e62d8e 100644 --- a/workflow/src/main/java/cn/fateverse/workflow/process/TriggerService.java +++ b/workflow/src/main/java/cn/fateverse/workflow/process/TriggerService.java @@ -162,10 +162,10 @@ public class TriggerService { try { //判断请求是否有效 if (response.getStatusCode() == HttpStatus.OK) { - jsResult = JavaScriptEngine.executeScript(http.getSuccess(), "handlerSuccess", result); + jsResult = (ScriptObjectMirror) JavaScriptEngine.execute(http.getSuccess(), "handlerSuccess", result); operation.setState(OperationStateEnums.SUCCESS); } else { - jsResult = JavaScriptEngine.executeScript(http.getFail(), "handlerFail", result); + jsResult = (ScriptObjectMirror) JavaScriptEngine.execute(http.getFail(), "handlerFail", result); operation.setState(OperationStateEnums.FAILURE); } } catch (Exception e) {