andy 1 سال پیش
والد
کامیت
0f665de2cc

+ 1 - 1
src/main/java/com/scbfkj/uni/api/GenericApi.java

@@ -29,7 +29,7 @@ public class GenericApi {
         } else if (uri.endsWith("movedata")) {
             event = "3";
         } else if (uri.endsWith("query")) {
-            event = "9";
+            event = "0";
         }
         body.put("event", event);
 

+ 0 - 17
src/main/java/com/scbfkj/uni/library/CodeUtil.java

@@ -1,17 +0,0 @@
-package com.scbfkj.uni.library;
-
-import java.security.SecureRandom;
-
-public class CodeUtil {
-
-    private static final SecureRandom RANDOM = new SecureRandom();
-
-    public static String createCode(int size, String source) {
-        StringBuilder verifyCode = new StringBuilder(size);
-        int codesLen = source.length();
-        for (int i = 0; i < size; i++) {
-            verifyCode.append(source.charAt(RANDOM.nextInt(codesLen - 1)));
-        }
-        return verifyCode.toString();
-    }
-}

+ 119 - 111
src/main/java/com/scbfkj/uni/library/DataEncryptionUtil.java

@@ -96,7 +96,7 @@ public class DataEncryptionUtil {
      * @param data 待加密的数据
      * @return 加密后的数据
      */
-    private static String encryptBase64(String data) {
+    public static String encryptBase64(String data) {
         return Base64.getEncoder().encodeToString(data.getBytes(StandardCharsets.UTF_8));
     }
 
@@ -106,40 +106,65 @@ public class DataEncryptionUtil {
      * @param data 要解密的数据
      * @return 解密后的字符串
      */
-    private static String decryptBase64(String data) {
+    public static String decryptBase64(String data) {
         return new String(Base64.getDecoder().decode(data));
     }
 
-    private static byte[] encryptByType(byte[] data, String type, String key, String algorithm) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
-// 创建AES加密算法实例
-        Cipher cipher = Cipher.getInstance(algorithm);
 
-        // 创建密钥规则
-        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), type);
+    public static String signatureSHA(String data, String algorithm) throws NoSuchAlgorithmException {
+        // 创建MessageDigest对象,指定使用SHA算法
+        MessageDigest md = MessageDigest.getInstance(checkSHAAlgorithm(algorithm));
 
-        // 初始化加密模式
-        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
+        // 将数据转换为字节数组
+        byte[] dataBytes = data.getBytes();
 
         // 执行加密操作
-        return cipher.doFinal(data);
+        byte[] encryptedBytes = md.digest(dataBytes);
+
+        // 将加密后的字节数组转换为十六进制字符串
+        StringBuilder sb = new StringBuilder();
+        for (byte b : encryptedBytes) {
+            sb.append(String.format("%02x", b));
+        }
+
+        return sb.toString();
     }
 
-    private static byte[] decryptByType(byte[] encryptedData, String type, String key, String algorithm) throws Exception {
-        // 创建AES解密算法实例
-        Cipher cipher = Cipher.getInstance(algorithm);
 
-        // 创建密钥规则
-        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), type);
+    public static boolean verifySHA(String encryptedData, String algorithm, String sourceData) throws Exception {
+        return signatureSHA(sourceData, checkSHAAlgorithm(algorithm)).equals(encryptedData);
+    }
 
-        // 初始化解密模式
-        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
 
-        // 执行解密操作
-        byte[] decryptedBytes = cipher.doFinal(encryptedData);
+    public static String signatureMD5(String data) throws NoSuchAlgorithmException {
+        // 创建MessageDigest对象,指定使用MD5算法
+        MessageDigest md = MessageDigest.getInstance("MD5");
 
-        // 将解密后的字节数组转换为字符串
+        // 将数据转换为字节数组
+        byte[] dataBytes = data.getBytes();
 
-        return decryptedBytes;
+        // 执行加密操作
+        byte[] encryptedBytes = md.digest(dataBytes);
+
+        // 将加密后的字节数组转换为十六进制字符串
+        StringBuilder sb = new StringBuilder();
+        for (byte b : encryptedBytes) {
+            sb.append(String.format("%02x", b));
+        }
+
+        return sb.toString();
+    }
+
+    public static boolean verifyMD5(String data, String encryptedData) throws NoSuchAlgorithmException {
+        return signatureMD5(data).equals(encryptedData);
+    }
+
+    public static String encryptRSAByPublicKey(@Nonnull String data) throws Exception {
+        //返回base64编码后的字符串
+        return Base64.getEncoder().encodeToString(doFinalByKeyStr(0, data.getBytes(), publicKeyStr, TYPE, ALGORITHM, Cipher.ENCRYPT_MODE));
+    }
+    public static String decryptRSAByPrivateKey(@Nonnull String data) throws Exception {
+        return new String(doFinalByKeyStr(1, Base64.getDecoder().decode(data), privateKeyStr, TYPE, ALGORITHM, Cipher.DECRYPT_MODE));
     }
 
     /**
@@ -150,54 +175,32 @@ public class DataEncryptionUtil {
      * @return 加密后的数据,以Base64编码的字符串形式返回
      * @throws Exception 加密过程中可能抛出的异常
      */
-    private static String encryptDES(String data, String key) throws Exception {
+    public static String encryptDES(String data, String key) throws Exception {
         // 将加密后的字节数组转换为Base64编码的字符串
         return Base64.getEncoder().encodeToString(encryptByType(data.getBytes(), "DES", key, "DES/ECB/PKCS5Padding"));
     }
 
-    private static String decryptDES(String encryptedData, String key) throws Exception {
+    public static String decryptDES(String encryptedData, String key) throws Exception {
         // 将解密后的字节数组转换为字符串
         return new String(decryptByType(Base64.getDecoder().decode(encryptedData), "DES", key, "DES/ECB/PKCS5Padding"));
     }
 
-    private static String encryptAES(String data, String key) throws Exception {
+    public static String encryptAES(String data, String key) throws Exception {
         return Base64.getEncoder().encodeToString(encryptByType(data.getBytes(), "AES", key, "AES/ECB/PKCS5Padding"));
     }
 
-    private static String decryptAES(String encryptedData, String key) throws Exception {
+    public static String decryptAES(String encryptedData, String key) throws Exception {
         return new String(decryptByType(Base64.getDecoder().decode(encryptedData), "AES", key, "AES/ECB/PKCS5Padding"));
     }
 
-    private static String encrypt3DES(String data, String key) throws Exception {
+    public static String encrypt3DES(String data, String key) throws Exception {
         return Base64.getEncoder().encodeToString(encryptByType(data.getBytes(), "DESede", key, "DESede/ECB/PKCS5Padding"));
     }
 
-    private static String decrypt3DES(String encryptedData, String key) throws Exception {
+    public static String decrypt3DES(String encryptedData, String key) throws Exception {
         return new String(decryptByType(Base64.getDecoder().decode(encryptedData), "DESede", key, "DESede/ECB/PKCS5Padding"));
     }
 
-    private static byte[] doFinalByKeyStr(int mode, byte[] data, String keyStr, String type, String algorithm, int opmode) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
-
-        //根据转换的名称获取密码对象Cipher(转换的名称:算法/工作模式/填充模式)
-        Cipher cipher = Cipher.getInstance(algorithm);
-
-        switch (mode) {
-            case 1 -> {
-                //根据PKCS8编码密钥规范产生私钥对象
-                PrivateKey privateKey = getPrivateKey(keyStr, checkType(type));
-                //用私钥初始化此Cipher对象(解密模式)
-                cipher.init(opmode, privateKey);
-            }
-            default -> {
-                //根据PKCS8编码密钥规范产生私钥对象
-                PublicKey publicKey = getPublicKey(keyStr, checkType(type));
-                //用私钥初始化此Cipher对象(解密模式)
-                cipher.init(opmode, publicKey);
-            }
-        }
-
-        return cipher.doFinal(data);
-    }
 
     /**
      * 公钥加密(用于数据加密)
@@ -212,7 +215,6 @@ public class DataEncryptionUtil {
         return Base64.getEncoder().encodeToString(doFinalByKeyStr(0, data.getBytes(), publicKeyStr, type, algorithm, Cipher.ENCRYPT_MODE));
     }
 
-
     /**
      * 私钥解密(用于数据解密)
      *
@@ -224,10 +226,6 @@ public class DataEncryptionUtil {
     public static String decryptByPrivateKey(@Nonnull String data, @Nonnull String privateKeyStr, @Nonnull String type, @Nonnull String algorithm) throws Exception {
         return new String(doFinalByKeyStr(1, Base64.getDecoder().decode(data), privateKeyStr, type, algorithm, Cipher.DECRYPT_MODE));
     }
-    public static String decryptRSAByPrivateKey(@Nonnull String data) throws Exception {
-        return new String(doFinalByKeyStr(1, Base64.getDecoder().decode(data), privateKeyStr, TYPE, ALGORITHM, Cipher.DECRYPT_MODE));
-    }
-
 
     /**
      * 私钥加密(用于数据加密)
@@ -254,53 +252,88 @@ public class DataEncryptionUtil {
     }
 
 
-    public static String signatureSHA(String data, String algorithm) throws NoSuchAlgorithmException {
-        // 创建MessageDigest对象,指定使用SHA算法
-        MessageDigest md = MessageDigest.getInstance(checkSHAAlgorithm(algorithm));
+    /**
+     * RSA签名
+     *
+     * @param data      待签名数据
+     * @param priKey    私钥
+     * @param type      RSA或DSA
+     * @param algorithm SHA1或256
+     * @return 签名
+     * @throws Exception
+     */
+    public static String sign(String data, String priKey, String type, String algorithm) throws Exception {
+        return sign(data.getBytes(), Base64.getDecoder().decode(priKey), type, algorithm);
+    }
+    /**
+     * RSA校验数字签名
+     *
+     * @param data      待校验数据
+     * @param sign      数字签名
+     * @param pubKey    公钥
+     * @param type      RSA或DSA
+     * @param algorithm SHA1或256
+     * @return boolean 校验成功返回true,失败返回false
+     */
+    public static boolean verify(String data, String sign, String pubKey, String type, String algorithm) throws Exception {
+        return verify(data.getBytes(), Base64.getDecoder().decode(sign), Base64.getDecoder().decode(pubKey), type, algorithm);
+    }
 
-        // 将数据转换为字节数组
-        byte[] dataBytes = data.getBytes();
+    private static byte[] encryptByType(byte[] data, String type, String key, String algorithm) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
+// 创建AES加密算法实例
+        Cipher cipher = Cipher.getInstance(algorithm);
 
-        // 执行加密操作
-        byte[] encryptedBytes = md.digest(dataBytes);
+        // 创建密钥规则
+        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), type);
 
-        // 将加密后的字节数组转换为十六进制字符串
-        StringBuilder sb = new StringBuilder();
-        for (byte b : encryptedBytes) {
-            sb.append(String.format("%02x", b));
-        }
+        // 初始化加密模式
+        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
 
-        return sb.toString();
+        // 执行加密操作
+        return cipher.doFinal(data);
     }
 
+    private static byte[] decryptByType(byte[] encryptedData, String type, String key, String algorithm) throws Exception {
+        // 创建AES解密算法实例
+        Cipher cipher = Cipher.getInstance(algorithm);
 
-    public static boolean verifySHA(String encryptedData, String algorithm, String sourceData) throws Exception {
-        return signatureSHA(sourceData, checkSHAAlgorithm(algorithm)).equals(encryptedData);
-    }
+        // 创建密钥规则
+        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), type);
 
+        // 初始化解密模式
+        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
 
-    public static String signatureMD5(String data) throws NoSuchAlgorithmException {
-        // 创建MessageDigest对象,指定使用MD5算法
-        MessageDigest md = MessageDigest.getInstance("MD5");
+        // 执行解密操作
+        byte[] decryptedBytes = cipher.doFinal(encryptedData);
 
-        // 将数据转换为字节数组
-        byte[] dataBytes = data.getBytes();
+        // 将解密后的字节数组转换为字符串
 
-        // 执行加密操作
-        byte[] encryptedBytes = md.digest(dataBytes);
+        return decryptedBytes;
+    }
 
-        // 将加密后的字节数组转换为十六进制字符串
-        StringBuilder sb = new StringBuilder();
-        for (byte b : encryptedBytes) {
-            sb.append(String.format("%02x", b));
+    private static byte[] doFinalByKeyStr(int mode, byte[] data, String keyStr, String type, String algorithm, int opmode) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
+
+        //根据转换的名称获取密码对象Cipher(转换的名称:算法/工作模式/填充模式)
+        Cipher cipher = Cipher.getInstance(algorithm);
+
+        switch (mode) {
+            case 1 -> {
+                //根据PKCS8编码密钥规范产生私钥对象
+                PrivateKey privateKey = getPrivateKey(keyStr, checkType(type));
+                //用私钥初始化此Cipher对象(解密模式)
+                cipher.init(opmode, privateKey);
+            }
+            default -> {
+                //根据PKCS8编码密钥规范产生私钥对象
+                PublicKey publicKey = getPublicKey(keyStr, checkType(type));
+                //用私钥初始化此Cipher对象(解密模式)
+                cipher.init(opmode, publicKey);
+            }
         }
 
-        return sb.toString();
+        return cipher.doFinal(data);
     }
 
-    public static boolean verifyMD5(String data, String encryptedData) throws NoSuchAlgorithmException {
-        return signatureMD5(data).equals(encryptedData);
-    }
 
 
     private static PublicKey getPublicKey(String publicKeyStr, String type) throws NoSuchAlgorithmException, InvalidKeySpecException {
@@ -316,19 +349,6 @@ public class DataEncryptionUtil {
     }
 
 
-    /**
-     * RSA签名
-     *
-     * @param data      待签名数据
-     * @param priKey    私钥
-     * @param type      RSA或DSA
-     * @param algorithm SHA1或256
-     * @return 签名
-     * @throws Exception
-     */
-    public static String sign(String data, String priKey, String type, String algorithm) throws Exception {
-        return sign(data.getBytes(), Base64.getDecoder().decode(priKey), type, algorithm);
-    }
 
     private static String sign(byte[] data, byte[] priKey, String type, String algorithm) throws Exception {
         //创建PKCS8编码密钥规范
@@ -349,19 +369,7 @@ public class DataEncryptionUtil {
         return Base64.getEncoder().encodeToString(sign);
     }
 
-    /**
-     * RSA校验数字签名
-     *
-     * @param data      待校验数据
-     * @param sign      数字签名
-     * @param pubKey    公钥
-     * @param type      RSA或DSA
-     * @param algorithm SHA1或256
-     * @return boolean 校验成功返回true,失败返回false
-     */
-    public static boolean verify(String data, String sign, String pubKey, String type, String algorithm) throws Exception {
-        return verify(data.getBytes(), Base64.getDecoder().decode(sign), Base64.getDecoder().decode(pubKey), type, algorithm);
-    }
+
 
     private static boolean verify(byte[] data, byte[] sign, byte[] pubKey, String type, String algorithm) throws Exception {
         //返回转换指定算法的KeyFactory对象

+ 45 - 4
src/main/java/com/scbfkj/uni/library/DataFormatUtil.java

@@ -12,7 +12,7 @@ import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
-import java.util.Map;
+import java.util.*;
 
 public final class DataFormatUtil {
     private final static ObjectMapper objectMapper = new ObjectMapper();
@@ -26,7 +26,7 @@ public final class DataFormatUtil {
     }
 
     public static JsonNode toJsonNode(Object source) throws JsonProcessingException {
-            return objectMapper.readTree(toString(source));
+        return objectMapper.readTree(toString(source));
     }
 
     public static <T> T stringToBean(String source, Class<T> clazz) throws JsonProcessingException {
@@ -45,7 +45,8 @@ public final class DataFormatUtil {
         return objectMapper.readValue(source, ArrayNode.class);
     }
 
-    public static String toString(Object source) throws JsonProcessingException {
+    public static String toString(Object source)  {
+        if(Objects.isNull(source)) return null;
         if (source instanceof String || source instanceof Number)
             return source.toString();
         if (source instanceof LocalDate result) {
@@ -54,7 +55,11 @@ public final class DataFormatUtil {
         if (source instanceof LocalDateTime result) {
             return result.format(dateTimeFormatter);
         }
-        return objectMapper.writeValueAsString(source);
+        try {
+            return objectMapper.writeValueAsString(source);
+        } catch (JsonProcessingException e) {
+            return source.toString();
+        }
     }
 
     public static LocalDate toDate(Object dateObj) {
@@ -84,4 +89,40 @@ public final class DataFormatUtil {
     public static LocalDateTime stringToDateTime(String dateTimeStr) {
         return LocalDateTime.parse(dateTimeStr);
     }
+
+    public static List<?> toList(Object value) {
+        if (Objects.isNull(value)) return null;
+        ArrayList<Object> result = new ArrayList<>();
+        if (value instanceof Iterable<?> iterable) {
+            iterable.forEach(result::add);
+            return result;
+        }
+        if (value.getClass().isArray()) {
+            result.addAll(Arrays.asList(((Object[]) value)));
+            return result;
+        }
+        return Collections.singletonList(value);
+    }
+    public static Object[] toArray(Object value) {
+        if (Objects.isNull(value)) return null;
+
+        return Objects.requireNonNull(toList(value)).toArray();
+    }
+
+    public static Map<?, ?> toMap(Object value) {
+        if (Objects.isNull(value)) return null;
+        if (value instanceof Map<?, ?> map) {
+            return map;
+        }
+        if (value instanceof String str) {
+            try {
+                return DataFormatUtil.stringToMap(str);
+            } catch (JsonProcessingException ignored) {
+
+            }
+        }
+        return new HashMap<>() {{
+            put("root", value);
+        }};
+    }
 }

+ 0 - 4
src/main/java/com/scbfkj/uni/library/JavaUtil.java

@@ -1,4 +0,0 @@
-package com.scbfkj.uni.library;
-
-public class JavaUtil {
-}

+ 136 - 0
src/main/java/com/scbfkj/uni/library/script/JavaScriptEngineUtil.java

@@ -0,0 +1,136 @@
+package com.scbfkj.uni.library.script;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.scbfkj.uni.library.DataFormatUtil;
+import org.apache.commons.pool2.BaseKeyedPooledObjectFactory;
+import org.apache.commons.pool2.KeyedObjectPool;
+import org.apache.commons.pool2.PooledObject;
+import org.apache.commons.pool2.impl.DefaultPooledObject;
+import org.apache.commons.pool2.impl.GenericKeyedObjectPool;
+
+import java.io.File;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+public class JavaScriptEngineUtil {
+
+    private static class JavaApply {
+        private Object instance;
+        private Method apply;
+        private Method close;
+
+        public JavaApply(Object instance, Method apply, Method close) {
+            this.instance = instance;
+            this.apply = apply;
+            this.close = close;
+        }
+
+        public Object getInstance() {
+            return instance;
+        }
+
+        public void setInstance(Object instance) {
+            this.instance = instance;
+        }
+
+        public Method getApply() {
+            return apply;
+        }
+
+        public void setApply(Method apply) {
+            this.apply = apply;
+        }
+
+        public Method getClose() {
+            return close;
+        }
+
+        public void setClose(Method close) {
+            this.close = close;
+        }
+
+        public void invokeClose() throws InvocationTargetException, IllegalAccessException {
+            if (Objects.nonNull(close)) {
+                close.invoke(instance);
+            }
+        }
+
+        public Object invokeApply(Object... args) throws InvocationTargetException, IllegalAccessException {
+            return apply.invoke(instance, args);
+        }
+    }
+
+    private final static KeyedObjectPool<String, JavaApply> javaRefPool = new GenericKeyedObjectPool<>(new BaseKeyedPooledObjectFactory<String, JavaApply>() {
+        @Override
+        public JavaApply create(String key) throws Exception {
+            JsonNode jsonNode = DataFormatUtil.toJsonNode(key);
+            JsonNode path = jsonNode.get("path");
+            JsonNode className = jsonNode.get("className");
+            JsonNode method = jsonNode.get("methodName");
+            if (Objects.nonNull(path)) {
+                File file = new File(System.getProperty("user.dir").concat(File.separator).concat("plugins").concat(File.separator).concat(path.asText()));
+                if (!file.exists()) {
+                    throw new RuntimeException("外部文件加载不存在:".concat(System.getProperty("user.dir")).concat(File.separator).concat("plugins").concat(File.separator).concat(path.asText()));
+                }
+                Method addURLMethod = null;
+
+                boolean accessible = false;
+                try {
+                    addURLMethod = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
+                    URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
+                    accessible = addURLMethod.canAccess(null); //获取方法的访问权限以便恢复:判读是否可以访问: true  代表可以访问
+                    if (!accessible) { //判读是否可以访问,如果是false,那就必须setAccessible(true)
+                        addURLMethod.setAccessible(true);//实际上是为了提效
+                    }
+                    addURLMethod.invoke(classLoader, file.toURI().toURL());//加载到系统中
+                } finally {
+                    if (addURLMethod != null && !accessible) {
+                        addURLMethod.setAccessible(false);//恢复原访问权限
+                    }
+                }
+            }
+            Class<?> classExample = Class.forName(className.asText()); //获取类实例
+            Object classInstance = classExample.getConstructor().newInstance();//类实例接口 无参数构造
+            Method javaMethod = null;
+            Method closeMethod = null;
+            for (Method currentMethod : classExample.getMethods()) {//循环所有方法
+                String methodName = currentMethod.getName();
+                if (methodName.equals(method.asText())) {
+                    javaMethod = currentMethod;
+                } else if (methodName.equals("close")) {
+                    closeMethod = currentMethod;
+                }
+            }
+            return new JavaApply(classInstance, javaMethod, closeMethod);
+        }
+
+        @Override
+        public PooledObject<JavaApply> wrap(JavaApply value) {
+            return new DefaultPooledObject<>(value);
+        }
+
+        @Override
+        public void destroyObject(String key, PooledObject<JavaApply> p) throws Exception {
+            JavaApply javaApply = p.getObject();
+            javaApply.invokeClose();
+
+        }
+    });
+
+    public static Object invoke(Map<String, Object> datasource, String expression, List<Object> args) throws Exception {
+        datasource.put("methodName", expression);
+        String key = DataFormatUtil.toString(datasource);
+
+        JavaApply javaApply = javaRefPool.borrowObject(key);
+        try{
+            return javaApply.invokeApply(args.toArray());
+        }finally {
+            javaRefPool.returnObject(key,javaApply);
+        }
+    }
+}

+ 2 - 2
src/main/java/com/scbfkj/uni/library/ScriptEngineUtil.java → src/main/java/com/scbfkj/uni/library/script/JsScriptEngineUtil.java

@@ -1,4 +1,4 @@
-package com.scbfkj.uni.library;
+package com.scbfkj.uni.library.script;
 
 import org.apache.commons.pool2.BaseKeyedPooledObjectFactory;
 import org.apache.commons.pool2.KeyedObjectPool;
@@ -10,7 +10,7 @@ import org.graalvm.polyglot.Context;
 import org.graalvm.polyglot.Source;
 import org.graalvm.polyglot.Value;
 
-public final class ScriptEngineUtil {
+public final class JsScriptEngineUtil {
 
     private final static String TO_STRING_SCRIPT = """
             (value) => {

+ 0 - 46
src/main/java/com/scbfkj/uni/service/CodeCacheService.java

@@ -1,46 +0,0 @@
-package com.scbfkj.uni.service;
-
-import com.scbfkj.uni.process.DataBase;
-import com.scbfkj.uni.system.Config;
-import org.springframework.stereotype.Service;
-
-import java.time.LocalDateTime;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-@Service
-public class CodeCacheService {
-
-
-    public void addCode(String code, String sessionId, String appid, Long securitycodeeffective, String requestIp) throws Exception {
-//      使用数据库
-        LocalDateTime localDateTime = LocalDateTime.now().plusSeconds(securitycodeeffective);
-        String insertSql = "insert into tempsecuritycode(appid,requestip,sessionid,securitycode,expiretime) values (?,?,?,?,?)";
-        DataBase.updateBatch(Config.securityConnectionStr, insertSql, new ArrayList<>() {{
-            add(new Object[]{ appid, requestIp, sessionId, code, localDateTime});
-        }});
-        String deleteSql = "delete from tempsecuritycode where expiretime < ?";
-        DataBase.updateBatch(Config.securityConnectionStr, deleteSql, new ArrayList<>() {{
-            add(new Object[]{LocalDateTime.now()});
-        }});
-    }
-
-    public boolean check(String code, String sessionId, String appid, String requestIp) throws Exception {
-
-        String selectSql = "select * from tempsecuritycode where securitycode=? and sessionid=? and appid=? and requestip=?";
-        List<Map<String, Object>> map = DataBase.query(Config.securityConnectionStr, selectSql, new ArrayList<>() {{
-            add(new Object[]{code, sessionId, appid, requestIp});
-        }});
-        return !map.isEmpty();
-
-    }
-
-    public void remove(String code, String sessionId, String appid, String requestIp) throws Exception {
-        String deleteSql = "delete from tempsecuritycode where securitycode=? and sessionid=? and appid=? and requestip=?";
-        DataBase.updateBatch(Config.securityConnectionStr, deleteSql, new ArrayList<>() {{
-            add(new Object[]{code, sessionId, appid, requestIp});
-        }});
-
-    }
-}

+ 153 - 90
src/main/java/com/scbfkj/uni/service/DataProcessService.java

@@ -1,73 +1,108 @@
 package com.scbfkj.uni.service;
 
 import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.JsonNode;
 import com.jayway.jsonpath.JsonPath;
 import com.scbfkj.uni.library.DataAliasGetUtil;
 import com.scbfkj.uni.library.DataFormatUtil;
-import com.scbfkj.uni.library.ScriptEngineUtil;
+import com.scbfkj.uni.library.RequestUtil;
 import com.scbfkj.uni.library.UniReturnUtil;
+import com.scbfkj.uni.library.script.JavaScriptEngineUtil;
+import com.scbfkj.uni.library.script.JsScriptEngineUtil;
 import com.scbfkj.uni.process.DataBase;
 import com.scbfkj.uni.system.Config;
-import jakarta.el.MethodNotFoundException;
 
-import java.io.File;
-import java.lang.reflect.Method;
-import java.net.URL;
-import java.net.URLClassLoader;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
 import java.util.*;
-import java.util.stream.Collectors;
 
 
 public class DataProcessService {
 
 
-    public static Map<String, Object> process(Map<String, Object> inData) throws Exception {
-
-        Optional<String> serviceIdOpt = DataAliasGetUtil.getValue("serviceid", inData);
-        if (Objects.isNull(inData) || inData.isEmpty() || serviceIdOpt.isEmpty())
-            return UniReturnUtil.fail("服务编号不能为空");
+    public static Map<String, Object> process(Map<String, Object> inData) {
 
+        String lifecycleid = null;
+        Map<String, Object> result;
         List<Map<String, Object>> resource = new ArrayList<>();
         resource.add(inData);
-        String serviceId = serviceIdOpt.get();
+        Object algorithmlibraryid;
+        try {
+            Optional<String> serviceIdOpt = DataAliasGetUtil.getValue("serviceid", inData);
+            if (Objects.isNull(inData) || inData.isEmpty() || serviceIdOpt.isEmpty())
+                return UniReturnUtil.fail("服务编号不能为空");
+            String serviceId = serviceIdOpt.get();
+
+//        熔断
+
+            List<Map<String, Object>> algorithmLibraries;
+            if (serviceId.matches("^\\d+$")) {
+                algorithmLibraries = DataBase.query(Config.centerConnectionStr, "select * from algorithmlibrary where serviceid=?", Collections.singletonList(new Object[]{serviceId}));
+            } else {
+                algorithmLibraries = DataBase.query(Config.localCenterConnectionStr, "select * from algorithmlibrary where serviceid=?", Collections.singletonList(new Object[]{serviceId}));
+            }
 
-        List<Map<String, Object>> algorithmLibraries;
-        if(serviceId.matches("^\\d+$")){
-            algorithmLibraries  = DataBase.query(Config.centerConnectionStr, "select * from algorithmlibrary where serviceid=?", Collections.singletonList(new Object[]{serviceId}));
-        }else{
-            algorithmLibraries  = DataBase.query(Config.localCenterConnectionStr, "select * from algorithmlibrary where serviceid=?", Collections.singletonList(new Object[]{serviceId}));
-        }
+            Optional<String> lifecycleidOpt = DataAliasGetUtil.getValue("lifecycleid", inData);
+            if (lifecycleidOpt.isEmpty()) {
+                lifecycleid = createLifeCycleCol(Config.containerCode, serviceId);
+                inData.put("lifecycleid", lifecycleid);
+            } else {
+                lifecycleid = lifecycleidOpt.get();
+            }
 
-        for (Map<String, Object> algorithmLibrary : algorithmLibraries) {
-            resource.add(processByAlgorithm(algorithmLibrary, resource, null, null));
+            for (Map<String, Object> algorithmLibrary : algorithmLibraries) {
+
+                Object preConditions = algorithmLibrary.get("preconditions");
+                Object preparameterset = algorithmLibrary.get("preparameterset");
+                if (Objects.nonNull(preConditions)) {
+                    String preCode = preConditionScript(preConditions.toString(), resource, DataFormatUtil.toString(preparameterset));
+                    if (Objects.equals("2", preCode)) {
+                        return UniReturnUtil.success(resource.size() - 1);
+                    } else if (Objects.equals("1", preCode)) {
+                        resource.add(null);
+                        continue;
+                    }
+                }
+                algorithmlibraryid = algorithmLibrary.get("algorithmlibraryid");
+                Map<String, Object> algorithmResult = null;
+                try {
+                    algorithmResult = processByAlgorithm(algorithmLibrary, resource);
+                } catch (Exception e) {
+//                    把错误细化后往上一层抛出统一记录日志
+                    throw new RuntimeException("算法id: %s 异常信息:%s ".formatted(algorithmlibraryid, e.getMessage()));
+                }
+                if (!Objects.equals(algorithmResult.get("code"), "0")) {
+                    resource.add(algorithmResult);
+                } else {
+                    throw new RuntimeException(algorithmResult.get("message").toString());
+                }
+            }
+            result = resource.get(resource.size() - 1);
+        } catch (Exception e) {
+//            异常
+            LoggerService.logServiceError(RequestUtil.getIpAddr(), RequestUtil.getUri(), RequestUtil.getSessionId(), DataFormatUtil.toString(resource), null, "-1", e.getMessage(), lifecycleid);
+            return UniReturnUtil.fail(e.getMessage());
         }
-        return resource.get(resource.size() - 1);
+//        成功
+        LoggerService.logService(RequestUtil.getIpAddr(), RequestUtil.getUri(), RequestUtil.getSessionId(), DataFormatUtil.toString(inData), DataFormatUtil.toString(result), "0", null, lifecycleid);
+        return result;
     }
 
     /**
      * @param algorithmLibrary 算法配置
      * @param args             算法参数
-     * @param filterColumns    数据库执行的列权限
-     * @param filterLines      数据库执行的行权限
      * @return
      * @throws Exception
      */
-    public static Map<String, Object> processByAlgorithm(Map<String, Object> algorithmLibrary, List<Map<String, Object>> args, List<String> filterColumns, List<Map<String,Object>> filterLines) throws Exception {
+    public static Map<String, Object> processByAlgorithm(Map<String, Object> algorithmLibrary, List<Map<String, Object>> args) throws Exception {
 
+        List<String> filterColumns = Optional.ofNullable(args).map(it -> it.get(0)).map(it -> it.get("filterColumns")).map(it -> ((List<String>) it)).orElse(new ArrayList<>());
+        List<Map<String, Object>> filterLines = Optional.ofNullable(args).map(it -> it.get(0)).map(it -> it.get("filterLines")).map(it -> ((List<Map<String, Object>>) it)).orElse(new ArrayList<>());
         Object type = algorithmLibrary.get("algorithmtype");
         Object expression = algorithmLibrary.get("computingexpression");
         Object parameterSet = algorithmLibrary.get("parameterset");
-        Object preConditions = algorithmLibrary.get("preconditions");
         Object dataSourceId = algorithmLibrary.get("datasourceid");
         List<Map<String, Object>> datasourceList = DataBase.query(Config.centerConnectionStr, "select * from datasource where datasourceid=?", Collections.singletonList(new Object[]{dataSourceId}));
         Map<String, Object> datasource = datasourceList.get(0);
-        if (Objects.nonNull(preConditions)) {
-            String result = preConditionScript(preConditions.toString(), args);
-            if (Objects.equals("1", result) || Objects.equals("2", result)) {
-                return UniReturnUtil.success(result);
-            }
-        }
         List<Object> parameters = new ArrayList<>();
 //        获取入参列表
         if (Objects.nonNull(parameterSet)) {
@@ -81,70 +116,21 @@ public class DataProcessService {
         switch (type.toString()) {
 //            java反射
             case "1" -> {
-                Object connectset = datasource.get("connectset");
-                JsonNode jsonNode = DataFormatUtil.toJsonNode(connectset);
-                JsonNode path = jsonNode.get("path");
-                if (Objects.nonNull(path)) {
-                    File file = new File(System.getProperty("user.dir").concat(File.separator).concat("plugins").concat(File.separator).concat(path.asText()));
-                    if (!file.exists()) {
-                        throw new RuntimeException("外部文件加载不存在:".concat(System.getProperty("user.dir")).concat(File.separator).concat("plugins").concat(File.separator).concat(path.asText()));
-                    }
-                    Method addURLMethod = null;
-
-                    boolean accessible = false;
-                    try {
-                        addURLMethod = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
-                        URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
-                        accessible = addURLMethod.canAccess(null); //获取方法的访问权限以便恢复:判读是否可以访问: true  代表可以访问
-                        if (!accessible) { //判读是否可以访问,如果是false,那就必须setAccessible(true)
-                            addURLMethod.setAccessible(true);//实际上是为了提效
-                        }
-                        addURLMethod.invoke(classLoader, file.toURI().toURL());//加载到系统中
-                    } finally {
-                        if (addURLMethod != null && !accessible) {
-                            addURLMethod.setAccessible(false);//恢复原访问权限
-                        }
-                    }
-                }
-                JsonNode className = jsonNode.get("className");
-
-                Class<?> classExample = Class.forName(className.asText()); //获取类实例
-                Method javaMethod = null;
-                Method closeMethod = null;
-                Object classInstance = classExample.getConstructor().newInstance();//类实例接口 无参数构造
-                for (Method currentMethod : classExample.getMethods()) {//循环所有方法
-                    String methodName = currentMethod.getName();
-                    if (methodName.equals(expression)) {
-                        javaMethod = currentMethod;
-                    } else if (methodName.equals("close")) {
-                        closeMethod = currentMethod;
-                    }
-                }
-                if (Objects.isNull(javaMethod)) {
-                    throw new MethodNotFoundException(expression + ": 没找到");
-                }
-
-                Object invoke = javaMethod.invoke(classInstance, parameters.toArray());
-//                关闭 因为没有做实例的缓存 所以要关闭算法
-                if (Objects.nonNull(closeMethod)) {
-                    closeMethod.invoke(classInstance);
-                }
+                Object invoke = JavaScriptEngineUtil.invoke(datasource, expression.toString(), parameters);
                 return UniReturnUtil.success(invoke);
             }
 //            JS表达式
             case "2" -> {
-                return UniReturnUtil.success(ScriptEngineUtil.eval(expression.toString(), parameters));
+                return UniReturnUtil.success(JsScriptEngineUtil.eval(expression.toString(), parameters));
             }
 //            数据库
             case "3" -> {
 //                下放到Database中处理数据
-//                参数表达式顺序是 数据源连接字符串($.datasource.connectset),sql表达式($.algorithm.computingexpression),需要操作的值($.args[1].returnData),执行编号($.algorithm.executionnumber)
+//                参数表达式顺序是 数据源连接字符串(String.$.datasource.connectset),sql表达式(String.$.algorithm.computingexpression),需要操作的值(List.$.args[1].returnData),执行编号(String.$.algorithm.executionnumber)
                 return DataBase.exec(parameters.get(0).toString(), parameters.get(1).toString(), ((List<Map<String, Object>>) parameters.get(2)), parameters.get(3), filterColumns, filterLines);
-
-
             }
         }
-        return UniReturnUtil.fail("");
+        return UniReturnUtil.fail("算法类型不支持");
     }
 
     /**
@@ -153,19 +139,96 @@ public class DataProcessService {
      * @return
      * @throws Exception
      */
-    private static String preConditionScript(String script, List<Map<String, Object>> args) throws Exception {
-        return ScriptEngineUtil.eval(script, args);
+    private static String preConditionScript(String script, List<Map<String, Object>> args, String parameterSet) throws Exception {
+        if (Objects.isNull(parameterSet)) {
+            return JsScriptEngineUtil.eval(script, args);
+        } else {
+            List<Object> params = getParams(parameterSet, args);
+            return JsScriptEngineUtil.eval(script, params.toArray());
+        }
     }
 
     /**
-     * @param parameterSet 使用标准的jsonPath表达式 $.a.b[0].c,多个参数之间使用;;分隔
+     * @param parameterSet 使用标准的jsonPath表达式 String.$.a.b[0].c,String.abcc 多个参数之间使用;;分隔
      * @param source       jsonpath需要取值的数据源
      * @return
      */
     public static List<Object> getParams(String parameterSet, Object source) throws JsonProcessingException {
         String[] paths = parameterSet.split(";;");
         String json = DataFormatUtil.toString(source);
-        return Arrays.stream(paths).map(it -> JsonPath.read(json, it.trim())).toList();
+        List<Object> result = new ArrayList<>();
+
+        for (String it : paths) {
+            it = it.trim();
+            String type = it.split("\\.")[0];
+            String path = it.replace(type + ".", "");
+            Object value = null;
+//            $开头的使用标准的jsonPath
+            if (path.startsWith("$")) {
+                value = JsonPath.read(json, path);
+            } else if (path.startsWith("#")) {
+//                todo  缓存之类的特殊值
+
+//                不是使用$#开头的直接取后面的字符串
+            } else {
+                value = path;
+            }
+            if (Objects.isNull(value)) {
+                result.add(null);
+                continue;
+            }
+            if ("String".equalsIgnoreCase(type)) {
+                value = DataFormatUtil.toString(value);
+            } else if ("List".equalsIgnoreCase(type)) {
+                value = DataFormatUtil.toList(value);
+            } else if ("Array".equalsIgnoreCase(type)) {
+                value = DataFormatUtil.toArray(value);
+            } else if ("Map".equalsIgnoreCase(type)) {
+                value = DataFormatUtil.toMap(value);
+            } else if ("Long".equalsIgnoreCase(type)) {
+                value = Long.parseLong(value.toString());
+            } else if ("Integer".equalsIgnoreCase(type)) {
+                value = Integer.parseInt(value.toString());
+            } else if ("Double".equalsIgnoreCase(type)) {
+                value = Double.parseDouble(value.toString());
+            } else if ("Float".equalsIgnoreCase(type)) {
+                value = Float.parseFloat(value.toString());
+            } else if ("Boolean".equalsIgnoreCase(type)) {
+                value = Boolean.parseBoolean(value.toString());
+            } else if ("Datetime".equalsIgnoreCase(type)) {
+                String string = value.toString();
+                String patten = "yyyy-MM-dd HH:mm:ss";
+                if (string.contains("(")) {
+                    patten = string.substring(string.indexOf("(") + 1, string.length() - 1);
+                    string = string.substring(0, string.indexOf("("));
+                }
+                value = LocalDateTime.parse(string, DateTimeFormatter.ofPattern(patten));
+            }
+
+            result.add(value);
+        }
+        return result;
     }
 
+    private static long sequence = 0L;
+    private static long lastTimestamp = -1L;
+
+    public synchronized static String createLifeCycleCol(String containerCode, String serviceId) {
+        long timestamp = System.currentTimeMillis();
+        //如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常
+        if (lastTimestamp == timestamp) { //如果是同一时间生成的,则进行毫秒内序列
+            sequence++;
+            if (sequence > 999L) {//毫秒内序列溢出
+                sequence = 0;
+                while (lastTimestamp == System.currentTimeMillis()) {//阻塞到下一个毫秒,获得新的时间戳
+                }
+                timestamp = System.currentTimeMillis();
+            }
+        } else {
+            sequence = 0L;
+        }
+        lastTimestamp = timestamp;//上次生成ID的时间截
+        //移位并通过或运算拼到一起组成64位的ID
+        return String.valueOf(timestamp).concat(String.format("%03d", sequence)).concat(String.format("%6s", containerCode)).concat(String.format("%6s", serviceId)).replaceAll("\\s", "0");
+    }
 }

+ 47 - 8
src/main/java/com/scbfkj/uni/service/SecurityService.java

@@ -8,6 +8,7 @@ import org.springframework.stereotype.Service;
 import org.springframework.web.context.request.RequestAttributes;
 import org.springframework.web.context.request.RequestContextHolder;
 
+import java.security.SecureRandom;
 import java.time.LocalDateTime;
 import java.util.*;
 
@@ -27,12 +28,20 @@ public class SecurityService {
     @Value("${app.debug:false}")
     private boolean debug;
 
-    private final CodeCacheService codeCacheService;
 
-    public SecurityService(CodeCacheService codeCacheService) {
-        this.codeCacheService = codeCacheService;
+
+    private static final SecureRandom RANDOM = new SecureRandom();
+
+    private static String createCode(int size, String source) {
+        StringBuilder verifyCode = new StringBuilder(size);
+        int codesLen = source.length();
+        for (int i = 0; i < size; i++) {
+            verifyCode.append(source.charAt(RANDOM.nextInt(codesLen - 1)));
+        }
+        return verifyCode.toString();
     }
 
+
     //安全类服务
     //连接认证--获取连接令牌
 
@@ -177,7 +186,7 @@ public class SecurityService {
                     length = random.nextInt(max);
                 } while (length <= min);
             }
-            String code = CodeUtil.createCode(length, rule);
+            String code = createCode(length, rule);
             String base64Code = ImageUtil.stringToImage(code);
             String sessionId = RequestUtil.getSessionId();
             String ip = RequestUtil.getIpAddr();
@@ -185,7 +194,7 @@ public class SecurityService {
             if (Objects.nonNull(securityCodeEffectiveObj)) {
                 securityCodeEffective = Long.parseLong(securityCodeEffectiveObj.toString());
             }
-            codeCacheService.addCode(code, sessionId, appId, securityCodeEffective, ip);
+            addCode(code, sessionId, appId, securityCodeEffective, ip);
 
             Map<String, Object> data = new HashMap<>();
             data.put("verifyCodeImage", base64Code);
@@ -215,7 +224,7 @@ public class SecurityService {
 
         if (Objects.nonNull(securityCodeRule) && !debug) {
             code = DataEncryptionUtil.decryptRSAByPrivateKey(verifycode.get());
-            if (Objects.nonNull(securityCodeRule) && !codeCacheService.check(code, sessionId, appId, ip)) {
+            if (Objects.nonNull(securityCodeRule) && !check(code, sessionId, appId, ip)) {
                 return UniReturnUtil.fail("验证码错误");
             }
         }
@@ -266,9 +275,9 @@ public class SecurityService {
                 data.put("userstatus", "1");
             }
         }
-        data.put("userid",userId);
+        data.put("userid", userId);
         if (Objects.nonNull(securityCodeRule)) {
-            codeCacheService.remove(code, sessionId, appId, ip);
+            remove(code, sessionId, appId, ip);
         }
         return UniReturnUtil.success(data);
     }
@@ -415,5 +424,35 @@ public class SecurityService {
 
     }
 
+    public void addCode(String code, String sessionId, String appid, Long securitycodeeffective, String requestIp) throws Exception {
+//      使用数据库
+        LocalDateTime localDateTime = LocalDateTime.now().plusSeconds(securitycodeeffective);
+        String insertSql = "insert into tempsecuritycode(appid,requestip,sessionid,securitycode,expiretime) values (?,?,?,?,?)";
+        DataBase.updateBatch(Config.securityConnectionStr, insertSql, new ArrayList<>() {{
+            add(new Object[]{appid, requestIp, sessionId, code, localDateTime});
+        }});
+        String deleteSql = "delete from tempsecuritycode where expiretime < ?";
+        DataBase.updateBatch(Config.securityConnectionStr, deleteSql, new ArrayList<>() {{
+            add(new Object[]{LocalDateTime.now()});
+        }});
+    }
+
+    public boolean check(String code, String sessionId, String appid, String requestIp) throws Exception {
+
+        String selectSql = "select * from tempsecuritycode where securitycode=? and sessionid=? and appid=? and requestip=?";
+        List<Map<String, Object>> map = DataBase.query(Config.securityConnectionStr, selectSql, new ArrayList<>() {{
+            add(new Object[]{code, sessionId, appid, requestIp});
+        }});
+        return !map.isEmpty();
+
+    }
+
+    public void remove(String code, String sessionId, String appid, String requestIp) throws Exception {
+        String deleteSql = "delete from tempsecuritycode where securitycode=? and sessionid=? and appid=? and requestip=?";
+        DataBase.updateBatch(Config.securityConnectionStr, deleteSql, new ArrayList<>() {{
+            add(new Object[]{code, sessionId, appid, requestIp});
+        }});
+
+    }
 
 }

+ 5 - 5
src/test/java/com/scbfkj/uni/service/DataProcessServiceTest.java

@@ -17,7 +17,7 @@ class DataProcessServiceTest {
 
     @Test
     void getParams() throws JsonProcessingException {
-        List<Object> params = DataProcessService.getParams("$.a[0];;$.c", """
+        List<Object> params = DataProcessService.getParams("List.$.a[0];;map.$.c;;double.1;;Datetime.20231031000001(yyyyMMddHHmmss)", """
                 {"a":[{"b":10}],"c":{"d":"20"}}""");
         System.out.println(params);
     }
@@ -43,7 +43,7 @@ class DataProcessServiceTest {
                     }});
                 }});
             }});
-        }}, null, null);
+        }});
 
         System.out.println(map);
 
@@ -69,7 +69,7 @@ class DataProcessServiceTest {
                     }});
                 }});
             }});
-        }}, null, null);
+        }});
 
         System.out.println(map);
 
@@ -100,7 +100,7 @@ class DataProcessServiceTest {
                     }});
                 }});
             }});
-        }}, null, null);
+        }});
 
         System.out.println(DataFormatUtil.toString(map));
 
@@ -131,7 +131,7 @@ class DataProcessServiceTest {
                     }});
                 }});
             }});
-        }}, null, null);
+        }});
 
         System.out.println(DataFormatUtil.toString(map));