Merge pull request 'perf : 引擎优化' (#84) from portal into master
Reviewed-on: http://git.feashow.cn/clay/fateverse/pulls/84
This commit is contained in:
@@ -13,8 +13,8 @@ import org.springframework.context.annotation.Bean;
|
|||||||
public class JavaCodeAutoConfiguration {
|
public class JavaCodeAutoConfiguration {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public JavaCodeEngine javaCodeEngine(JavaCodeProperties javaCodeProperties){
|
public JavaCodeEngine javaCodeEngine(JavaCodeProperties javaCodeProperties) {
|
||||||
return new JavaCodeEngine(javaCodeProperties);
|
return new JavaCodeEngine(javaCodeProperties.getClassPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,19 +5,22 @@ import cn.fateverse.common.core.exception.CustomException;
|
|||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.util.concurrent.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 控制台输出捕获
|
||||||
|
*
|
||||||
* @author Clay
|
* @author Clay
|
||||||
* @date 2024/4/22 17:08
|
* @date 2024/4/22 17:08
|
||||||
*/
|
*/
|
||||||
public class MultiThreadedCapture {
|
public class ConsoleCapture {
|
||||||
|
|
||||||
|
|
||||||
private final static ExecutorService executor = Executors.newFixedThreadPool(2);
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 捕获方法
|
||||||
|
*
|
||||||
|
* @param task 任務
|
||||||
|
* @return 返回结果
|
||||||
|
*/
|
||||||
public static EngineResult capture(Task task) {
|
public static EngineResult capture(Task task) {
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
PrintStream oldOut = System.out;
|
PrintStream oldOut = System.out;
|
||||||
@@ -27,7 +30,7 @@ public class MultiThreadedCapture {
|
|||||||
try {
|
try {
|
||||||
result = task.execute();
|
result = task.execute();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (e instanceof CustomException){
|
if (e instanceof CustomException) {
|
||||||
throw (CustomException) e;
|
throw (CustomException) e;
|
||||||
}
|
}
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
@@ -1,17 +1,16 @@
|
|||||||
package cn.fateverse.common.code.engine;
|
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.console.MultiThreadedCapture;
|
|
||||||
import cn.fateverse.common.code.exception.SandboxClassNotFoundException;
|
import cn.fateverse.common.code.exception.SandboxClassNotFoundException;
|
||||||
import cn.fateverse.common.code.lock.SegmentLock;
|
import cn.fateverse.common.code.lock.SegmentLock;
|
||||||
import cn.fateverse.common.code.model.EngineResult;
|
import cn.fateverse.common.code.model.EngineResult;
|
||||||
import cn.fateverse.common.code.sandbox.SandboxClassLoader;
|
import cn.fateverse.common.code.sandbox.SandboxClassLoader;
|
||||||
import cn.fateverse.common.code.sandbox.SandboxSecurityManager;
|
import cn.fateverse.common.code.sandbox.SandboxSecurityManager;
|
||||||
import cn.fateverse.common.core.exception.CustomException;
|
import cn.fateverse.common.core.exception.CustomException;
|
||||||
|
import lombok.Getter;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
import javax.tools.JavaCompiler;
|
import javax.tools.JavaCompiler;
|
||||||
@@ -39,9 +38,7 @@ public class JavaCodeEngine {
|
|||||||
|
|
||||||
private final URL url;
|
private final URL url;
|
||||||
|
|
||||||
private final URLClassLoader classLoader;
|
private final Map<String, CacheWrapper> classCache = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
private final Map<String, Class<?>> classCache = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
|
|
||||||
private final SandboxSecurityManager securityManager = new SandboxSecurityManager(classCache);
|
private final SandboxSecurityManager securityManager = new SandboxSecurityManager(classCache);
|
||||||
@@ -50,53 +47,31 @@ public class JavaCodeEngine {
|
|||||||
private final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
|
private final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
|
||||||
|
|
||||||
|
|
||||||
public JavaCodeEngine(JavaCodeProperties javaCodeProperties) {
|
public JavaCodeEngine(String classPath) {
|
||||||
try {
|
try {
|
||||||
CLASS_PATH = javaCodeProperties.getClassPath();
|
CLASS_PATH = classPath;
|
||||||
File file = new File(CLASS_PATH);
|
File file = new File(CLASS_PATH);
|
||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
file.mkdirs();
|
file.mkdirs();
|
||||||
}
|
}
|
||||||
url = file.toURI().toURL();
|
url = file.toURI().toURL();
|
||||||
classLoader = new SandboxClassLoader(new URL[]{url});
|
|
||||||
} catch (MalformedURLException e) {
|
} catch (MalformedURLException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 执行方法
|
|
||||||
*
|
|
||||||
* @param code 代码字符串
|
|
||||||
* @param className 类名
|
|
||||||
* @param methodName 方法名
|
|
||||||
* @param paramClass 参数类型数组
|
|
||||||
* @param args 参数数组
|
|
||||||
* @param development 是否为开发环境 开发环境下会将生成的类在执行完成后删除,不是生产环境则会缓存提高运行效率
|
|
||||||
* @return 执行结果
|
|
||||||
*/
|
|
||||||
public EngineResult 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 code 需要执行的代码字符串
|
||||||
* @param className 类名
|
* @param className 类名
|
||||||
* @param methodName 方法名
|
* @param methodName 方法名
|
||||||
* @param paramClass 参数类型数组
|
|
||||||
* @param args 参数数组
|
* @param args 参数数组
|
||||||
* @return 执行结构
|
* @return 执行结构
|
||||||
*/
|
*/
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
private EngineResult 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;
|
Class<?> loadClass = null;
|
||||||
try {
|
try {
|
||||||
// 加锁,确保类只加载一次
|
// 加锁,确保类只加载一次
|
||||||
@@ -106,12 +81,12 @@ public class JavaCodeEngine {
|
|||||||
// 创建一个URLClassLoader,用于加载代码字符串
|
// 创建一个URLClassLoader,用于加载代码字符串
|
||||||
tempClassLoader = new URLClassLoader(new URL[]{url});
|
tempClassLoader = new URLClassLoader(new URL[]{url});
|
||||||
// 编译代码字符串为类
|
// 编译代码字符串为类
|
||||||
Class<?> tempClass = compilerClass(className, code, tempClassLoader);
|
return compilerClass(className, code, tempClassLoader);
|
||||||
// 将编译好的类放入缓存
|
|
||||||
classCache.put(className, tempClass);
|
|
||||||
return tempClass;
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
if (e instanceof CustomException) {
|
||||||
|
throw (CustomException) e;
|
||||||
|
}
|
||||||
// 异常处理,并抛出自定义的SandboxClassNotFoundException异常
|
// 异常处理,并抛出自定义的SandboxClassNotFoundException异常
|
||||||
throw new SandboxClassNotFoundException(e.getMessage());
|
throw new SandboxClassNotFoundException(e.getMessage());
|
||||||
} finally {
|
} finally {
|
||||||
@@ -121,15 +96,17 @@ public class JavaCodeEngine {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
// 获取需要执行的方法
|
// 获取需要执行的方法
|
||||||
Method method = loadClass.getMethod(methodName, paramClass);
|
Method method = getMethod(methodName, loadClass);
|
||||||
// 设置安全检查器
|
// 设置安全检查器
|
||||||
System.setSecurityManager(securityManager);
|
System.setSecurityManager(securityManager);
|
||||||
// 执行方法并返回结果
|
// 执行方法并返回结果
|
||||||
return MultiThreadedCapture.capture(() -> 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 {
|
} finally {
|
||||||
// 从缓存中移除编译好的类
|
|
||||||
classCache.remove(className);
|
|
||||||
// 清空安全检查器
|
// 清空安全检查器
|
||||||
System.setSecurityManager(null);
|
System.setSecurityManager(null);
|
||||||
if (loadClass != null) {
|
if (loadClass != null) {
|
||||||
@@ -156,37 +133,53 @@ public class JavaCodeEngine {
|
|||||||
* @param code 需要执行的代码字符串
|
* @param code 需要执行的代码字符串
|
||||||
* @param className 类名
|
* @param className 类名
|
||||||
* @param methodName 方法名
|
* @param methodName 方法名
|
||||||
* @param paramClass 参数类型数组
|
|
||||||
* @param args 参数数组
|
* @param args 参数数组
|
||||||
* @return 执行结构
|
* @return 执行结构
|
||||||
*/
|
*/
|
||||||
private EngineResult onlineExecute(String code, String className, String methodName, Class<?>[] paramClass, Object[] args) {
|
public Object execute(String code, String className, String methodName, Object[] args) {
|
||||||
try {
|
try {
|
||||||
Class<?> loadClass = null;
|
Class<?> loadClass = null;
|
||||||
loadClass = classCache.get(className);
|
//从缓存中获取
|
||||||
if (loadClass == null) {
|
CacheWrapper wrapper = classCache.get(className);
|
||||||
loadClass = getLoadClass(code, className);
|
//缓存中不存在
|
||||||
Method method = loadClass.getMethod(methodName, paramClass);
|
if (wrapper == null) {
|
||||||
System.setSecurityManager(securityManager);
|
//加载
|
||||||
Object result = (Object) method.invoke(null, args);
|
wrapper = getLoadClass(code, className);
|
||||||
return new EngineResult(result);
|
|
||||||
}
|
}
|
||||||
|
//获取到类信息
|
||||||
|
loadClass = wrapper.getClazz();
|
||||||
|
//获取方法
|
||||||
|
Method method = getMethod(methodName, loadClass);
|
||||||
|
//开启安全模式
|
||||||
|
System.setSecurityManager(securityManager);
|
||||||
|
//执行方法
|
||||||
|
return method.invoke(null, args);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
remove(className);
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
} finally {
|
} finally {
|
||||||
System.setSecurityManager(null);
|
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;
|
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对象
|
* 获取到编译完成的Class对象
|
||||||
*
|
*
|
||||||
@@ -194,15 +187,18 @@ public class JavaCodeEngine {
|
|||||||
* @param className 类名
|
* @param className 类名
|
||||||
* @return 编译后的Java对象
|
* @return 编译后的Java对象
|
||||||
*/
|
*/
|
||||||
private Class<?> getLoadClass(String code, String className) {
|
private CacheWrapper getLoadClass(String code, String className) {
|
||||||
//使用分段锁,提高效率,放多并发情况下多次对同一个类进行编译
|
//使用分段锁,提高效率,放多并发情况下多次对同一个类进行编译
|
||||||
return SegmentLock.lock(className, () -> {
|
return SegmentLock.lock(className, () -> {
|
||||||
try {
|
try {
|
||||||
|
URLClassLoader classLoader = new SandboxClassLoader(new URL[]{url});
|
||||||
//执行编译
|
//执行编译
|
||||||
Class<?> tempClass = compilerClass(className, code, classLoader);
|
Class<?> tempClass = compilerClass(className, code, classLoader);
|
||||||
|
//创建缓存包装对象
|
||||||
|
CacheWrapper wrapper = new CacheWrapper(tempClass, classLoader);
|
||||||
//将编译之后的类对象放在缓存中,提高线上环境的运行效率
|
//将编译之后的类对象放在缓存中,提高线上环境的运行效率
|
||||||
classCache.put(className, tempClass);
|
classCache.put(className, wrapper);
|
||||||
return tempClass;
|
return wrapper;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@@ -248,11 +244,19 @@ public class JavaCodeEngine {
|
|||||||
*/
|
*/
|
||||||
public Boolean remove(String className) {
|
public Boolean remove(String className) {
|
||||||
return SegmentLock.lock(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);
|
File javaFile = new File(CLASS_PATH + className + JAVA_SUFFIX);
|
||||||
if (javaFile.exists()) {
|
if (javaFile.exists()) {
|
||||||
javaFile.delete();
|
javaFile.delete();
|
||||||
}
|
}
|
||||||
|
//删除class文件
|
||||||
File classFile = new File(CLASS_PATH + className + CLASS_SUFFIX);
|
File classFile = new File(CLASS_PATH + className + CLASS_SUFFIX);
|
||||||
if (classFile.exists()) {
|
if (classFile.exists()) {
|
||||||
classFile.delete();
|
classFile.delete();
|
||||||
@@ -260,4 +264,24 @@ public class JavaCodeEngine {
|
|||||||
return true;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
package cn.fateverse.common.code.engine;
|
package cn.fateverse.common.code.engine;
|
||||||
|
|
||||||
import cn.fateverse.common.code.console.MultiThreadedCapture;
|
import cn.fateverse.common.code.console.ConsoleCapture;
|
||||||
import cn.fateverse.common.code.lock.SegmentLock;
|
import cn.fateverse.common.code.lock.SegmentLock;
|
||||||
import cn.fateverse.common.code.model.EngineResult;
|
import cn.fateverse.common.code.model.EngineResult;
|
||||||
import cn.fateverse.common.core.exception.CustomException;
|
import cn.fateverse.common.core.exception.CustomException;
|
||||||
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSON;
|
||||||
import org.graalvm.polyglot.Context;
|
import org.graalvm.polyglot.Context;
|
||||||
import org.graalvm.polyglot.Value;
|
import org.graalvm.polyglot.Value;
|
||||||
import org.springframework.security.core.parameters.P;
|
|
||||||
|
|
||||||
import javax.script.*;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -42,9 +40,16 @@ public class JavaScriptEngine {
|
|||||||
* @param args 参数
|
* @param args 参数
|
||||||
* @return 返回结构
|
* @return 返回结构
|
||||||
*/
|
*/
|
||||||
public static EngineResult execute(String script, String functionName, boolean development, Object args) {
|
public static Object execute(String script, String functionName, Object args) {
|
||||||
if (development) {
|
Value executeFunction = getFunction(functionName, script);
|
||||||
return MultiThreadedCapture.capture(() -> {
|
Value result = executeFunction.execute(JSON.toJSONString(args));
|
||||||
|
return result.as(Object.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static EngineResult mockExecute(String script, String functionName, Object args) {
|
||||||
|
try {
|
||||||
|
return ConsoleCapture.capture(() -> {
|
||||||
Context context = Context.newBuilder()
|
Context context = Context.newBuilder()
|
||||||
.allowAllAccess(true)
|
.allowAllAccess(true)
|
||||||
// .allowHostClassLoading(true)
|
// .allowHostClassLoading(true)
|
||||||
@@ -63,10 +68,11 @@ public class JavaScriptEngine {
|
|||||||
Value result = executeFunction.execute(javaObjectAsValue);
|
Value result = executeFunction.execute(javaObjectAsValue);
|
||||||
return result.as(Object.class);
|
return result.as(Object.class);
|
||||||
});
|
});
|
||||||
} else {
|
}catch (CustomException e){
|
||||||
Value executeFunction = getFunction(functionName, script);
|
EngineResult result = new EngineResult();
|
||||||
Value result = executeFunction.execute(JSON.toJSONString(args));
|
result.setSuccess(Boolean.FALSE);
|
||||||
return new EngineResult(result.as(Object.class));
|
result.setConsole(e.getMessage());
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import java.util.concurrent.locks.ReentrantLock;
|
|||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 分段锁对象
|
||||||
|
*
|
||||||
* @author Clay
|
* @author Clay
|
||||||
* @date 2023-10-25
|
* @date 2023-10-25
|
||||||
*/
|
*/
|
||||||
@@ -15,10 +17,11 @@ public class SegmentLock {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 分段锁
|
* 分段锁
|
||||||
* @param key 锁名称
|
*
|
||||||
|
* @param key 锁名称
|
||||||
* @param supplier 需要执行的函数
|
* @param supplier 需要执行的函数
|
||||||
|
* @param <T> 接收泛型
|
||||||
* @return 执行后的结果
|
* @return 执行后的结果
|
||||||
* @param <T> 接收泛型
|
|
||||||
*/
|
*/
|
||||||
public static <T> T lock(String key, Supplier<T> supplier) {
|
public static <T> T lock(String key, Supplier<T> supplier) {
|
||||||
ReentrantLock lock = lockMap.get(key);
|
ReentrantLock lock = lockMap.get(key);
|
||||||
|
|||||||
@@ -18,8 +18,11 @@ public class EngineResult {
|
|||||||
|
|
||||||
private String console;
|
private String console;
|
||||||
|
|
||||||
|
private Boolean success;
|
||||||
|
|
||||||
public EngineResult(Object result) {
|
public EngineResult(Object result, String console) {
|
||||||
|
success = true;
|
||||||
this.result = result;
|
this.result = result;
|
||||||
|
this.console = console;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package cn.fateverse.common.code.sandbox;
|
package cn.fateverse.common.code.sandbox;
|
||||||
|
|
||||||
|
import cn.fateverse.common.code.engine.JavaCodeEngine;
|
||||||
|
|
||||||
import java.io.FilePermission;
|
import java.io.FilePermission;
|
||||||
import java.lang.reflect.ReflectPermission;
|
import java.lang.reflect.ReflectPermission;
|
||||||
import java.security.Permission;
|
import java.security.Permission;
|
||||||
@@ -9,9 +11,9 @@ import java.util.Set;
|
|||||||
|
|
||||||
public class SandboxSecurityManager extends SecurityManager {
|
public class SandboxSecurityManager extends SecurityManager {
|
||||||
|
|
||||||
private final Map<String, Class<?>> classCache;
|
private final Map<String, JavaCodeEngine.CacheWrapper> classCache;
|
||||||
|
|
||||||
public SandboxSecurityManager(Map<String, Class<?>> classCache) {
|
public SandboxSecurityManager(Map<String, JavaCodeEngine.CacheWrapper> classCache) {
|
||||||
this.classCache = classCache;
|
this.classCache = classCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,7 +40,7 @@ public class SandboxSecurityManager extends SecurityManager {
|
|||||||
|
|
||||||
private boolean isAllowedPermission(Permission permission) {
|
private boolean isAllowedPermission(Permission permission) {
|
||||||
//权限:用于校验文件系统访问权限,包括读取、写入、删除文件,以及目录操作。权限名称可能包括文件路径和操作,如 "read", "write", "delete", "execute" 等。
|
//权限:用于校验文件系统访问权限,包括读取、写入、删除文件,以及目录操作。权限名称可能包括文件路径和操作,如 "read", "write", "delete", "execute" 等。
|
||||||
if (permission instanceof FilePermission){
|
if (permission instanceof FilePermission) {
|
||||||
System.out.println("触发文件读写权限");
|
System.out.println("触发文件读写权限");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package cn.fateverse.common.security.filter;
|
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.service.TokenService;
|
||||||
import cn.fateverse.common.security.entity.LoginUser;
|
import cn.fateverse.common.security.entity.LoginUser;
|
||||||
import cn.fateverse.common.security.utils.SecurityUtils;
|
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.authentication.UsernamePasswordAuthenticationToken;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||||
|
import org.springframework.util.ObjectUtils;
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
|||||||
@@ -69,10 +69,11 @@ public class DataAdapter extends BaseEntity {
|
|||||||
this.code = "\n" +
|
this.code = "\n" +
|
||||||
"import java.util.*;\n" +
|
"import java.util.*;\n" +
|
||||||
"import java.util.stream.*;\n" +
|
"import java.util.stream.*;\n" +
|
||||||
|
"import com.alibaba.fastjson2.*;\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"public class DataAdapter {\n" +
|
"public class DataAdapter {\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
" public static Object execute(List<Map<String, Object>> data) {\n" +
|
" public static Object execute(Object data) {\n" +
|
||||||
" return data;\n" +
|
" return data;\n" +
|
||||||
" }\n" +
|
" }\n" +
|
||||||
"}\n";
|
"}\n";
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ public class PortalBo implements Serializable {
|
|||||||
private Boolean createDataAdapter;
|
private Boolean createDataAdapter;
|
||||||
private Boolean page;
|
private Boolean page;
|
||||||
private String path;
|
private String path;
|
||||||
private String url;
|
|
||||||
private Integer state;
|
private Integer state;
|
||||||
private List<PortalMapping> mappings;
|
private List<PortalMapping> mappings;
|
||||||
|
|
||||||
|
|||||||
@@ -29,5 +29,7 @@ public class MockParam {
|
|||||||
private String key;
|
private String key;
|
||||||
|
|
||||||
private Object value;
|
private Object value;
|
||||||
|
|
||||||
|
private String type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ public abstract class AbstractDataAdapterHandler implements DataAdapterHandler {
|
|||||||
this.handlerReader = handlerReader;
|
this.handlerReader = handlerReader;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Object execute(Long adapterId, Object data, boolean development) {
|
protected Object execute(Long adapterId, Object data) {
|
||||||
if (ObjectUtils.isEmpty(adapterId)) {
|
if (ObjectUtils.isEmpty(adapterId)) {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
@@ -33,15 +33,15 @@ public abstract class AbstractDataAdapterHandler implements DataAdapterHandler {
|
|||||||
throw new RuntimeException("dataAdapter is null");
|
throw new RuntimeException("dataAdapter is null");
|
||||||
}
|
}
|
||||||
handlerReader.preconditioning(dataAdapter);
|
handlerReader.preconditioning(dataAdapter);
|
||||||
EngineResult execute = handlerReader.execute(dataAdapter, data, development);
|
Object result = handlerReader.execute(dataAdapter, data);
|
||||||
if (ObjectUtils.isEmpty(execute)) {
|
if (ObjectUtils.isEmpty(result)) {
|
||||||
throw new RuntimeException("执行结果错误");
|
throw new RuntimeException("执行结果错误");
|
||||||
}
|
}
|
||||||
return execute.getResult();
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected EngineResult mockExecute(Long adapterId, String code, Object data, boolean development) {
|
protected EngineResult mockExecute(Long adapterId, String code, Object data) {
|
||||||
//获取当当前接口对应的数据适配器
|
//获取当当前接口对应的数据适配器
|
||||||
DataAdapter dataAdapter = dataAdapterMapper.selectById(adapterId);
|
DataAdapter dataAdapter = dataAdapterMapper.selectById(adapterId);
|
||||||
if (ObjectUtils.isEmpty(dataAdapter)) {
|
if (ObjectUtils.isEmpty(dataAdapter)) {
|
||||||
@@ -49,7 +49,7 @@ public abstract class AbstractDataAdapterHandler implements DataAdapterHandler {
|
|||||||
}
|
}
|
||||||
dataAdapter.setCode(code);
|
dataAdapter.setCode(code);
|
||||||
handlerReader.preconditioning(dataAdapter);
|
handlerReader.preconditioning(dataAdapter);
|
||||||
EngineResult execute = handlerReader.execute(dataAdapter, data, development);
|
EngineResult execute = handlerReader.mockExecute(dataAdapter, data);
|
||||||
if (ObjectUtils.isEmpty(execute)) {
|
if (ObjectUtils.isEmpty(execute)) {
|
||||||
throw new RuntimeException("执行结果错误");
|
throw new RuntimeException("执行结果错误");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
package cn.fateverse.query.handler.adapter.impl;
|
package cn.fateverse.query.handler.adapter.impl;
|
||||||
|
|
||||||
import cn.fateverse.common.core.exception.CustomException;
|
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.dto.MockParam;
|
||||||
import cn.fateverse.query.entity.bo.PortalBo;
|
import cn.fateverse.query.entity.bo.PortalBo;
|
||||||
import cn.fateverse.query.enums.PortalEnum;
|
import cn.fateverse.query.enums.PortalEnum;
|
||||||
import cn.fateverse.query.handler.adapter.AbstractDataAdapterHandler;
|
import cn.fateverse.query.handler.adapter.AbstractDataAdapterHandler;
|
||||||
import cn.fateverse.query.handler.reader.EngineExecuteHandlerReader;
|
import cn.fateverse.query.handler.reader.EngineExecuteHandlerReader;
|
||||||
import cn.fateverse.query.mapper.DataAdapterMapper;
|
import cn.fateverse.query.mapper.DataAdapterMapper;
|
||||||
|
import cn.fateverse.query.mapper.PortalInterfaceMapper;
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
@@ -17,6 +20,7 @@ import org.springframework.web.client.RestTemplate;
|
|||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Clay
|
* @author Clay
|
||||||
@@ -31,11 +35,15 @@ public class ExternalDataAdapterHandler extends AbstractDataAdapterHandler {
|
|||||||
*/
|
*/
|
||||||
private final RestTemplate restTemplate;
|
private final RestTemplate restTemplate;
|
||||||
|
|
||||||
public ExternalDataAdapterHandler(DataAdapterMapper dataAdapterMapper,
|
private final PortalInterfaceMapper portalInterfaceMapper;
|
||||||
|
|
||||||
|
public ExternalDataAdapterHandler(RestTemplate restTemplate,
|
||||||
|
DataAdapterMapper dataAdapterMapper,
|
||||||
EngineExecuteHandlerReader handlerReader,
|
EngineExecuteHandlerReader handlerReader,
|
||||||
RestTemplate restTemplate) {
|
PortalInterfaceMapper portalInterfaceMapper) {
|
||||||
super(dataAdapterMapper, handlerReader);
|
super(dataAdapterMapper, handlerReader);
|
||||||
this.restTemplate = restTemplate;
|
this.restTemplate = restTemplate;
|
||||||
|
this.portalInterfaceMapper = portalInterfaceMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -44,18 +52,28 @@ public class ExternalDataAdapterHandler extends AbstractDataAdapterHandler {
|
|||||||
if (!PortalEnum.EXTERNAL.equals(portal.getType())) {
|
if (!PortalEnum.EXTERNAL.equals(portal.getType())) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
PortalInterface portalInterface = portalInterfaceMapper.selectById(portal.getInterfaceId());
|
||||||
|
if (ObjectUtils.isEmpty(portalInterface)) {
|
||||||
|
throw new CustomException("接口不存在");
|
||||||
|
}
|
||||||
HttpHeaders headers = new HttpHeaders();
|
HttpHeaders headers = new HttpHeaders();
|
||||||
MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
|
MediaType type = MediaType.parseMediaType(portalInterface.getContentType());
|
||||||
headers.setContentType(type);
|
headers.setContentType(type);
|
||||||
headers.add("Accept", MediaType.APPLICATION_JSON.toString());
|
Map<String, Object> requestParams = new HashMap<>();
|
||||||
HashMap<String, Object> map = 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;
|
JSONObject response = null;
|
||||||
switch (portal.getRequestMethod()) {
|
switch (portalInterface.getRequestMethod()) {
|
||||||
case "GET":
|
case "GET":
|
||||||
response = restTemplate.getForObject(portal.getUrl(), JSONObject.class, map);
|
response = restTemplate.getForObject(portalInterface.getUrl(), JSONObject.class, requestParams);
|
||||||
break;
|
break;
|
||||||
case "POST":
|
case "POST":
|
||||||
response = restTemplate.postForObject(portal.getUrl(), map, JSONObject.class);
|
response = restTemplate.postForObject(portalInterface.getUrl(), requestParams, JSONObject.class);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new CustomException("请求方式错误");
|
throw new CustomException("请求方式错误");
|
||||||
@@ -63,12 +81,49 @@ public class ExternalDataAdapterHandler extends AbstractDataAdapterHandler {
|
|||||||
if (ObjectUtils.isEmpty(portal.getAdapterId()) || !portal.getCreateDataAdapter()) {
|
if (ObjectUtils.isEmpty(portal.getAdapterId()) || !portal.getCreateDataAdapter()) {
|
||||||
return response;
|
return response;
|
||||||
} else {
|
} else {
|
||||||
return super.mockExecute(portal.getAdapterId(), mockParam.getCode(), response, true);
|
return super.mockExecute(portal.getAdapterId(), mockParam.getCode(), response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object execute(PortalBo portal, HttpServletRequest request) {
|
public Object execute(PortalBo portal, HttpServletRequest request) {
|
||||||
return null;
|
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<String, Object> 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ public class LocalDataAdapterHandler extends AbstractDataAdapterHandler {
|
|||||||
if (ObjectUtils.isEmpty(portal.getAdapterId()) || !portal.getCreateDataAdapter()) {
|
if (ObjectUtils.isEmpty(portal.getAdapterId()) || !portal.getCreateDataAdapter()) {
|
||||||
return tableDataInfo.getRows();
|
return tableDataInfo.getRows();
|
||||||
} else {
|
} else {
|
||||||
return super.mockExecute(portal.getAdapterId(), mockParam.getCode(), tableDataInfo.getRows(), true);
|
return super.mockExecute(portal.getAdapterId(), mockParam.getCode(), tableDataInfo.getRows());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,7 +103,7 @@ public class LocalDataAdapterHandler extends AbstractDataAdapterHandler {
|
|||||||
//根据设置的参数动态调整当前是否需要分页操作
|
//根据设置的参数动态调整当前是否需要分页操作
|
||||||
TableDataInfo<Map<String, Object>> tableDataInfo = dynamicDataSearchService.searchData(uniConList, query, null, Boolean.TRUE);
|
TableDataInfo<Map<String, Object>> tableDataInfo = dynamicDataSearchService.searchData(uniConList, query, null, Boolean.TRUE);
|
||||||
if (portal.getCreateDataAdapter()) {
|
if (portal.getCreateDataAdapter()) {
|
||||||
return super.execute(portal.getAdapterId(), tableDataInfo.getRows(), false);
|
return super.execute(portal.getAdapterId(), tableDataInfo.getRows());
|
||||||
} else {
|
} else {
|
||||||
return tableDataInfo.getRows();
|
return tableDataInfo.getRows();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,10 +11,18 @@ public interface EngineExecuteHandler {
|
|||||||
*
|
*
|
||||||
* @param dataAdapter 数据适配器
|
* @param dataAdapter 数据适配器
|
||||||
* @param data 数据列表
|
* @param data 数据列表
|
||||||
* @param development
|
|
||||||
* @return JSONObject对象
|
* @return JSONObject对象
|
||||||
*/
|
*/
|
||||||
EngineResult 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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 预处理数据适配器
|
* 预处理数据适配器
|
||||||
@@ -31,4 +39,5 @@ public interface EngineExecuteHandler {
|
|||||||
* @return 删除结果
|
* @return 删除结果
|
||||||
*/
|
*/
|
||||||
Boolean remove(DataAdapter dataAdapter);
|
Boolean remove(DataAdapter dataAdapter);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import cn.fateverse.query.handler.engine.EngineExecuteHandler;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
@@ -32,12 +31,18 @@ public class JavaEngineExecuteHandler implements EngineExecuteHandler {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EngineResult execute(DataAdapter dataAdapter, Object data, boolean development) {
|
public Object execute(DataAdapter dataAdapter, Object data) {
|
||||||
if (!DataAdapterType.JAVA.equals(dataAdapter.getType())) {
|
if (!DataAdapterType.JAVA.equals(dataAdapter.getType())) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return javaCodeEngine.execute(dataAdapter.getExecuteCode(), getClassName(dataAdapter),
|
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) {
|
||||||
|
return javaCodeEngine.mockExecute(dataAdapter.getExecuteCode(), getClassName(dataAdapter),
|
||||||
|
"execute", new Object[]{data});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getClassName(DataAdapter dataAdapter) {
|
private static String getClassName(DataAdapter dataAdapter) {
|
||||||
@@ -53,7 +58,8 @@ public class JavaEngineExecuteHandler implements EngineExecuteHandler {
|
|||||||
String modifiedCode = modifiedCode(dataAdapter.getCode());
|
String modifiedCode = modifiedCode(dataAdapter.getCode());
|
||||||
String replacedCode = replacedClass(modifiedCode, getClassName(dataAdapter));
|
String replacedCode = replacedClass(modifiedCode, getClassName(dataAdapter));
|
||||||
String IMPORT_CODE = "import java.util.*;\n" +
|
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);
|
dataAdapter.setExecuteCode(IMPORT_CODE + replacedCode);
|
||||||
return Boolean.TRUE;
|
return Boolean.TRUE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,11 +23,20 @@ import java.util.regex.Pattern;
|
|||||||
public class JavaScriptEngineExecuteHandler implements EngineExecuteHandler {
|
public class JavaScriptEngineExecuteHandler implements EngineExecuteHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EngineResult execute(DataAdapter dataAdapter, Object data, boolean development) {
|
public Object execute(DataAdapter dataAdapter, Object data) {
|
||||||
if (!DataAdapterType.JAVA_SCRIPT.equals(dataAdapter.getType())) {
|
if (!DataAdapterType.JAVA_SCRIPT.equals(dataAdapter.getType())) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return JavaScriptEngine.execute(dataAdapter.getExecuteCode(), "execute" + dataAdapter.getAdapterId(), development, 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
|
@Override
|
||||||
|
|||||||
@@ -48,11 +48,11 @@ public class EngineExecuteHandlerReader {
|
|||||||
* @param data 数据列表
|
* @param data 数据列表
|
||||||
* @return 执行结果
|
* @return 执行结果
|
||||||
*/
|
*/
|
||||||
public EngineResult execute(DataAdapter dataAdapter, Object data, boolean development) {
|
public Object execute(DataAdapter dataAdapter, Object data) {
|
||||||
// 遍历引擎执行处理器列表
|
// 遍历引擎执行处理器列表
|
||||||
for (EngineExecuteHandler engineExecuteHandler : handlerList) {
|
for (EngineExecuteHandler engineExecuteHandler : handlerList) {
|
||||||
// 执行数据适配器的处理方法
|
// 执行数据适配器的处理方法
|
||||||
EngineResult result = engineExecuteHandler.execute(dataAdapter, data, development);
|
Object result = engineExecuteHandler.execute(dataAdapter, data);
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -60,6 +60,22 @@ public class EngineExecuteHandlerReader {
|
|||||||
// 若未找到匹配的数据适配器处理器,则返回null
|
// 若未找到匹配的数据适配器处理器,则返回null
|
||||||
return 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) {
|
public Boolean remove(DataAdapter dataAdapter) {
|
||||||
|
|||||||
@@ -3,12 +3,9 @@ package cn.fateverse.query.portal;
|
|||||||
import cn.fateverse.common.core.result.Result;
|
import cn.fateverse.common.core.result.Result;
|
||||||
import cn.fateverse.common.security.utils.ResponseRender;
|
import cn.fateverse.common.security.utils.ResponseRender;
|
||||||
import cn.fateverse.query.constant.QueryConstant;
|
import cn.fateverse.query.constant.QueryConstant;
|
||||||
import cn.fateverse.query.entity.DataAdapter;
|
|
||||||
import cn.fateverse.query.entity.Portal;
|
import cn.fateverse.query.entity.Portal;
|
||||||
import cn.fateverse.query.entity.PortalMapping;
|
import cn.fateverse.query.entity.PortalMapping;
|
||||||
import cn.fateverse.query.entity.bo.PortalBo;
|
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.handler.reader.DataAdapterHandlerReader;
|
||||||
import cn.fateverse.query.mapper.DataAdapterMapper;
|
import cn.fateverse.query.mapper.DataAdapterMapper;
|
||||||
import cn.fateverse.query.mapper.PortalMapper;
|
import cn.fateverse.query.mapper.PortalMapper;
|
||||||
@@ -20,7 +17,6 @@ import org.springframework.stereotype.Component;
|
|||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ public class PortalServiceImpl implements PortalService {
|
|||||||
this.handlerReader = handlerReader;
|
this.handlerReader = handlerReader;
|
||||||
taskExecuteExecutor.execute(() -> {
|
taskExecuteExecutor.execute(() -> {
|
||||||
PortalQuery query = new PortalQuery();
|
PortalQuery query = new PortalQuery();
|
||||||
query.setState(QueryConstant.PORTAL_PUBLISH);
|
// query.setState(QueryConstant.PORTAL_PUBLISH);
|
||||||
List<Portal> portalList = portalMapper.selectList(query);
|
List<Portal> portalList = portalMapper.selectList(query);
|
||||||
if (ObjectUtils.isEmpty(portalList)) {
|
if (ObjectUtils.isEmpty(portalList)) {
|
||||||
log.info("portal is empty!");
|
log.info("portal is empty!");
|
||||||
@@ -247,9 +247,13 @@ public class PortalServiceImpl implements PortalService {
|
|||||||
if (!ObjectUtils.isEmpty(old)) {
|
if (!ObjectUtils.isEmpty(old)) {
|
||||||
throw new CustomException("系统中存在当前请求路径");
|
throw new CustomException("系统中存在当前请求路径");
|
||||||
}
|
}
|
||||||
UniQuery uniQuery = queryMapper.selectById(portal.getQueryId());
|
if (PortalEnum.EXTERNAL.equals(portal.getType())) {
|
||||||
if (ObjectUtils.isEmpty(uniQuery)) {
|
createPortalInterface(portalDto, portal);
|
||||||
throw new CustomException("未找到对应的查询接口!");
|
}else {
|
||||||
|
UniQuery uniQuery = queryMapper.selectById(portal.getQueryId());
|
||||||
|
if (ObjectUtils.isEmpty(uniQuery)) {
|
||||||
|
throw new CustomException("未找到对应的查询接口!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
portal.setState(QueryConstant.PORTAL_DEV);
|
portal.setState(QueryConstant.PORTAL_DEV);
|
||||||
// 判断是否需要创建数据适配器
|
// 判断是否需要创建数据适配器
|
||||||
@@ -261,9 +265,6 @@ public class PortalServiceImpl implements PortalService {
|
|||||||
throw new CustomException("未找到对应的数据适配器!");
|
throw new CustomException("未找到对应的数据适配器!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (PortalEnum.EXTERNAL.equals(portal.getType())) {
|
|
||||||
createPortalInterface(portalDto, portal);
|
|
||||||
}
|
|
||||||
portalMapper.insert(portal);
|
portalMapper.insert(portal);
|
||||||
List<PortalMapping> mappings = portalDto.getMappings();
|
List<PortalMapping> mappings = portalDto.getMappings();
|
||||||
if (!ObjectUtils.isEmpty(mappings)) {
|
if (!ObjectUtils.isEmpty(mappings)) {
|
||||||
|
|||||||
@@ -5,19 +5,20 @@
|
|||||||
<mapper namespace="cn.fateverse.query.mapper.PortalInterfaceMapper">
|
<mapper namespace="cn.fateverse.query.mapper.PortalInterfaceMapper">
|
||||||
|
|
||||||
<select id="selectById" resultType="cn.fateverse.query.entity.PortalInterface">
|
<select id="selectById" resultType="cn.fateverse.query.entity.PortalInterface">
|
||||||
select interface_id, content_type, request_method
|
select interface_id, url, content_type, request_method
|
||||||
from portal_interface
|
from portal_interface
|
||||||
where interface_id = #{interfaceId}
|
where interface_id = #{interfaceId}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<insert id="insert" useGeneratedKeys="true" keyColumn="interface_id" keyProperty="interfaceId">
|
<insert id="insert" useGeneratedKeys="true" keyColumn="interface_id" keyProperty="interfaceId">
|
||||||
insert into portal_interface (interface_id, content_type, request_method)
|
insert into portal_interface (interface_id, url, content_type, request_method)
|
||||||
values (#{interfaceId}, #{contentType}, #{requestMethod})
|
values (#{interfaceId}, #{url}, #{contentType}, #{requestMethod})
|
||||||
</insert>
|
</insert>
|
||||||
|
|
||||||
<update id="update">
|
<update id="update">
|
||||||
update portal_interface
|
update portal_interface
|
||||||
set content_type = #{contentType},
|
set content_type = #{contentType},
|
||||||
|
url = #{url},
|
||||||
request_method = #{requestMethod}
|
request_method = #{requestMethod}
|
||||||
where interface_id = #{interfaceId}
|
where interface_id = #{interfaceId}
|
||||||
</update>
|
</update>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package cn.fateverse.workflow.process;
|
package cn.fateverse.workflow.process;
|
||||||
|
|
||||||
import cn.fateverse.common.code.engine.JavaScriptEngine;
|
import cn.fateverse.common.code.engine.JavaScriptEngine;
|
||||||
import cn.fateverse.common.code.model.EngineResult;
|
|
||||||
import cn.fateverse.workflow.constant.ProcessConstant;
|
import cn.fateverse.workflow.constant.ProcessConstant;
|
||||||
import cn.fateverse.workflow.entity.bpmn.*;
|
import cn.fateverse.workflow.entity.bpmn.*;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
@@ -159,14 +158,14 @@ public class TriggerService {
|
|||||||
}
|
}
|
||||||
//获取到请求的返回结果
|
//获取到请求的返回结果
|
||||||
Map<String, Object> result = response.getBody();
|
Map<String, Object> result = response.getBody();
|
||||||
EngineResult engineResult;
|
ScriptObjectMirror jsResult;
|
||||||
try {
|
try {
|
||||||
//判断请求是否有效
|
//判断请求是否有效
|
||||||
if (response.getStatusCode() == HttpStatus.OK) {
|
if (response.getStatusCode() == HttpStatus.OK) {
|
||||||
engineResult = JavaScriptEngine.execute(http.getSuccess(), "handlerSuccess", false, result);
|
jsResult = (ScriptObjectMirror) JavaScriptEngine.execute(http.getSuccess(), "handlerSuccess", result);
|
||||||
operation.setState(OperationStateEnums.SUCCESS);
|
operation.setState(OperationStateEnums.SUCCESS);
|
||||||
} else {
|
} else {
|
||||||
engineResult = JavaScriptEngine.execute(http.getFail(), "handlerFail", false, result);
|
jsResult = (ScriptObjectMirror) JavaScriptEngine.execute(http.getFail(), "handlerFail", result);
|
||||||
operation.setState(OperationStateEnums.FAILURE);
|
operation.setState(OperationStateEnums.FAILURE);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -178,7 +177,6 @@ public class TriggerService {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ScriptObjectMirror jsResult = (ScriptObjectMirror) engineResult.getResult();
|
|
||||||
//获取到自定义脚本的状态
|
//获取到自定义脚本的状态
|
||||||
boolean state = (Boolean) jsResult.get("state");
|
boolean state = (Boolean) jsResult.get("state");
|
||||||
//获取到js脚本中的内容
|
//获取到js脚本中的内容
|
||||||
|
|||||||
Reference in New Issue
Block a user