feat: java执行引擎和js执行引擎调试完成
This commit is contained in:
@@ -21,6 +21,16 @@
|
|||||||
<groupId>cn.fateverse</groupId>
|
<groupId>cn.fateverse</groupId>
|
||||||
<artifactId>common-core</artifactId>
|
<artifactId>common-core</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.graalvm.js</groupId>
|
||||||
|
<artifactId>js-scriptengine</artifactId>
|
||||||
|
<version>22.1.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.graalvm.js</groupId>
|
||||||
|
<artifactId>js</artifactId>
|
||||||
|
<version>22.1.0</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
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;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Clay
|
||||||
|
* @date 2024/4/22 17:08
|
||||||
|
*/
|
||||||
|
public class MultiThreadedCapture {
|
||||||
|
|
||||||
|
|
||||||
|
private final static ExecutorService executor = Executors.newFixedThreadPool(2);
|
||||||
|
|
||||||
|
|
||||||
|
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) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} finally {
|
||||||
|
System.setOut(oldOut);
|
||||||
|
// 从捕获的字节数组输出流中获取打印的文本
|
||||||
|
capturedOutput = baos.toString();
|
||||||
|
}
|
||||||
|
return new EngineResult(result, capturedOutput);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public interface Task {
|
||||||
|
Object execute() throws Exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,18 +2,21 @@ package cn.fateverse.common.code.engine;
|
|||||||
|
|
||||||
|
|
||||||
import cn.fateverse.common.code.config.JavaCodeProperties;
|
import cn.fateverse.common.code.config.JavaCodeProperties;
|
||||||
|
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.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 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 javax.tools.JavaCompiler;
|
import javax.tools.JavaCompiler;
|
||||||
import javax.tools.ToolProvider;
|
import javax.tools.ToolProvider;
|
||||||
import java.io.File;
|
import java.io.*;
|
||||||
import java.io.FileWriter;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
@@ -73,7 +76,7 @@ public class JavaCodeEngine {
|
|||||||
* @param development 是否为开发环境 开发环境下会将生成的类在执行完成后删除,不是生产环境则会缓存提高运行效率
|
* @param development 是否为开发环境 开发环境下会将生成的类在执行完成后删除,不是生产环境则会缓存提高运行效率
|
||||||
* @return 执行结果
|
* @return 执行结果
|
||||||
*/
|
*/
|
||||||
public <T> T execute(String code, String className, String methodName, Class<?>[] paramClass, Object[] args, boolean development) {
|
public EngineResult execute(String code, String className, String methodName, Class<?>[] paramClass, Object[] args, boolean development) {
|
||||||
if (development) {
|
if (development) {
|
||||||
return developmentExecute(code, className, methodName, paramClass, args);
|
return developmentExecute(code, className, methodName, paramClass, args);
|
||||||
} else {
|
} else {
|
||||||
@@ -90,11 +93,10 @@ public class JavaCodeEngine {
|
|||||||
* @param methodName 方法名
|
* @param methodName 方法名
|
||||||
* @param paramClass 参数类型数组
|
* @param paramClass 参数类型数组
|
||||||
* @param args 参数数组
|
* @param args 参数数组
|
||||||
* @param <T> 接收泛型
|
|
||||||
* @return 执行结构
|
* @return 执行结构
|
||||||
*/
|
*/
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
private <T> T developmentExecute(String code, String className, String methodName, Class<?>[] paramClass, Object[] args) {
|
private EngineResult developmentExecute(String code, String className, String methodName, Class<?>[] paramClass, Object[] args) {
|
||||||
Class<?> loadClass = null;
|
Class<?> loadClass = null;
|
||||||
try {
|
try {
|
||||||
// 加锁,确保类只加载一次
|
// 加锁,确保类只加载一次
|
||||||
@@ -123,7 +125,8 @@ public class JavaCodeEngine {
|
|||||||
// 设置安全检查器
|
// 设置安全检查器
|
||||||
System.setSecurityManager(securityManager);
|
System.setSecurityManager(securityManager);
|
||||||
// 执行方法并返回结果
|
// 执行方法并返回结果
|
||||||
return (T) method.invoke(null, args);
|
return MultiThreadedCapture.capture(() -> method.invoke(null, args));
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
// 从缓存中移除编译好的类
|
// 从缓存中移除编译好的类
|
||||||
classCache.remove(className);
|
classCache.remove(className);
|
||||||
@@ -155,10 +158,9 @@ public class JavaCodeEngine {
|
|||||||
* @param methodName 方法名
|
* @param methodName 方法名
|
||||||
* @param paramClass 参数类型数组
|
* @param paramClass 参数类型数组
|
||||||
* @param args 参数数组
|
* @param args 参数数组
|
||||||
* @param <T> 接收泛型
|
|
||||||
* @return 执行结构
|
* @return 执行结构
|
||||||
*/
|
*/
|
||||||
private <T> T onlineExecute(String code, String className, String methodName, Class<?>[] paramClass, Object[] args) {
|
private EngineResult onlineExecute(String code, String className, String methodName, Class<?>[] paramClass, Object[] args) {
|
||||||
try {
|
try {
|
||||||
Class<?> loadClass = null;
|
Class<?> loadClass = null;
|
||||||
loadClass = classCache.get(className);
|
loadClass = classCache.get(className);
|
||||||
@@ -166,7 +168,8 @@ public class JavaCodeEngine {
|
|||||||
loadClass = getLoadClass(code, className);
|
loadClass = getLoadClass(code, className);
|
||||||
Method method = loadClass.getMethod(methodName, paramClass);
|
Method method = loadClass.getMethod(methodName, paramClass);
|
||||||
System.setSecurityManager(securityManager);
|
System.setSecurityManager(securityManager);
|
||||||
return (T) method.invoke(null, args);
|
Object result = (Object) method.invoke(null, args);
|
||||||
|
return new EngineResult(result);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@@ -215,22 +218,31 @@ public class JavaCodeEngine {
|
|||||||
* @return 编译完成的类对象
|
* @return 编译完成的类对象
|
||||||
*/
|
*/
|
||||||
private Class<?> compilerClass(String className, String code, URLClassLoader classLoader) {
|
private Class<?> compilerClass(String className, String code, URLClassLoader classLoader) {
|
||||||
log.info(code);
|
|
||||||
File tempFile = new File(CLASS_PATH + className + JAVA_SUFFIX);
|
File tempFile = new File(CLASS_PATH + className + JAVA_SUFFIX);
|
||||||
try (FileWriter writer = new FileWriter(tempFile)) {
|
try (FileWriter writer = new FileWriter(tempFile)) {
|
||||||
writer.write(code);
|
writer.write(code);
|
||||||
writer.close();
|
writer.close();
|
||||||
|
ByteArrayOutputStream errorStream = new ByteArrayOutputStream(10240);
|
||||||
// 编译.java文件
|
// 编译.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);
|
return classLoader.loadClass(className);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
throw new RuntimeException(e);
|
if (e instanceof CustomException) {
|
||||||
|
throw (CustomException) e;
|
||||||
|
}
|
||||||
|
throw new CustomException("执行或者编辑错误!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除类
|
* 删除类
|
||||||
|
*
|
||||||
* @param className 删除类
|
* @param className 删除类
|
||||||
* @return 删除结果
|
* @return 删除结果
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,9 +1,17 @@
|
|||||||
package cn.fateverse.common.code.engine;
|
package cn.fateverse.common.code.engine;
|
||||||
|
|
||||||
import javax.script.Invocable;
|
import cn.fateverse.common.code.console.MultiThreadedCapture;
|
||||||
import javax.script.ScriptEngine;
|
import cn.fateverse.common.code.lock.SegmentLock;
|
||||||
import javax.script.ScriptEngineManager;
|
import cn.fateverse.common.code.model.EngineResult;
|
||||||
import javax.script.ScriptException;
|
import cn.fateverse.common.core.exception.CustomException;
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import org.graalvm.polyglot.Context;
|
||||||
|
import org.graalvm.polyglot.Value;
|
||||||
|
import org.springframework.security.core.parameters.P;
|
||||||
|
|
||||||
|
import javax.script.*;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* js 工具类
|
* js 工具类
|
||||||
@@ -13,25 +21,60 @@ import javax.script.ScriptException;
|
|||||||
*/
|
*/
|
||||||
public class JavaScriptEngine {
|
public class JavaScriptEngine {
|
||||||
|
|
||||||
|
|
||||||
|
// 创建 GraalVM 上下文
|
||||||
|
private static final Context context = Context.newBuilder()
|
||||||
|
.allowAllAccess(true)
|
||||||
|
// .allowHostClassLoading(true)
|
||||||
|
// .allowIO(true)
|
||||||
|
// .allowNativeAccess(true)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
|
||||||
|
private static final Map<String, Value> functionMap = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 执行js代码
|
* 执行js代码
|
||||||
* @param script js脚本
|
*
|
||||||
* @param function js函数名
|
* @param script js脚本
|
||||||
* @param args 参数
|
* @param functionName js函数名
|
||||||
|
* @param args 参数
|
||||||
* @return 返回结构
|
* @return 返回结构
|
||||||
* @param <T> 泛型类型
|
|
||||||
*/
|
*/
|
||||||
public static <T> T executeScript(String script, String function, Object... args) {
|
public static EngineResult execute(String script, String functionName, boolean development, Object args) {
|
||||||
ScriptEngineManager manager = new ScriptEngineManager();
|
if (development) {
|
||||||
ScriptEngine engine = manager.getEngineByName("JavaScript");
|
return MultiThreadedCapture.capture(() -> {
|
||||||
try {
|
Context context = Context.newBuilder()
|
||||||
engine.eval(script);
|
.allowAllAccess(true)
|
||||||
Invocable inv = (Invocable) engine;
|
.allowHostClassLoading(true)
|
||||||
return (T) inv.invokeFunction(function, args);
|
.allowIO(true)
|
||||||
} catch (ScriptException | NoSuchMethodException e) {
|
.allowNativeAccess(true).build();
|
||||||
throw new RuntimeException(e);
|
context.eval("js", script);
|
||||||
|
Value executeFunction = context.getBindings("js").getMember(functionName);
|
||||||
|
Value javaObjectAsValue = Value.asValue(args);
|
||||||
|
Value result = executeFunction.execute(javaObjectAsValue);
|
||||||
|
return result.as(Object.class);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Value executeFunction = getFunction(functionName, script);
|
||||||
|
Value result = executeFunction.execute(JSON.toJSONString(args));
|
||||||
|
return new EngineResult(result.as(Object.class));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
public EngineResult(Object result) {
|
||||||
|
this.result = result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,4 +12,23 @@ import java.lang.annotation.Target;
|
|||||||
@Target(ElementType.METHOD)
|
@Target(ElementType.METHOD)
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
public @interface Encrypt {
|
public @interface Encrypt {
|
||||||
|
|
||||||
|
Position value() default Position.ALL;
|
||||||
|
|
||||||
|
|
||||||
|
EncryptType type() default EncryptType.SM4;
|
||||||
|
|
||||||
|
|
||||||
|
enum EncryptType {
|
||||||
|
|
||||||
|
SM4,
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Position {
|
||||||
|
ALL,
|
||||||
|
OUT,
|
||||||
|
IN
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,4 +11,12 @@ import java.lang.annotation.Target;
|
|||||||
@Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD})
|
@Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD})
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
public @interface EncryptField {
|
public @interface EncryptField {
|
||||||
|
|
||||||
|
Position value() default Position.ALL;
|
||||||
|
|
||||||
|
enum Position {
|
||||||
|
ALL,
|
||||||
|
OUT,
|
||||||
|
IN
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@ package cn.fateverse.common.decrypt.aspect;
|
|||||||
|
|
||||||
import cn.fateverse.common.core.exception.CustomException;
|
import cn.fateverse.common.core.exception.CustomException;
|
||||||
import cn.fateverse.common.core.result.Result;
|
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.annotation.EncryptField;
|
||||||
import cn.fateverse.common.decrypt.service.EncryptService;
|
import cn.fateverse.common.decrypt.service.EncryptService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -11,12 +12,10 @@ import org.aspectj.lang.annotation.Aspect;
|
|||||||
import org.aspectj.lang.reflect.MethodSignature;
|
import org.aspectj.lang.reflect.MethodSignature;
|
||||||
import org.springframework.util.ReflectionUtils;
|
import org.springframework.util.ReflectionUtils;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Parameter;
|
import java.lang.reflect.Parameter;
|
||||||
import java.util.Collection;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Aspect
|
@Aspect
|
||||||
@@ -41,36 +40,35 @@ public class EncryptAspect {
|
|||||||
@Around("@annotation(cn.fateverse.common.decrypt.annotation.Encrypt)")
|
@Around("@annotation(cn.fateverse.common.decrypt.annotation.Encrypt)")
|
||||||
public Object decryptField(ProceedingJoinPoint point) throws Throwable {
|
public Object decryptField(ProceedingJoinPoint point) throws Throwable {
|
||||||
MethodSignature signature = (MethodSignature) point.getSignature();
|
MethodSignature signature = (MethodSignature) point.getSignature();
|
||||||
//获取请求参数
|
|
||||||
Object[] args = point.getArgs();
|
|
||||||
//获取方法
|
//获取方法
|
||||||
Method method = signature.getMethod();
|
Method method = signature.getMethod();
|
||||||
//获取方法参数 Parameter对象集 参数修饰符、参数名、注解及注解类型
|
Encrypt encrypt = method.getAnnotation(Encrypt.class);
|
||||||
Parameter[] parameters = method.getParameters();
|
if (encrypt == null) {
|
||||||
for (int i = 0; i < parameters.length; i++) {
|
return point.proceed();
|
||||||
Parameter parameter = parameters[i];
|
}
|
||||||
//获取参数注解
|
//获取请求参数
|
||||||
EncryptField encryptField = parameter.getAnnotation(EncryptField.class);
|
Object[] args = point.getArgs();
|
||||||
Object arg = args[i];
|
if (Encrypt.Position.ALL.equals(encrypt.value()) || Encrypt.Position.IN.equals(encrypt.value())) {
|
||||||
if (null != encryptField) {
|
decryptParams(args, method);
|
||||||
if (arg instanceof String) {
|
|
||||||
String decrypt = encryptService.decrypt((String) arg);
|
|
||||||
args[i] = decrypt;
|
|
||||||
} else if (arg instanceof List) {
|
|
||||||
try {
|
|
||||||
List<String> list = (List<String>) 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
//正常执行业务,最后返回的返回值为Result
|
//正常执行业务,最后返回的返回值为Result
|
||||||
Object proceed = point.proceed(args);
|
Object proceed = point.proceed(args);
|
||||||
|
if (Encrypt.Position.ALL.equals(encrypt.value()) || Encrypt.Position.OUT.equals(encrypt.value())) {
|
||||||
|
Result<Object> error = encryptResult(proceed);
|
||||||
|
if (error != null) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return proceed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加密返回值
|
||||||
|
*
|
||||||
|
* @param proceed 返回执
|
||||||
|
* @return 加密结果
|
||||||
|
*/
|
||||||
|
private Result<Object> encryptResult(Object proceed) {
|
||||||
if (proceed instanceof Result) {
|
if (proceed instanceof Result) {
|
||||||
Result<Object> result = (Result<Object>) proceed;
|
Result<Object> result = (Result<Object>) proceed;
|
||||||
Object data = result.getData();
|
Object data = result.getData();
|
||||||
@@ -91,29 +89,71 @@ public class EncryptAspect {
|
|||||||
return Result.error("加密异常!");
|
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<String> list = (List<String>) 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) {
|
if (data == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Class<?> argClass = data.getClass();
|
Class<?> argClass = data.getClass();
|
||||||
|
List<Field> fieldList = new ArrayList<>();
|
||||||
if (argClass.getTypeName().startsWith(BASE_PACKAGE)) {
|
if (argClass.getTypeName().startsWith(BASE_PACKAGE)) {
|
||||||
Field[] fields = argClass.getDeclaredFields();
|
getFields(argClass, fieldList);
|
||||||
for (Field field : fields) {
|
for (Field field : fieldList) {
|
||||||
EncryptField encryptField = field.getAnnotation(EncryptField.class);
|
EncryptField encryptField = field.getAnnotation(EncryptField.class);
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
Object value = ReflectionUtils.getField(field, data);
|
Object value = ReflectionUtils.getField(field, data);
|
||||||
if (null == value) {
|
if (null == value) {
|
||||||
continue;
|
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);
|
String decrypt = encryptService.encrypt((String) value);
|
||||||
ReflectionUtils.setField(field, data, decrypt);
|
ReflectionUtils.setField(field, data, decrypt);
|
||||||
} else if (field.getType().getName().startsWith(BASE_PACKAGE)) {
|
} else if (field.getType().getName().startsWith(BASE_PACKAGE)) {
|
||||||
if (!value.getClass().isEnum()){
|
if (!value.getClass().isEnum()) {
|
||||||
encrypt(value);
|
encrypt(value);
|
||||||
}
|
}
|
||||||
} else if (value instanceof Collection) {
|
} else if (value instanceof Collection) {
|
||||||
@@ -128,29 +168,49 @@ public class EncryptAspect {
|
|||||||
for (Object item : collection) {
|
for (Object item : collection) {
|
||||||
encrypt(item);
|
encrypt(item);
|
||||||
}
|
}
|
||||||
|
} else if (data instanceof Map) {
|
||||||
|
Map<Object, Object> map = (Map<Object, Object>) data;
|
||||||
|
for (Object key : map.keySet()) {
|
||||||
|
Object value = map.get(key);
|
||||||
|
encrypt(key);
|
||||||
|
encrypt(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void decrypt(Object arg) throws Exception {
|
private void decrypt(Object arg) throws Exception {
|
||||||
Class<?> argClass = arg.getClass();
|
Class<?> argClass = arg.getClass();
|
||||||
Field[] fields = argClass.getDeclaredFields();
|
List<Field> fieldList = new ArrayList<>();
|
||||||
for (Field field : fields) {
|
getFields(argClass, fieldList);
|
||||||
|
for (Field field : fieldList) {
|
||||||
EncryptField encryptField = field.getAnnotation(EncryptField.class);
|
EncryptField encryptField = field.getAnnotation(EncryptField.class);
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
Object value = ReflectionUtils.getField(field, arg);
|
Object value = ReflectionUtils.getField(field, arg);
|
||||||
if (null == value) {
|
if (null == value) {
|
||||||
continue;
|
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);
|
String decrypt = encryptService.decrypt((String) value);
|
||||||
ReflectionUtils.setField(field, arg, decrypt);
|
ReflectionUtils.setField(field, arg, decrypt);
|
||||||
} else if (field.getType().getName().startsWith(BASE_PACKAGE)) {
|
} else if (field.getType().getName().startsWith(BASE_PACKAGE)) {
|
||||||
if (!value.getClass().isEnum()){
|
if (!value.getClass().isEnum()) {
|
||||||
decrypt(value);
|
decrypt(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void getFields(Class<?> argClass, List<Field> fieldList) {
|
||||||
|
if (argClass.getTypeName().startsWith(BASE_PACKAGE)) {
|
||||||
|
Field[] fields = argClass.getDeclaredFields();
|
||||||
|
fieldList.addAll(Arrays.asList(fields));
|
||||||
|
getFields(argClass.getSuperclass(), fieldList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,6 +76,10 @@
|
|||||||
<groupId>cn.fateverse</groupId>
|
<groupId>cn.fateverse</groupId>
|
||||||
<artifactId>common-excel</artifactId>
|
<artifactId>common-excel</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.squareup.okhttp3</groupId>
|
||||||
|
<artifactId>okhttp</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<build>
|
<build>
|
||||||
<finalName>${project.artifactId}</finalName>
|
<finalName>${project.artifactId}</finalName>
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,9 +6,29 @@ package cn.fateverse.query.constant;
|
|||||||
*/
|
*/
|
||||||
public class QueryConstant {
|
public class QueryConstant {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义查询权限前缀
|
||||||
|
*/
|
||||||
public static final String PERMISSIONS_KEY = "custom:query:online:";
|
public static final String PERMISSIONS_KEY = "custom:query:online:";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义接口Redis前缀key
|
||||||
|
*/
|
||||||
public static final String PORTAL_KEY = "custom:query:portal:";
|
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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,13 +66,11 @@ public class DataAdapterController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation("获取数据源适配器详细信息")
|
@ApiOperation("获取数据源适配器详细信息")
|
||||||
@Encrypt
|
|
||||||
@GetMapping("/{adapterId}")
|
@GetMapping("/{adapterId}")
|
||||||
@PreAuthorize("@ss.hasPermission('query:adapter:info')")
|
@PreAuthorize("@ss.hasPermission('query:adapter:info')")
|
||||||
public Result<DataAdapterVo> info(@PathVariable @EncryptField String adapterId) {
|
public Result<DataAdapterVo> info(@PathVariable Long adapterId) {
|
||||||
ObjectUtils.checkPk(adapterId);
|
ObjectUtils.checkPk(adapterId);
|
||||||
Long id = Long.valueOf(adapterId);
|
DataAdapterVo dataAdapter = dataAdapterService.searchById(adapterId);
|
||||||
DataAdapterVo dataAdapter = dataAdapterService.searchById(id);
|
|
||||||
return Result.ok(dataAdapter);
|
return Result.ok(dataAdapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import cn.fateverse.common.core.result.page.TableDataInfo;
|
|||||||
import cn.fateverse.common.core.utils.ObjectUtils;
|
import cn.fateverse.common.core.utils.ObjectUtils;
|
||||||
import cn.fateverse.common.decrypt.annotation.Encrypt;
|
import cn.fateverse.common.decrypt.annotation.Encrypt;
|
||||||
import cn.fateverse.common.decrypt.annotation.EncryptField;
|
import cn.fateverse.common.decrypt.annotation.EncryptField;
|
||||||
|
import cn.fateverse.query.entity.dto.MockParam;
|
||||||
import cn.fateverse.query.entity.dto.PortalDto;
|
import cn.fateverse.query.entity.dto.PortalDto;
|
||||||
import cn.fateverse.query.entity.query.PortalQuery;
|
import cn.fateverse.query.entity.query.PortalQuery;
|
||||||
import cn.fateverse.query.entity.vo.PortalIdWrapper;
|
import cn.fateverse.query.entity.vo.PortalIdWrapper;
|
||||||
@@ -36,7 +37,7 @@ public class PortalController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation("获取接口管理表详细信息")
|
@ApiOperation("获取接口管理表详细信息")
|
||||||
@Encrypt
|
@Encrypt(Encrypt.Position.IN)
|
||||||
@GetMapping("/{portalId}")
|
@GetMapping("/{portalId}")
|
||||||
@PreAuthorize("@ss.hasPermission('query:portal:info')")
|
@PreAuthorize("@ss.hasPermission('query:portal:info')")
|
||||||
public Result<PortalVo> info(@PathVariable @EncryptField String portalId) {
|
public Result<PortalVo> info(@PathVariable @EncryptField String portalId) {
|
||||||
@@ -47,6 +48,17 @@ public class PortalController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ApiOperation("详情接口")
|
||||||
|
@Encrypt(Encrypt.Position.IN)
|
||||||
|
@GetMapping("/detail/{portalId}")
|
||||||
|
public Result<PortalVo> detail(@PathVariable @EncryptField String portalId) {
|
||||||
|
ObjectUtils.checkPk(portalId);
|
||||||
|
Long value = Long.valueOf(portalId);
|
||||||
|
PortalVo portal = portalService.searchDetailById(value);
|
||||||
|
return Result.ok(portal);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@ApiOperation("获取接口管理表列表")
|
@ApiOperation("获取接口管理表列表")
|
||||||
@GetMapping
|
@GetMapping
|
||||||
@Encrypt
|
@Encrypt
|
||||||
@@ -57,7 +69,7 @@ public class PortalController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation("新增接口")
|
@ApiOperation("新增接口")
|
||||||
@Encrypt
|
@Encrypt(Encrypt.Position.OUT)
|
||||||
@PostMapping
|
@PostMapping
|
||||||
@PreAuthorize("@ss.hasPermission('query:portal:add')")
|
@PreAuthorize("@ss.hasPermission('query:portal:add')")
|
||||||
public Result<PortalIdWrapper> add(@RequestBody @Validated PortalDto portalDto) {
|
public Result<PortalIdWrapper> add(@RequestBody @Validated PortalDto portalDto) {
|
||||||
@@ -66,7 +78,7 @@ public class PortalController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation("修改接口")
|
@ApiOperation("修改接口")
|
||||||
@Encrypt
|
@Encrypt(Encrypt.Position.OUT)
|
||||||
@PutMapping
|
@PutMapping
|
||||||
@PreAuthorize("@ss.hasPermission('query:portal:edit')")
|
@PreAuthorize("@ss.hasPermission('query:portal:edit')")
|
||||||
public Result<PortalIdWrapper> edit(@RequestBody @Validated PortalDto portalDto) {
|
public Result<PortalIdWrapper> edit(@RequestBody @Validated PortalDto portalDto) {
|
||||||
@@ -76,4 +88,48 @@ public class PortalController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ApiOperation("模拟执行")
|
||||||
|
@PostMapping("/mock/execute")
|
||||||
|
@PreAuthorize("@ss.hasPermission('query:portal:execute')")
|
||||||
|
public Result<Object> 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<Object> mockData(@RequestBody @Validated MockParam mockParam) {
|
||||||
|
Object result = portalService.mockData(mockParam);
|
||||||
|
return Result.ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ApiOperation("撤销发布")
|
||||||
|
@Encrypt
|
||||||
|
@PutMapping("/cancel/{portalId}")
|
||||||
|
@PreAuthorize("@ss.hasPermission('query:portal:edit')")
|
||||||
|
public Result<PortalIdWrapper> 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<Void> remove(@PathVariable @EncryptField String portalId) {
|
||||||
|
ObjectUtils.checkPk(portalId);
|
||||||
|
Long value = Long.valueOf(portalId);
|
||||||
|
portalService.delete(value);
|
||||||
|
return Result.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,6 +78,9 @@ public class DataAdapter extends BaseEntity {
|
|||||||
"}\n";
|
"}\n";
|
||||||
} else if (DataAdapterType.JAVA_SCRIPT.equals(type)) {
|
} else if (DataAdapterType.JAVA_SCRIPT.equals(type)) {
|
||||||
//JavaScript代码初始化
|
//JavaScript代码初始化
|
||||||
|
this.code = "function execute(data) {\n" +
|
||||||
|
"\n" +
|
||||||
|
"}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -58,9 +58,16 @@ public class Portal extends BaseEntity {
|
|||||||
*/
|
*/
|
||||||
private String requestMethod;
|
private String requestMethod;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否创建数据适配器
|
||||||
|
*/
|
||||||
private Boolean createDataAdapter;
|
private Boolean createDataAdapter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否分页
|
||||||
|
*/
|
||||||
|
private Boolean page;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 系统暴露地址
|
* 系统暴露地址
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -43,12 +43,23 @@ public class PortalMapping {
|
|||||||
* 映射值 自定义查询映射值为查询条件的id 第三方接口则为接口查询的key
|
* 映射值 自定义查询映射值为查询条件的id 第三方接口则为接口查询的key
|
||||||
*/
|
*/
|
||||||
private String mappingValue;
|
private String mappingValue;
|
||||||
|
/**
|
||||||
|
* 输入类型
|
||||||
|
*/
|
||||||
|
private String inputType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 描述
|
||||||
|
*/
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
|
||||||
public Boolean check() {
|
public Boolean check() {
|
||||||
if (ObjectUtils.isEmpty(mappingKey)
|
if (ObjectUtils.isEmpty(mappingKey)
|
||||||
|| ObjectUtils.isEmpty(mappingValue)
|
|| ObjectUtils.isEmpty(mappingValue)
|
||||||
|| ObjectUtils.isEmpty(mappingType)){
|
|| ObjectUtils.isEmpty(mappingType)
|
||||||
|
// || ObjectUtils.isEmpty(inputType)
|
||||||
|
) {
|
||||||
return Boolean.FALSE;
|
return Boolean.FALSE;
|
||||||
}
|
}
|
||||||
return Boolean.TRUE;
|
return Boolean.TRUE;
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ public class PortalBo implements Serializable {
|
|||||||
private Long adapterId;
|
private Long adapterId;
|
||||||
private PortalEnum type;
|
private PortalEnum type;
|
||||||
private String requestMethod;
|
private String requestMethod;
|
||||||
|
private Boolean createDataAdapter;
|
||||||
|
private Boolean page;
|
||||||
private String path;
|
private String path;
|
||||||
private String url;
|
private String url;
|
||||||
private Integer state;
|
private Integer state;
|
||||||
@@ -37,6 +39,8 @@ public class PortalBo implements Serializable {
|
|||||||
.adapterId(portal.getAdapterId())
|
.adapterId(portal.getAdapterId())
|
||||||
.type(portal.getType())
|
.type(portal.getType())
|
||||||
.requestMethod(portal.getRequestMethod())
|
.requestMethod(portal.getRequestMethod())
|
||||||
|
.createDataAdapter(portal.getCreateDataAdapter())
|
||||||
|
.page(portal.getPage())
|
||||||
.path(portal.getPath())
|
.path(portal.getPath())
|
||||||
.url(portal.getUrl())
|
.url(portal.getUrl())
|
||||||
.state(portal.getState())
|
.state(portal.getState())
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
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<Param> params;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class Param {
|
||||||
|
|
||||||
|
private String key;
|
||||||
|
|
||||||
|
private Object value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -70,6 +70,11 @@ public class PortalDto {
|
|||||||
@NotNull(message = "是否创建数据适配器不能为空!")
|
@NotNull(message = "是否创建数据适配器不能为空!")
|
||||||
private Boolean createDataAdapter;
|
private Boolean createDataAdapter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否分页
|
||||||
|
*/
|
||||||
|
private Boolean page;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 系统暴露地址
|
* 系统暴露地址
|
||||||
*/
|
*/
|
||||||
@@ -113,6 +118,7 @@ public class PortalDto {
|
|||||||
.anonymity(anonymity)
|
.anonymity(anonymity)
|
||||||
.createDataAdapter(createDataAdapter)
|
.createDataAdapter(createDataAdapter)
|
||||||
.requestMethod(requestMethod)
|
.requestMethod(requestMethod)
|
||||||
|
.page(page)
|
||||||
.type(type)
|
.type(type)
|
||||||
.path(path)
|
.path(path)
|
||||||
.url(url)
|
.url(url)
|
||||||
@@ -120,7 +126,7 @@ public class PortalDto {
|
|||||||
.build();
|
.build();
|
||||||
try {
|
try {
|
||||||
RequestMethod.valueOf(requestMethod);
|
RequestMethod.valueOf(requestMethod);
|
||||||
}catch (Exception e){
|
} catch (Exception e) {
|
||||||
throw new RuntimeException("请求类型不支持!");
|
throw new RuntimeException("请求类型不支持!");
|
||||||
}
|
}
|
||||||
if (!ObjectUtils.isEmpty(portalId)) {
|
if (!ObjectUtils.isEmpty(portalId)) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package cn.fateverse.query.entity.query;
|
package cn.fateverse.query.entity.query;
|
||||||
|
|
||||||
import cn.fateverse.query.enums.PortalEnum;
|
import cn.fateverse.query.enums.PortalEnum;
|
||||||
import io.swagger.annotations.ApiModel;
|
import io.swagger.annotations.ApiModel;
|
||||||
@@ -42,4 +42,6 @@ public class PortalQuery {
|
|||||||
*/
|
*/
|
||||||
@ApiModelProperty("系统暴露地址")
|
@ApiModelProperty("系统暴露地址")
|
||||||
private String path;
|
private String path;
|
||||||
|
|
||||||
|
private Integer state;
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@ package cn.fateverse.query.entity.vo;
|
|||||||
|
|
||||||
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 com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
import io.swagger.annotations.ApiModel;
|
import io.swagger.annotations.ApiModel;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
@@ -20,12 +21,32 @@ import java.util.List;
|
|||||||
@ApiModel("接口详细管理表Vo")
|
@ApiModel("接口详细管理表Vo")
|
||||||
public class PortalVo extends SimplePortalVo {
|
public class PortalVo extends SimplePortalVo {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询类型
|
||||||
|
*/
|
||||||
private Integer queryType;
|
private Integer queryType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否创建数据适配器
|
||||||
|
*/
|
||||||
private Boolean createDataAdapter;
|
private Boolean createDataAdapter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否分页
|
||||||
|
*/
|
||||||
|
private Boolean page;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 条件映射
|
||||||
|
*/
|
||||||
private List<PortalMapping> mappings;
|
private List<PortalMapping> mappings;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据适配器信息
|
||||||
|
*/
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
private DataAdapterVo dataAdapter;
|
||||||
|
|
||||||
public static PortalVo toPortalVo(Portal portal) {
|
public static PortalVo toPortalVo(Portal portal) {
|
||||||
return toPortalVo(portal, null);
|
return toPortalVo(portal, null);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,16 +37,14 @@ public class SimplePortalVo {
|
|||||||
* 自定义查询id
|
* 自定义查询id
|
||||||
*/
|
*/
|
||||||
@ApiModelProperty("自定义查询id")
|
@ApiModelProperty("自定义查询id")
|
||||||
@EncryptField
|
private Long queryId;
|
||||||
private String queryId;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数据适配器id
|
* 数据适配器id
|
||||||
*/
|
*/
|
||||||
@ApiModelProperty("数据适配器id")
|
@ApiModelProperty("数据适配器id")
|
||||||
@EncryptField
|
private Long adapterId;
|
||||||
private String adapterId;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 接口名称
|
* 接口名称
|
||||||
@@ -127,6 +125,8 @@ public class SimplePortalVo {
|
|||||||
.portalId(String.valueOf(portal.getPortalId()))
|
.portalId(String.valueOf(portal.getPortalId()))
|
||||||
.portalName(portal.getPortalName())
|
.portalName(portal.getPortalName())
|
||||||
.anonymity(portal.getAnonymity())
|
.anonymity(portal.getAnonymity())
|
||||||
|
.queryId(portal.getQueryId())
|
||||||
|
.adapterId(portal.getAdapterId())
|
||||||
.type(portal.getType())
|
.type(portal.getType())
|
||||||
.path(portal.getPath())
|
.path(portal.getPath())
|
||||||
.state(portal.getState())
|
.state(portal.getState())
|
||||||
@@ -136,12 +136,6 @@ public class SimplePortalVo {
|
|||||||
.build();
|
.build();
|
||||||
portalVo.setCreateTime(portal.getCreateTime());
|
portalVo.setCreateTime(portal.getCreateTime());
|
||||||
portalVo.setUpdateTime(portal.getUpdateTime());
|
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;
|
return portalVo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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, boolean development) {
|
||||||
|
if (ObjectUtils.isEmpty(adapterId)) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
//获取当当前接口对应的数据适配器
|
||||||
|
DataAdapter dataAdapter = dataAdapterMapper.selectById(adapterId);
|
||||||
|
if (ObjectUtils.isEmpty(dataAdapter)) {
|
||||||
|
throw new RuntimeException("dataAdapter is null");
|
||||||
|
}
|
||||||
|
handlerReader.preconditioning(dataAdapter);
|
||||||
|
EngineResult execute = handlerReader.execute(dataAdapter, data, development);
|
||||||
|
if (ObjectUtils.isEmpty(execute)) {
|
||||||
|
throw new RuntimeException("执行结果错误");
|
||||||
|
}
|
||||||
|
return execute.getResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected EngineResult mockExecute(Long adapterId, String code, Object data, boolean development) {
|
||||||
|
//获取当当前接口对应的数据适配器
|
||||||
|
DataAdapter dataAdapter = dataAdapterMapper.selectById(adapterId);
|
||||||
|
if (ObjectUtils.isEmpty(dataAdapter)) {
|
||||||
|
throw new RuntimeException("dataAdapter is null");
|
||||||
|
}
|
||||||
|
dataAdapter.setCode(code);
|
||||||
|
handlerReader.preconditioning(dataAdapter);
|
||||||
|
EngineResult execute = handlerReader.execute(dataAdapter, data, development);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
package cn.fateverse.query.handler.adapter;
|
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 cn.fateverse.query.entity.bo.PortalBo;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Clay
|
* @author Clay
|
||||||
* @date 2023-10-31 20:52
|
* @date 2023-10-31 20:52
|
||||||
@@ -12,19 +14,27 @@ public interface DataAdapterHandler {
|
|||||||
/**
|
/**
|
||||||
* 模拟执行
|
* 模拟执行
|
||||||
*
|
*
|
||||||
* @param dataAdapter 数据适配器信息
|
* @param portal 接口对象
|
||||||
* @param portal
|
* @param mockParam 请求头
|
||||||
* @return 执行结果
|
* @return 执行结果
|
||||||
*/
|
*/
|
||||||
Object mockExecute(DataAdapter dataAdapter, PortalBo portal, Object param);
|
Object mockExecute(PortalBo portal, MockParam mockParam);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 真实执行
|
* 真实执行
|
||||||
*
|
*
|
||||||
* @param dataAdapter 数据适配器信息
|
* @param portal 接口对象
|
||||||
* @param portal
|
* @param request
|
||||||
* @return 执行结果
|
* @return 执行结果
|
||||||
*/
|
*/
|
||||||
Object execute(DataAdapter dataAdapter, PortalBo portal, Object param);
|
Object execute(PortalBo portal, HttpServletRequest request);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除数据适配器
|
||||||
|
*
|
||||||
|
* @param adapterId 数据适配器id
|
||||||
|
* @return 删除结果
|
||||||
|
*/
|
||||||
|
boolean remove(Long adapterId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package cn.fateverse.query.handler.adapter.impl;
|
||||||
|
|
||||||
|
import cn.fateverse.common.core.exception.CustomException;
|
||||||
|
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 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.web.client.RestTemplate;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Clay
|
||||||
|
* @date 2024/4/19 22:12
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class ExternalDataAdapterHandler extends AbstractDataAdapterHandler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求对象
|
||||||
|
*/
|
||||||
|
private final RestTemplate restTemplate;
|
||||||
|
|
||||||
|
public ExternalDataAdapterHandler(DataAdapterMapper dataAdapterMapper,
|
||||||
|
EngineExecuteHandlerReader handlerReader,
|
||||||
|
RestTemplate restTemplate) {
|
||||||
|
super(dataAdapterMapper, handlerReader);
|
||||||
|
this.restTemplate = restTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object mockExecute(PortalBo portal, MockParam mockParam) {
|
||||||
|
if (!PortalEnum.EXTERNAL.equals(portal.getType())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
|
||||||
|
headers.setContentType(type);
|
||||||
|
headers.add("Accept", MediaType.APPLICATION_JSON.toString());
|
||||||
|
HashMap<String, Object> map = new HashMap<>();
|
||||||
|
JSONObject response = null;
|
||||||
|
switch (portal.getRequestMethod()) {
|
||||||
|
case "GET":
|
||||||
|
response = restTemplate.getForObject(portal.getUrl(), JSONObject.class, map);
|
||||||
|
break;
|
||||||
|
case "POST":
|
||||||
|
response = restTemplate.postForObject(portal.getUrl(), map, JSONObject.class);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new CustomException("请求方式错误");
|
||||||
|
}
|
||||||
|
if (portal.getCreateDataAdapter()) {
|
||||||
|
return super.execute(portal.getAdapterId(), response, true);
|
||||||
|
} else {
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object execute(PortalBo portal, HttpServletRequest request) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,20 +2,23 @@ package cn.fateverse.query.handler.adapter.impl;
|
|||||||
|
|
||||||
import cn.fateverse.common.core.exception.CustomException;
|
import cn.fateverse.common.core.exception.CustomException;
|
||||||
import cn.fateverse.common.core.result.page.TableDataInfo;
|
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.UniQuery;
|
||||||
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.enums.PortalEnum;
|
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.handler.reader.EngineExecuteHandlerReader;
|
||||||
|
import cn.fateverse.query.mapper.DataAdapterMapper;
|
||||||
import cn.fateverse.query.mapper.UniQueryMapper;
|
import cn.fateverse.query.mapper.UniQueryMapper;
|
||||||
import cn.fateverse.query.service.DynamicDataSearchService;
|
import cn.fateverse.query.service.DynamicDataSearchService;
|
||||||
import com.alibaba.fastjson2.JSON;
|
|
||||||
import com.alibaba.fastjson2.TypeReference;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
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.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -25,55 +28,86 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
public class LocalDataAdapterHandler implements DataAdapterHandler {
|
public class LocalDataAdapterHandler extends AbstractDataAdapterHandler {
|
||||||
|
|
||||||
|
|
||||||
private final UniQueryMapper uniQueryMapper;
|
private final UniQueryMapper uniQueryMapper;
|
||||||
|
|
||||||
private final EngineExecuteHandlerReader handlerReader;
|
|
||||||
|
|
||||||
private final DynamicDataSearchService dynamicDataSearchService;
|
private final DynamicDataSearchService dynamicDataSearchService;
|
||||||
|
|
||||||
public LocalDataAdapterHandler(UniQueryMapper uniQueryMapper,
|
public LocalDataAdapterHandler(UniQueryMapper uniQueryMapper,
|
||||||
|
DataAdapterMapper dataAdapterMapper,
|
||||||
EngineExecuteHandlerReader handlerReader,
|
EngineExecuteHandlerReader handlerReader,
|
||||||
DynamicDataSearchService dynamicDataSearchService) {
|
DynamicDataSearchService dynamicDataSearchService) {
|
||||||
|
super(dataAdapterMapper, handlerReader);
|
||||||
this.uniQueryMapper = uniQueryMapper;
|
this.uniQueryMapper = uniQueryMapper;
|
||||||
this.handlerReader = handlerReader;
|
|
||||||
this.dynamicDataSearchService = dynamicDataSearchService;
|
this.dynamicDataSearchService = dynamicDataSearchService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object mockExecute(DataAdapter dataAdapter, PortalBo portal, Object param) {
|
public Object mockExecute(PortalBo portal, MockParam mockParam) {
|
||||||
if (portal.getType() != PortalEnum.LOCAL) {
|
if (portal.getType() != PortalEnum.LOCAL) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
handlerReader.preconditioning(dataAdapter);
|
//自定义查询编辑查询对象
|
||||||
if (null == param) {
|
List<UniConDto> uniConList = new ArrayList<>();
|
||||||
throw new CustomException("参数对象不能为空");
|
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());
|
UniQuery query = uniQueryMapper.selectSampleById(portal.getQueryId());
|
||||||
if (null == query) {
|
if (null == query) {
|
||||||
throw new CustomException("数据源为空!");
|
throw new CustomException("数据源为空!");
|
||||||
}
|
}
|
||||||
//根据设置的参数动态调整当前是否需要分页操作
|
//根据设置的参数动态调整当前是否需要分页操作
|
||||||
TableDataInfo<Map<String, Object>> tableDataInfo = dynamicDataSearchService.searchData(info.getList(), query, null, Boolean.TRUE);
|
TableDataInfo<Map<String, Object>> tableDataInfo = dynamicDataSearchService.searchData(uniConList, query, null, Boolean.TRUE);
|
||||||
return handlerReader.execute(dataAdapter, tableDataInfo.getRows(), true);
|
if (portal.getCreateDataAdapter()) {
|
||||||
|
return super.mockExecute(portal.getAdapterId(), mockParam.getCode(), tableDataInfo.getRows(), true);
|
||||||
|
} else {
|
||||||
|
return tableDataInfo.getRows();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object execute(DataAdapter dataAdapter, PortalBo portal, Object param) {
|
public Object execute(PortalBo portal, HttpServletRequest request) {
|
||||||
if (portal.getType() != PortalEnum.LOCAL) {
|
if (portal.getType() != PortalEnum.LOCAL) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
handlerReader.preconditioning(dataAdapter);
|
//自定义查询编辑查询对象
|
||||||
List<Map<String, Object>> data = JSON.parseObject(dataAdapter.getMockData(), new TypeReference<List<Map<String, Object>>>() {
|
List<UniConDto> uniConList = new ArrayList<>();
|
||||||
});
|
//根据映射关系从request中获取请求参数
|
||||||
return handlerReader.execute(dataAdapter, data, false);
|
for (PortalMapping portalMapping : portal.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);
|
||||||
|
}
|
||||||
|
UniQuery query = uniQueryMapper.selectSampleById(portal.getQueryId());
|
||||||
|
if (null == query) {
|
||||||
|
throw new CustomException("数据源为空!");
|
||||||
|
}
|
||||||
|
//根据设置的参数动态调整当前是否需要分页操作
|
||||||
|
TableDataInfo<Map<String, Object>> tableDataInfo = dynamicDataSearchService.searchData(uniConList, query, null, Boolean.TRUE);
|
||||||
|
if (portal.getCreateDataAdapter()) {
|
||||||
|
return super.execute(portal.getAdapterId(), tableDataInfo.getRows(), false);
|
||||||
|
} else {
|
||||||
|
return tableDataInfo.getRows();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package cn.fateverse.query.handler.engine;
|
package cn.fateverse.query.handler.engine;
|
||||||
|
|
||||||
|
import cn.fateverse.common.code.model.EngineResult;
|
||||||
import cn.fateverse.query.entity.DataAdapter;
|
import cn.fateverse.query.entity.DataAdapter;
|
||||||
|
|
||||||
public interface EngineExecuteHandler {
|
public interface EngineExecuteHandler {
|
||||||
@@ -13,7 +14,7 @@ public interface EngineExecuteHandler {
|
|||||||
* @param development
|
* @param development
|
||||||
* @return JSONObject对象
|
* @return JSONObject对象
|
||||||
*/
|
*/
|
||||||
Object execute(DataAdapter dataAdapter, Object data, boolean development);
|
EngineResult execute(DataAdapter dataAdapter, Object data, boolean development);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 预处理数据适配器
|
* 预处理数据适配器
|
||||||
@@ -25,6 +26,7 @@ public interface EngineExecuteHandler {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除数据适配器
|
* 删除数据适配器
|
||||||
|
*
|
||||||
* @param dataAdapter 数据适配器
|
* @param dataAdapter 数据适配器
|
||||||
* @return 删除结果
|
* @return 删除结果
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package cn.fateverse.query.handler.engine.impl;
|
package cn.fateverse.query.handler.engine.impl;
|
||||||
|
|
||||||
import cn.fateverse.common.code.engine.JavaCodeEngine;
|
import cn.fateverse.common.code.engine.JavaCodeEngine;
|
||||||
|
import cn.fateverse.common.code.model.EngineResult;
|
||||||
import cn.fateverse.common.core.exception.CustomException;
|
import cn.fateverse.common.core.exception.CustomException;
|
||||||
import cn.fateverse.query.entity.DataAdapter;
|
import cn.fateverse.query.entity.DataAdapter;
|
||||||
import cn.fateverse.query.enums.DataAdapterType;
|
import cn.fateverse.query.enums.DataAdapterType;
|
||||||
@@ -31,8 +32,8 @@ public class JavaEngineExecuteHandler implements EngineExecuteHandler {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object execute(DataAdapter dataAdapter, Object data, boolean development) {
|
public EngineResult execute(DataAdapter dataAdapter, Object data, boolean development) {
|
||||||
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),
|
||||||
|
|||||||
@@ -1,12 +1,17 @@
|
|||||||
package cn.fateverse.query.handler.engine.impl;
|
package cn.fateverse.query.handler.engine.impl;
|
||||||
|
|
||||||
import cn.fateverse.common.code.engine.JavaScriptEngine;
|
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.entity.DataAdapter;
|
||||||
import cn.fateverse.query.enums.DataAdapterType;
|
import cn.fateverse.query.enums.DataAdapterType;
|
||||||
import cn.fateverse.query.handler.engine.EngineExecuteHandler;
|
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.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JavaScript 代码执行器
|
* JavaScript 代码执行器
|
||||||
*
|
*
|
||||||
@@ -18,19 +23,31 @@ import org.springframework.stereotype.Component;
|
|||||||
public class JavaScriptEngineExecuteHandler implements EngineExecuteHandler {
|
public class JavaScriptEngineExecuteHandler implements EngineExecuteHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object execute(DataAdapter dataAdapter, Object data, boolean development) {
|
public EngineResult execute(DataAdapter dataAdapter, Object data, boolean development) {
|
||||||
if (!DataAdapterType.JAVA_SCRIPT.equals(dataAdapter.getType())) {
|
if (!DataAdapterType.JAVA_SCRIPT.equals(dataAdapter.getType())) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return JavaScriptEngine.executeScript(dataAdapter.getExecuteCode(), "execute", data);
|
return JavaScriptEngine.execute(dataAdapter.getExecuteCode(), "execute" + dataAdapter.getAdapterId(), development, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Boolean preconditioning(DataAdapter dataAdapter) {
|
public Boolean preconditioning(DataAdapter dataAdapter) {
|
||||||
if (DataAdapterType.JAVA_SCRIPT.equals(dataAdapter.getType())) {
|
if (!DataAdapterType.JAVA_SCRIPT.equals(dataAdapter.getType())) {
|
||||||
return Boolean.TRUE;
|
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
|
@Override
|
||||||
|
|||||||
@@ -2,12 +2,13 @@ package cn.fateverse.query.handler.reader;
|
|||||||
|
|
||||||
|
|
||||||
import cn.fateverse.common.core.exception.CustomException;
|
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.entity.bo.PortalBo;
|
||||||
import cn.fateverse.query.handler.adapter.DataAdapterHandler;
|
import cn.fateverse.query.handler.adapter.DataAdapterHandler;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.util.List;
|
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) {
|
for (DataAdapterHandler dataAdapterHandler : handlerList) {
|
||||||
Object result = dataAdapterHandler.mockExecute(dataAdapter, portal, params);
|
Object result = dataAdapterHandler.mockExecute(portal, mockParam);
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
return result;
|
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) {
|
for (DataAdapterHandler dataAdapterHandler : handlerList) {
|
||||||
Object result = dataAdapterHandler.execute(dataAdapter, portal, params);
|
Object result = dataAdapterHandler.execute(portal, request);
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -49,5 +50,15 @@ public class DataAdapterHandlerReader {
|
|||||||
throw new CustomException("当前数据源类型不支持!");
|
throw new CustomException("当前数据源类型不支持!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean remove(Long adaptorId) {
|
||||||
|
for (DataAdapterHandler dataAdapterHandler : handlerList) {
|
||||||
|
boolean result = dataAdapterHandler.remove(adaptorId);
|
||||||
|
if (result) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package cn.fateverse.query.handler.reader;
|
package cn.fateverse.query.handler.reader;
|
||||||
|
|
||||||
|
import cn.fateverse.common.code.model.EngineResult;
|
||||||
import cn.fateverse.query.entity.DataAdapter;
|
import cn.fateverse.query.entity.DataAdapter;
|
||||||
import cn.fateverse.query.handler.engine.EngineExecuteHandler;
|
import cn.fateverse.query.handler.engine.EngineExecuteHandler;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -47,11 +48,11 @@ public class EngineExecuteHandlerReader {
|
|||||||
* @param data 数据列表
|
* @param data 数据列表
|
||||||
* @return 执行结果
|
* @return 执行结果
|
||||||
*/
|
*/
|
||||||
public Object execute(DataAdapter dataAdapter, Object data, boolean development) {
|
public EngineResult execute(DataAdapter dataAdapter, Object data, boolean development) {
|
||||||
// 遍历引擎执行处理器列表
|
// 遍历引擎执行处理器列表
|
||||||
for (EngineExecuteHandler engineExecuteHandler : handlerList) {
|
for (EngineExecuteHandler engineExecuteHandler : handlerList) {
|
||||||
// 执行数据适配器的处理方法
|
// 执行数据适配器的处理方法
|
||||||
Object result = engineExecuteHandler.execute(dataAdapter, data, development);
|
EngineResult result = engineExecuteHandler.execute(dataAdapter, data, development);
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,14 @@ public interface DataAdapterMapper {
|
|||||||
*/
|
*/
|
||||||
int update(DataAdapter dataAdapter);
|
int update(DataAdapter dataAdapter);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新代码
|
||||||
|
*
|
||||||
|
* @param dataAdapter 数据适配器
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int updateCode(DataAdapter dataAdapter);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除数据源适配器
|
* 删除数据源适配器
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -48,4 +48,28 @@ public interface PortalMapper {
|
|||||||
* @return 更新数量
|
* @return 更新数量
|
||||||
*/
|
*/
|
||||||
int insert(Portal portal);
|
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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,34 +70,13 @@ public class PortalDispatchServlet {
|
|||||||
portalBo = PortalBo.toPortalBo(portal, portalMappings);
|
portalBo = PortalBo.toPortalBo(portal, portalMappings);
|
||||||
redisTemplate.opsForValue().set(QueryConstant.PORTAL_KEY + portalBo.getPath() + ":" + portalBo.getRequestMethod(), portalBo);
|
redisTemplate.opsForValue().set(QueryConstant.PORTAL_KEY + portalBo.getPath() + ":" + portalBo.getRequestMethod(), portalBo);
|
||||||
}
|
}
|
||||||
//自定义查询编辑查询对象
|
|
||||||
SearchInfo searchInfo = new SearchInfo();
|
|
||||||
List<UniConDto> 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;
|
Object result = null;
|
||||||
if (portalBo.getState() == 1 || portalBo.getState() == 2) {
|
// if (portalBo.getState() == 1 || portalBo.getState() == 2) {
|
||||||
result = dataAdapterHandler.execute(dataAdapter, portalBo, searchInfo);
|
result = dataAdapterHandler.execute(portalBo, request);
|
||||||
} else {
|
// } else {
|
||||||
result = dataAdapterHandler.mockExecute(dataAdapter, portalBo, searchInfo);
|
// result = dataAdapterHandler.mockExecute(portalBo, request);
|
||||||
}
|
// }
|
||||||
//将返回结果放入response
|
//将返回结果放入response
|
||||||
ResponseRender.renderString(response, Result.ok(result));
|
ResponseRender.renderString(response, Result.ok(result));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -140,6 +140,7 @@ public class DispatchSyncService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (NacosException e) {
|
} catch (NacosException e) {
|
||||||
|
log.error("NacosException: {}", e.getMessage());
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,9 @@ public class DynamicDataSearchService {
|
|||||||
} else {
|
} else {
|
||||||
uniConList = uniConMapper.selectByQueryIdAndUcIdList(query.getId(), ids);
|
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) {
|
if (query.getType() == 1) {
|
||||||
SqlSelect select = new SqlSelect();
|
SqlSelect select = new SqlSelect();
|
||||||
select.setSelectSql(query.getUqSql());
|
select.setSelectSql(query.getUqSql());
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package cn.fateverse.query.service;
|
package cn.fateverse.query.service;
|
||||||
|
|
||||||
import cn.fateverse.common.core.result.page.TableDataInfo;
|
import cn.fateverse.common.core.result.page.TableDataInfo;
|
||||||
|
import cn.fateverse.query.entity.dto.MockParam;
|
||||||
import cn.fateverse.query.entity.dto.PortalDto;
|
import cn.fateverse.query.entity.dto.PortalDto;
|
||||||
import cn.fateverse.query.entity.query.PortalQuery;
|
import cn.fateverse.query.entity.query.PortalQuery;
|
||||||
import cn.fateverse.query.entity.vo.PortalIdWrapper;
|
import cn.fateverse.query.entity.vo.PortalIdWrapper;
|
||||||
@@ -21,6 +22,14 @@ public interface PortalService {
|
|||||||
*/
|
*/
|
||||||
PortalVo searchById(Long portalId);
|
PortalVo searchById(Long portalId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据id查询详情
|
||||||
|
*
|
||||||
|
* @param portalId id
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
PortalVo searchDetailById(Long portalId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询接口列表
|
* 查询接口列表
|
||||||
*
|
*
|
||||||
@@ -29,6 +38,23 @@ public interface PortalService {
|
|||||||
*/
|
*/
|
||||||
TableDataInfo<SimplePortalVo> searchList(PortalQuery query);
|
TableDataInfo<SimplePortalVo> searchList(PortalQuery query);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模拟执行
|
||||||
|
*
|
||||||
|
* @param mockParam 执行数据
|
||||||
|
* @return 执行结果
|
||||||
|
*/
|
||||||
|
Object mockExecute(MockParam mockParam);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取到模拟数据
|
||||||
|
*
|
||||||
|
* @param mockParam
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Object mockData(MockParam mockParam);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 保存接口信息
|
* 保存接口信息
|
||||||
*
|
*
|
||||||
@@ -44,4 +70,19 @@ public interface PortalService {
|
|||||||
* @return 修改完成后接口id和数据适配器id
|
* @return 修改完成后接口id和数据适配器id
|
||||||
*/
|
*/
|
||||||
PortalIdWrapper edit(PortalDto portalDto);
|
PortalIdWrapper edit(PortalDto portalDto);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取消发布
|
||||||
|
*
|
||||||
|
* @param portalId 接口id
|
||||||
|
*/
|
||||||
|
void cancel(Long portalId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除接口信息
|
||||||
|
*
|
||||||
|
* @param portalId 接口id
|
||||||
|
*/
|
||||||
|
void delete(Long portalId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,14 +3,14 @@ package cn.fateverse.query.service.impl;
|
|||||||
import cn.fateverse.common.core.exception.CustomException;
|
import cn.fateverse.common.core.exception.CustomException;
|
||||||
import cn.fateverse.common.core.result.page.TableDataInfo;
|
import cn.fateverse.common.core.result.page.TableDataInfo;
|
||||||
import cn.fateverse.common.mybatis.utils.PageUtils;
|
import cn.fateverse.common.mybatis.utils.PageUtils;
|
||||||
|
import cn.fateverse.query.entity.*;
|
||||||
import cn.fateverse.query.entity.bo.PortalBo;
|
import cn.fateverse.query.entity.bo.PortalBo;
|
||||||
|
import cn.fateverse.query.entity.dto.MockParam;
|
||||||
|
import cn.fateverse.query.entity.vo.DataAdapterVo;
|
||||||
import cn.fateverse.query.entity.vo.PortalIdWrapper;
|
import cn.fateverse.query.entity.vo.PortalIdWrapper;
|
||||||
|
import cn.fateverse.query.handler.reader.DataAdapterHandlerReader;
|
||||||
import cn.fateverse.query.portal.service.HandlerMethodService;
|
import cn.fateverse.query.portal.service.HandlerMethodService;
|
||||||
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.PortalMapping;
|
|
||||||
import cn.fateverse.query.entity.UniQuery;
|
|
||||||
import cn.fateverse.query.entity.dto.DataAdapterDto;
|
import cn.fateverse.query.entity.dto.DataAdapterDto;
|
||||||
import cn.fateverse.query.entity.dto.PortalDto;
|
import cn.fateverse.query.entity.dto.PortalDto;
|
||||||
import cn.fateverse.query.entity.query.PortalQuery;
|
import cn.fateverse.query.entity.query.PortalQuery;
|
||||||
@@ -32,7 +32,6 @@ import org.springframework.web.bind.annotation.RequestMethod;
|
|||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -57,19 +56,26 @@ public class PortalServiceImpl implements PortalService {
|
|||||||
|
|
||||||
private final PortalMappingMapper portalMappingMapper;
|
private final PortalMappingMapper portalMappingMapper;
|
||||||
|
|
||||||
|
|
||||||
|
private final DataAdapterHandlerReader handlerReader;
|
||||||
|
|
||||||
public PortalServiceImpl(PortalMapper portalMapper,
|
public PortalServiceImpl(PortalMapper portalMapper,
|
||||||
UniQueryMapper queryMapper,
|
UniQueryMapper queryMapper,
|
||||||
DataAdapterMapper adapterMapper,
|
DataAdapterMapper adapterMapper,
|
||||||
PortalMappingMapper portalMappingMapper,
|
PortalMappingMapper portalMappingMapper,
|
||||||
ThreadPoolTaskExecutor taskExecuteExecutor,
|
ThreadPoolTaskExecutor taskExecuteExecutor,
|
||||||
HandlerMethodService methodService) {
|
HandlerMethodService methodService,
|
||||||
|
DataAdapterHandlerReader handlerReader) {
|
||||||
this.portalMapper = portalMapper;
|
this.portalMapper = portalMapper;
|
||||||
this.queryMapper = queryMapper;
|
this.queryMapper = queryMapper;
|
||||||
this.adapterMapper = adapterMapper;
|
this.adapterMapper = adapterMapper;
|
||||||
this.portalMappingMapper = portalMappingMapper;
|
this.portalMappingMapper = portalMappingMapper;
|
||||||
this.methodService = methodService;
|
this.methodService = methodService;
|
||||||
|
this.handlerReader = handlerReader;
|
||||||
taskExecuteExecutor.execute(() -> {
|
taskExecuteExecutor.execute(() -> {
|
||||||
List<Portal> portalList = portalMapper.selectList(new PortalQuery());
|
PortalQuery query = new PortalQuery();
|
||||||
|
// query.setState(QueryConstant.PORTAL_PUBLISH);
|
||||||
|
List<Portal> portalList = portalMapper.selectList(query);
|
||||||
if (ObjectUtils.isEmpty(portalList)) {
|
if (ObjectUtils.isEmpty(portalList)) {
|
||||||
log.info("portal is empty!");
|
log.info("portal is empty!");
|
||||||
return;
|
return;
|
||||||
@@ -116,6 +122,20 @@ public class PortalServiceImpl implements PortalService {
|
|||||||
return portalVo;
|
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
|
@Override
|
||||||
public TableDataInfo<SimplePortalVo> searchList(PortalQuery query) {
|
public TableDataInfo<SimplePortalVo> searchList(PortalQuery query) {
|
||||||
PageUtils.startPage();
|
PageUtils.startPage();
|
||||||
@@ -162,6 +182,21 @@ public class PortalServiceImpl implements PortalService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object mockExecute(MockParam mockParam) {
|
||||||
|
Portal portal = portalMapper.selectById(mockParam.getPortalId());
|
||||||
|
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
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
@@ -176,7 +211,7 @@ public class PortalServiceImpl implements PortalService {
|
|||||||
if (ObjectUtils.isEmpty(uniQuery)) {
|
if (ObjectUtils.isEmpty(uniQuery)) {
|
||||||
throw new CustomException("未找到对应的查询接口!");
|
throw new CustomException("未找到对应的查询接口!");
|
||||||
}
|
}
|
||||||
portal.setState(0);
|
portal.setState(QueryConstant.PORTAL_DEV);
|
||||||
// 判断是否需要创建数据适配器
|
// 判断是否需要创建数据适配器
|
||||||
if (portal.getCreateDataAdapter()) {
|
if (portal.getCreateDataAdapter()) {
|
||||||
createDataAdapter(portalDto, portal);
|
createDataAdapter(portalDto, portal);
|
||||||
@@ -203,6 +238,7 @@ public class PortalServiceImpl implements PortalService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public PortalIdWrapper edit(PortalDto portalDto) {
|
public PortalIdWrapper edit(PortalDto portalDto) {
|
||||||
Portal portal = portalDto.toPortal();
|
Portal portal = portalDto.toPortal();
|
||||||
checkPortalType(portal);
|
checkPortalType(portal);
|
||||||
@@ -210,7 +246,6 @@ public class PortalServiceImpl implements PortalService {
|
|||||||
if (!ObjectUtils.isEmpty(old) && !old.getPortalId().equals(portal.getPortalId())) {
|
if (!ObjectUtils.isEmpty(old) && !old.getPortalId().equals(portal.getPortalId())) {
|
||||||
throw new CustomException("系统中存在当前请求路径");
|
throw new CustomException("系统中存在当前请求路径");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (portal.getCreateDataAdapter() != old.getCreateDataAdapter()) {
|
if (portal.getCreateDataAdapter() != old.getCreateDataAdapter()) {
|
||||||
if (portal.getCreateDataAdapter()) {
|
if (portal.getCreateDataAdapter()) {
|
||||||
createDataAdapter(portalDto, portal);
|
createDataAdapter(portalDto, portal);
|
||||||
@@ -218,51 +253,55 @@ public class PortalServiceImpl implements PortalService {
|
|||||||
adapterMapper.deleteById(old.getAdapterId());
|
adapterMapper.deleteById(old.getAdapterId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PortalBo portalBo = PortalBo.toPortalBo(portal, portalDto.getMappings());
|
portalMappingMapper.deleteByPortalId(portal.getPortalId());
|
||||||
//存在接口路径或者请求类型不同则需要重新发布
|
portalMapper.update(portal);
|
||||||
if (!old.getPath().equals(portal.getPath())
|
if (!ObjectUtils.isEmpty(portalDto.getMappings())) {
|
||||||
|| !old.getRequestMethod().equals(portal.getRequestMethod())) {
|
List<PortalMapping> mappings = portalDto.getMappings();
|
||||||
//先卸载接口,需要进行数据同步
|
for (PortalMapping mapping : mappings) {
|
||||||
unpublishPortal(old, true);
|
mapping.setPortalId(portal.getPortalId());
|
||||||
//注册新的映射
|
}
|
||||||
methodService.registerMapping(portalBo.getPath(), RequestMethod.valueOf(portalBo.getRequestMethod()), true);
|
portalMappingMapper.insertBatch(mappings);
|
||||||
}
|
}
|
||||||
//修改Redis中的数据信息
|
|
||||||
redisTemplate.opsForValue().set(QueryConstant.PORTAL_KEY + portalBo.getPath() + ":" + portalBo.getRequestMethod(), portalBo);
|
|
||||||
//返回接口id和适配器id
|
//返回接口id和适配器id
|
||||||
return PortalIdWrapper.builder()
|
return PortalIdWrapper.builder()
|
||||||
.portalId(String.valueOf(portal.getPortalId()))
|
.portalId(String.valueOf(portal.getPortalId()))
|
||||||
.adapterId(String.valueOf(portal.getAdapterId()))
|
.adapterId(String.valueOf(portal.getAdapterId()))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean mappingCheckEquals(List<PortalMapping> oldPortalMappingList, List<PortalMapping> mappings) {
|
@Override
|
||||||
if (ObjectUtils.isEmpty(oldPortalMappingList) && ObjectUtils.isEmpty(mappings)) {
|
public void cancel(Long portalId) {
|
||||||
return true;
|
Portal portal = portalMapper.selectById(portalId);
|
||||||
|
if (ObjectUtils.isEmpty(portal)) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (ObjectUtils.isEmpty(oldPortalMappingList) || ObjectUtils.isEmpty(mappings)) {
|
if (QueryConstant.PORTAL_DEV.equals(portal.getState())) {
|
||||||
return false;
|
throw new CustomException("当前状态错误");
|
||||||
}
|
}
|
||||||
Optional<PortalMapping> optional = mappings.stream().filter(ObjectUtils::isEmpty).findAny();
|
portalMapper.updateState(portalId, QueryConstant.PORTAL_DEV);
|
||||||
if (optional.isEmpty()) {
|
if (QueryConstant.PORTAL_PUBLISH.equals(portal.getState())) {
|
||||||
return false;
|
unpublishPortal(portal, Boolean.TRUE);
|
||||||
}
|
}
|
||||||
if (oldPortalMappingList.size() == mappings.size()) {
|
|
||||||
Map<Long, PortalMapping> oldPortalMappingMap = oldPortalMappingList.stream()
|
|
||||||
.collect(Collectors.toMap(PortalMapping::getMappingId, Function.identity()));
|
|
||||||
Map<Long, PortalMapping> 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
|
||||||
|
@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);
|
||||||
|
portalMapper.deleteById(portalId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发布接口
|
* 发布接口
|
||||||
*
|
*
|
||||||
@@ -302,7 +341,7 @@ public class PortalServiceImpl implements PortalService {
|
|||||||
if (ObjectUtils.isEmpty(dataAdapter.getType())) {
|
if (ObjectUtils.isEmpty(dataAdapter.getType())) {
|
||||||
throw new CustomException("请选择数据适配器类型!");
|
throw new CustomException("请选择数据适配器类型!");
|
||||||
}
|
}
|
||||||
dataAdapter.setAdapterName(portal.getPortalName() + "专用数据适配器!");
|
dataAdapter.setAdapterName(portal.getPortalName() + "专用");
|
||||||
dataAdapter.setCommon(Boolean.FALSE);
|
dataAdapter.setCommon(Boolean.FALSE);
|
||||||
//初始化对应的数据适配器
|
//初始化对应的数据适配器
|
||||||
dataAdapter.init();
|
dataAdapter.init();
|
||||||
|
|||||||
@@ -20,9 +20,10 @@
|
|||||||
<sql id="selectDataAdapterVo">
|
<sql id="selectDataAdapterVo">
|
||||||
select adapter_id,
|
select adapter_id,
|
||||||
adapter_name,
|
adapter_name,
|
||||||
`type`,
|
type,
|
||||||
common,
|
common,
|
||||||
code,
|
code,
|
||||||
|
execute_code,
|
||||||
mock_data,
|
mock_data,
|
||||||
create_by,
|
create_by,
|
||||||
create_time,
|
create_time,
|
||||||
@@ -35,8 +36,10 @@
|
|||||||
<select id="selectList" resultMap="DataAdapterResult">
|
<select id="selectList" resultMap="DataAdapterResult">
|
||||||
<include refid="selectDataAdapterVo"/>
|
<include refid="selectDataAdapterVo"/>
|
||||||
<where>
|
<where>
|
||||||
<if test="adapterName != null and adapterName != ''">and adapter_name like concat('%', #{adapterName}, '%')</if>
|
<if test="adapterName != null and adapterName != ''">and adapter_name like concat('%', #{adapterName},
|
||||||
<if test="type != null">and `type` = #{type}</if>
|
'%')
|
||||||
|
</if>
|
||||||
|
<if test="type != null">and type = #{type}</if>
|
||||||
<if test="common != null">and common = #{common}</if>
|
<if test="common != null">and common = #{common}</if>
|
||||||
</where>
|
</where>
|
||||||
</select>
|
</select>
|
||||||
@@ -58,7 +61,7 @@
|
|||||||
insert into data_adapter
|
insert into data_adapter
|
||||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||||
<if test="adapterName != null">adapter_name,</if>
|
<if test="adapterName != null">adapter_name,</if>
|
||||||
<if test="type != null">`type`,</if>
|
<if test="type != null">type,</if>
|
||||||
<if test="common != null">common,</if>
|
<if test="common != null">common,</if>
|
||||||
<if test="code != null">code,</if>
|
<if test="code != null">code,</if>
|
||||||
<if test="mockData != null">mock_data,</if>
|
<if test="mockData != null">mock_data,</if>
|
||||||
@@ -80,7 +83,7 @@
|
|||||||
update data_adapter
|
update data_adapter
|
||||||
<set>
|
<set>
|
||||||
<if test="adapterName != null">adapter_name = #{adapterName},</if>
|
<if test="adapterName != null">adapter_name = #{adapterName},</if>
|
||||||
<if test="type != null">`type` = #{type},</if>
|
<if test="type != null">type = #{type},</if>
|
||||||
<if test="code != null">code = #{code},</if>
|
<if test="code != null">code = #{code},</if>
|
||||||
<if test="mockData != null">mock_data = #{mockData},</if>
|
<if test="mockData != null">mock_data = #{mockData},</if>
|
||||||
<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
|
<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
|
||||||
@@ -89,6 +92,18 @@
|
|||||||
where adapter_id = #{adapterId}
|
where adapter_id = #{adapterId}
|
||||||
</update>
|
</update>
|
||||||
|
|
||||||
|
<update id="updateCode">
|
||||||
|
update data_adapter
|
||||||
|
<set>
|
||||||
|
<if test="code != null and code != ''">code = #{code},</if>
|
||||||
|
<if test="executeCode != null and executeCode != ''">execute_code = #{code},</if>
|
||||||
|
<if test="mockData != null and mockData != ''">mock_data = #{mockData},</if>
|
||||||
|
<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
|
||||||
|
<if test="updateTime != null ">update_time = #{updateTime},</if>
|
||||||
|
</set>
|
||||||
|
where adapter_id = #{adapterId}
|
||||||
|
</update>
|
||||||
|
|
||||||
<delete id="deleteById">
|
<delete id="deleteById">
|
||||||
delete
|
delete
|
||||||
from data_adapter
|
from data_adapter
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
type,
|
type,
|
||||||
request_method,
|
request_method,
|
||||||
create_data_adapter,
|
create_data_adapter,
|
||||||
|
page,
|
||||||
path,
|
path,
|
||||||
url,
|
url,
|
||||||
state,
|
state,
|
||||||
@@ -23,7 +24,6 @@
|
|||||||
remark
|
remark
|
||||||
from portal
|
from portal
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
<select id="selectById" resultType="cn.fateverse.query.entity.Portal">
|
<select id="selectById" resultType="cn.fateverse.query.entity.Portal">
|
||||||
<include refid="selectVo"/>
|
<include refid="selectVo"/>
|
||||||
where portal_id = #{portalId}
|
where portal_id = #{portalId}
|
||||||
@@ -32,9 +32,10 @@
|
|||||||
<select id="selectList" resultType="cn.fateverse.query.entity.Portal">
|
<select id="selectList" resultType="cn.fateverse.query.entity.Portal">
|
||||||
<include refid="selectVo"/>
|
<include refid="selectVo"/>
|
||||||
<where>
|
<where>
|
||||||
<if test="portalName != null and portalName != ''">and portal_name like concat('%', #{portalName}, '%') </if>
|
<if test="portalName != null and portalName != ''">and portal_name like concat('%', #{portalName}, '%')</if>
|
||||||
<if test="anonymity != null ">and anonymity = #{anonymity}</if>
|
<if test="anonymity != null ">and anonymity = #{anonymity}</if>
|
||||||
<if test="type != null">and type = #{type}</if>
|
<if test="type != null">and type = #{type}</if>
|
||||||
|
<if test="state != null">and state = #{state}</if>
|
||||||
<if test="path != null and path != ''">and path like concat('%', #{path}, '%')</if>
|
<if test="path != null and path != ''">and path like concat('%', #{path}, '%')</if>
|
||||||
</where>
|
</where>
|
||||||
</select>
|
</select>
|
||||||
@@ -52,6 +53,7 @@
|
|||||||
<if test="portalName != null">portal_name,</if>
|
<if test="portalName != null">portal_name,</if>
|
||||||
<if test="anonymity != null">anonymity,</if>
|
<if test="anonymity != null">anonymity,</if>
|
||||||
<if test="type != null">type,</if>
|
<if test="type != null">type,</if>
|
||||||
|
<if test="page != null">page,</if>
|
||||||
<if test="requestMethod != null">request_method,</if>
|
<if test="requestMethod != null">request_method,</if>
|
||||||
<if test="createDataAdapter != null">create_data_adapter,</if>
|
<if test="createDataAdapter != null">create_data_adapter,</if>
|
||||||
<if test="path != null">path,</if>
|
<if test="path != null">path,</if>
|
||||||
@@ -66,6 +68,7 @@
|
|||||||
<if test="portalName != null">#{portalName},</if>
|
<if test="portalName != null">#{portalName},</if>
|
||||||
<if test="anonymity != null">#{anonymity},</if>
|
<if test="anonymity != null">#{anonymity},</if>
|
||||||
<if test="type != null">#{type},</if>
|
<if test="type != null">#{type},</if>
|
||||||
|
<if test="page != null">#{page},</if>
|
||||||
<if test="requestMethod != null">#{requestMethod},</if>
|
<if test="requestMethod != null">#{requestMethod},</if>
|
||||||
<if test="createDataAdapter != null">#{createDataAdapter},</if>
|
<if test="createDataAdapter != null">#{createDataAdapter},</if>
|
||||||
<if test="path != null">#{path},</if>
|
<if test="path != null">#{path},</if>
|
||||||
@@ -75,4 +78,35 @@
|
|||||||
<if test="createTime != null ">#{createTime},</if>
|
<if test="createTime != null ">#{createTime},</if>
|
||||||
</trim>
|
</trim>
|
||||||
</insert>
|
</insert>
|
||||||
|
|
||||||
|
<update id="update">
|
||||||
|
update portal
|
||||||
|
<set>
|
||||||
|
<if test="queryId != null">query_id = #{queryId},</if>
|
||||||
|
<if test="adapterId != null">adapter_id = #{adapterId},</if>
|
||||||
|
<if test="portalName != null">portal_name = #{portalName},</if>
|
||||||
|
<if test="anonymity != null">anonymity = #{anonymity},</if>
|
||||||
|
<if test="type != null">type = #{type},</if>
|
||||||
|
<if test="page != null">type = #{page},</if>
|
||||||
|
<if test="requestMethod != null">request_method = #{requestMethod},</if>
|
||||||
|
<if test="createDataAdapter != null">create_data_adapter = #{createDataAdapter},</if>
|
||||||
|
<if test="path != null">path = #{path},</if>
|
||||||
|
<if test="url != null">url = #{url},</if>
|
||||||
|
<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
|
||||||
|
<if test="updateTime != null">update_time = #{updateTime},</if>
|
||||||
|
</set>
|
||||||
|
where portal_id = #{portalId}
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<update id="updateState">
|
||||||
|
update portal
|
||||||
|
set state = #{state}
|
||||||
|
where portal_id = #{portalId}
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<delete id="deleteById">
|
||||||
|
delete
|
||||||
|
from portal
|
||||||
|
where portal_id = #{portalId}
|
||||||
|
</delete>
|
||||||
</mapper>
|
</mapper>
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
<mapper namespace="cn.fateverse.query.mapper.PortalMappingMapper">
|
<mapper namespace="cn.fateverse.query.mapper.PortalMappingMapper">
|
||||||
<sql id="selectPortalMapping">
|
<sql id="selectPortalMapping">
|
||||||
select mapping_id, portal_id, mapping_key, mapping_type, mapping_value
|
select mapping_id, portal_id, mapping_key, mapping_type, mapping_value, input_type, description
|
||||||
from portal_mapping
|
from portal_mapping
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
@@ -23,10 +23,11 @@
|
|||||||
|
|
||||||
|
|
||||||
<insert id="insertBatch">
|
<insert id="insertBatch">
|
||||||
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, description)
|
||||||
values
|
values
|
||||||
<foreach collection="list" item="item" separator=",">
|
<foreach collection="list" item="item" separator=",">
|
||||||
(#{item.portalId}, #{item.mappingKey}, #{item.mappingType}, #{item.mappingValue})
|
(#{item.portalId}, #{item.mappingKey}, #{item.mappingType}, #{item.mappingValue}, #{item.inputType},
|
||||||
|
#{item.description})
|
||||||
</foreach>
|
</foreach>
|
||||||
</insert>
|
</insert>
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
package cn.fateverse.query;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.stream.*;
|
|
||||||
|
|
||||||
public class DataAdapter {
|
|
||||||
|
|
||||||
public static Object execute(List<Map<String, Object>> data) {
|
|
||||||
for (Map<String, Object> objectMap : data) {
|
|
||||||
objectMap.remove("oper_location");
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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<Object> list = new ArrayList<>();
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
|
||||||
|
Map<String, Object> 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<String>) s -> true);
|
||||||
|
|
||||||
|
jsEngine.eval(finalCode);
|
||||||
|
JSONObject jsonObject = new JSONObject();
|
||||||
|
jsonObject.put("foo", "sdsdsdsds");
|
||||||
|
Object res= funcCall.invokeFunction("execute1", jsonObject);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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<Object> 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<EngineResult> 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<EngineResult> 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<Object> 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<Object> 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<Object> objectEngineResult = JavaScriptEngine.executeScript(finalCode, "execute", "测试控制台输出");
|
||||||
|
//
|
||||||
|
// ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
// PrintStream oldOut = System.out;
|
||||||
|
// System.setOut(new PrintStream(baos));
|
||||||
|
|
||||||
|
|
||||||
|
// EngineResult<Object> 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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,10 +16,10 @@
|
|||||||
<maven.deploy.skip>true</maven.deploy.skip>
|
<maven.deploy.skip>true</maven.deploy.skip>
|
||||||
</properties>
|
</properties>
|
||||||
<modules>
|
<modules>
|
||||||
<module>monitor</module>
|
<!-- <module>monitor</module>-->
|
||||||
<!-- <module>code-gen-test-oracle</module>-->
|
<!-- <module>code-gen-test-oracle</module>-->
|
||||||
<!-- <module>code-gen-test-mysql</module>-->
|
<!-- <module>code-gen-test-mysql</module>-->
|
||||||
<module>sentinel-dashboard</module>
|
<!-- <module>sentinel-dashboard</module>-->
|
||||||
<!-- <module>sentinel-dashboard-pro</module>-->
|
<!-- <module>sentinel-dashboard-pro</module>-->
|
||||||
<!-- <module>xxl-job-admin</module>-->
|
<!-- <module>xxl-job-admin</module>-->
|
||||||
</modules>
|
</modules>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
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;
|
||||||
@@ -158,14 +159,14 @@ public class TriggerService {
|
|||||||
}
|
}
|
||||||
//获取到请求的返回结果
|
//获取到请求的返回结果
|
||||||
Map<String, Object> result = response.getBody();
|
Map<String, Object> result = response.getBody();
|
||||||
ScriptObjectMirror jsResult;
|
EngineResult engineResult;
|
||||||
try {
|
try {
|
||||||
//判断请求是否有效
|
//判断请求是否有效
|
||||||
if (response.getStatusCode() == HttpStatus.OK) {
|
if (response.getStatusCode() == HttpStatus.OK) {
|
||||||
jsResult = JavaScriptEngine.executeScript(http.getSuccess(), "handlerSuccess", result);
|
engineResult = JavaScriptEngine.execute(http.getSuccess(), "handlerSuccess", false, result);
|
||||||
operation.setState(OperationStateEnums.SUCCESS);
|
operation.setState(OperationStateEnums.SUCCESS);
|
||||||
} else {
|
} else {
|
||||||
jsResult = JavaScriptEngine.executeScript(http.getFail(), "handlerFail", result);
|
engineResult = JavaScriptEngine.execute(http.getFail(), "handlerFail", false, result);
|
||||||
operation.setState(OperationStateEnums.FAILURE);
|
operation.setState(OperationStateEnums.FAILURE);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -177,6 +178,7 @@ 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