Просмотр исходного кода

【代码评审】IoT:产品脚本的逻辑

YunaiV 7 месяцев назад
Родитель
Сommit
eeb1dc4a07
20 измененных файлов с 111 добавлено и 75 удалено
  1. 1 0
      yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductScriptLanguageEnum.java
  2. 1 0
      yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductScriptStatusEnum.java
  3. 1 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductScriptDO.java
  4. 1 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductScriptServiceImpl.java
  5. 4 6
      yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/IotHttpPluginApplication.java
  6. 16 8
      yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/script/HttpScriptService.java
  7. 1 2
      yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/IotDeviceUpstreamServer.java
  8. 6 4
      yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDeviceUpstreamVertxHandler.java
  9. 1 0
      yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-script/src/main/java/cn/iocoder/yudao/module/iot/plugin/script/ScriptExample.java
  10. 3 2
      yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-script/src/main/java/cn/iocoder/yudao/module/iot/plugin/script/config/ScriptConfiguration.java
  11. 12 11
      yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-script/src/main/java/cn/iocoder/yudao/module/iot/plugin/script/context/PluginScriptContext.java
  12. 3 1
      yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-script/src/main/java/cn/iocoder/yudao/module/iot/plugin/script/context/ScriptContext.java
  13. 1 1
      yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-script/src/main/java/cn/iocoder/yudao/module/iot/plugin/script/engine/AbstractScriptEngine.java
  14. 12 12
      yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-script/src/main/java/cn/iocoder/yudao/module/iot/plugin/script/engine/JsScriptEngine.java
  15. 6 7
      yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-script/src/main/java/cn/iocoder/yudao/module/iot/plugin/script/engine/ScriptEngineFactory.java
  16. 11 9
      yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-script/src/main/java/cn/iocoder/yudao/module/iot/plugin/script/sandbox/JsSandbox.java
  17. 2 1
      yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-script/src/main/java/cn/iocoder/yudao/module/iot/plugin/script/sandbox/ScriptSandbox.java
  18. 6 5
      yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-script/src/main/java/cn/iocoder/yudao/module/iot/plugin/script/service/ScriptService.java
  19. 10 2
      yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-script/src/main/java/cn/iocoder/yudao/module/iot/plugin/script/service/ScriptServiceImpl.java
  20. 13 4
      yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-script/src/main/java/cn/iocoder/yudao/module/iot/plugin/script/util/ScriptUtils.java

+ 1 - 0
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductScriptLanguageEnum.java

@@ -43,4 +43,5 @@ public enum IotProductScriptLanguageEnum implements ArrayValuable<String> {
                 .findFirst()
                 .orElse(null);
     }
+
 }

+ 1 - 0
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductScriptStatusEnum.java

@@ -6,6 +6,7 @@ import lombok.Getter;
 
 import java.util.Arrays;
 
+// TODO @haohao:要不复用 commonstatus?
 /**
  * IoT 产品脚本状态枚举
  *

+ 1 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductScriptDO.java

@@ -8,6 +8,7 @@ import lombok.*;
 
 import java.time.LocalDateTime;
 
+// TODO @haohao:类似阿里云的脚本,貌似是一个?这个可以简化么?【微信讨论哈】类似阿里云,貌似是加了个 topic?
 /**
  * IoT 产品脚本信息 DO
  *

+ 1 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductScriptServiceImpl.java

@@ -26,6 +26,7 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU
 import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_NOT_EXISTS;
 import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_SCRIPT_NOT_EXISTS;
 
+// TODO @芋艿:后续再 review 哈!
 /**
  * IoT 产品脚本信息 Service 实现类
  *

+ 4 - 6
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/IotHttpPluginApplication.java

@@ -5,17 +5,15 @@ import org.springframework.boot.SpringApplication;
 import org.springframework.boot.WebApplicationType;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 
+// TODO @芋艿:是不是搞成 cn.iocoder.yudao.module.iot.plugin?或者 common、script 要自动配置
 /**
  * 独立运行入口
  */
 @Slf4j
 @SpringBootApplication(scanBasePackages = {
-        // common 的包
-        "cn.iocoder.yudao.module.iot.plugin.common",
-        // http 的包
-        "cn.iocoder.yudao.module.iot.plugin.http",
-        // script 的包
-        "cn.iocoder.yudao.module.iot.plugin.script"
+        "cn.iocoder.yudao.module.iot.plugin.common", // common 的包
+        "cn.iocoder.yudao.module.iot.plugin.http", // http 的包
+        "cn.iocoder.yudao.module.iot.plugin.script" // script 的包
 })
 public class IotHttpPluginApplication {
 

+ 16 - 8
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/script/HttpScriptService.java

@@ -13,7 +13,7 @@ import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
 /**
- * HTTP协议脚本处理服务
+ * HTTP 协议脚本处理服务
  * 用于管理和执行设备数据解析脚本
  *
  * @author haohao
@@ -25,8 +25,10 @@ public class HttpScriptService {
 
     private final ScriptService scriptService;
 
+    // TODO @haohao:后续可以考虑放到 guava 缓存
+    // TODO @haohao:可能要抽一个 script factory 之类的?方便多个 emqx、http 之类复用?
     /**
-     * 脚本缓存,按产品Key缓存脚本内容
+     * 脚本缓存,按产品 Key 缓存脚本内容
      */
     private final Map<String, String> scriptCache = new ConcurrentHashMap<>();
 
@@ -76,6 +78,7 @@ public class HttpScriptService {
                     productKey, deviceName, e);
         }
 
+        // TODO @芋艿:解析失败,是不是不能返回空?!
         // 解析失败,返回空数据
         return new HashMap<>();
     }
@@ -115,13 +118,14 @@ public class HttpScriptService {
                     productKey, deviceName, identifier, payload, result);
 
             // 处理结果
+            // TODO @haohao:处理结果,可以复用么?
             if (result instanceof Map) {
                 return (Map<String, Object>) result;
             } else if (result instanceof String) {
                 try {
                     return new JsonObject((String) result).getMap();
                 } catch (Exception e) {
-                    log.warn("[parseEventData][脚本返回的字符串不是有效的JSON] result:{}", result);
+                    log.warn("[parseEventData][脚本返回的字符串不是有效的 JSON] result:{}", result);
                 }
             }
         } catch (Exception e) {
@@ -129,6 +133,7 @@ public class HttpScriptService {
                     productKey, deviceName, identifier, e);
         }
 
+        // TODO @芋艿:解析失败,是不是不能返回空?!
         // 解析失败,返回空数据
         return new HashMap<>();
     }
@@ -191,10 +196,11 @@ public class HttpScriptService {
     /**
      * 设置产品解析脚本
      *
-     * @param productKey 产品Key
+     * @param productKey 产品 Key
      * @param script     脚本内容
      */
     public void setScript(String productKey, String script) {
+        // TODO @haohao:if return 会好点哈
         if (StrUtil.isNotBlank(productKey) && StrUtil.isNotBlank(script)) {
             // 验证脚本是否有效
             if (scriptService.validateScript("js", script)) {
@@ -209,13 +215,14 @@ public class HttpScriptService {
     /**
      * 清除产品解析脚本
      *
-     * @param productKey 产品Key
+     * @param productKey 产品 Key
      */
     public void clearScript(String productKey) {
-        if (StrUtil.isNotBlank(productKey)) {
-            scriptCache.remove(productKey);
-            log.info("[clearScript][清除产品:{}的解析脚本]", productKey);
+        if (StrUtil.isBlank(productKey)) {
+           return;
         }
+        scriptCache.remove(productKey);
+        log.info("[clearScript][清除产品({})的解析脚本]", productKey);
     }
 
     /**
@@ -225,4 +232,5 @@ public class HttpScriptService {
         scriptCache.clear();
         log.info("[clearAllScripts][清除所有脚本缓存]");
     }
+
 }

+ 1 - 2
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/IotDeviceUpstreamServer.java

@@ -35,8 +35,7 @@ public class IotDeviceUpstreamServer {
         router.route().handler(BodyHandler.create()); // 处理 Body
 
         // 使用统一的 Handler 处理所有上行请求
-        IotDeviceUpstreamVertxHandler upstreamHandler = new IotDeviceUpstreamVertxHandler(deviceUpstreamApi,
-                applicationContext);
+        IotDeviceUpstreamVertxHandler upstreamHandler = new IotDeviceUpstreamVertxHandler(deviceUpstreamApi, applicationContext);
         router.post(IotDeviceUpstreamVertxHandler.PROPERTY_PATH).handler(upstreamHandler);
         router.post(IotDeviceUpstreamVertxHandler.EVENT_PATH).handler(upstreamHandler);
 

+ 6 - 4
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDeviceUpstreamVertxHandler.java

@@ -1,5 +1,6 @@
 package cn.iocoder.yudao.module.iot.plugin.http.upstream.router;
 
+import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.IdUtil;
 import cn.hutool.core.util.ObjUtil;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
@@ -150,10 +151,11 @@ public class IotDeviceUpstreamVertxHandler implements Handler<RoutingContext> {
         Map<String, Object> properties = scriptService.parsePropertyData(productKey, deviceName, body);
 
         // 如果脚本解析结果为空,使用默认解析逻辑
-        if (properties.isEmpty()) {
+        // TODO @芋艿:注释说明一下,为什么要这么处理?
+        if (CollUtil.isNotEmpty(properties)) {
             properties = new HashMap<>();
-            Map<String, Object> params = body.getJsonObject("params") != null ? body.getJsonObject("params").getMap()
-                    : null;
+            Map<String, Object> params = body.getJsonObject("params") != null ?
+                    body.getJsonObject("params").getMap() : null;
             if (params != null) {
                 // 将标准格式的 params 转换为平台需要的 properties 格式
                 for (Map.Entry<String, Object> entry : params.entrySet()) {
@@ -193,7 +195,7 @@ public class IotDeviceUpstreamVertxHandler implements Handler<RoutingContext> {
         Map<String, Object> params = scriptService.parseEventData(productKey, deviceName, identifier, body);
 
         // 如果脚本解析结果为空,使用默认解析逻辑
-        if (params.isEmpty()) {
+        if (CollUtil.isNotEmpty(params)) {
             if (body.containsKey("params")) {
                 params = body.getJsonObject("params").getMap();
             } else {

+ 1 - 0
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-script/src/main/java/cn/iocoder/yudao/module/iot/plugin/script/ScriptExample.java

@@ -9,6 +9,7 @@ import org.springframework.stereotype.Component;
 import java.util.HashMap;
 import java.util.Map;
 
+// TODO @haohao:写到单测类里;
 /**
  * 脚本使用示例类
  */

+ 3 - 2
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-script/src/main/java/cn/iocoder/yudao/module/iot/plugin/script/config/ScriptConfiguration.java

@@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.iot.plugin.script.service.ScriptServiceImpl;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 
+// TODO @haohao:这个模块,是不是融合到 plugin-common 里哈?
 /**
  * 脚本模块配置类
  */
@@ -31,7 +32,7 @@ public class ScriptConfiguration {
     @Bean
     public ScriptService scriptService(ScriptEngineFactory engineFactory) {
         ScriptServiceImpl service = new ScriptServiceImpl();
-        // 如果有其他配置可以在这里设置
+        // TODO @haohao:如果有其他配置可以在这里设置
         return service;
     }
-} 
+}

+ 12 - 11
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-script/src/main/java/cn/iocoder/yudao/module/iot/plugin/script/context/PluginScriptContext.java

@@ -1,5 +1,7 @@
 package cn.iocoder.yudao.module.iot.plugin.script.context;
 
+import lombok.Getter;
+
 import java.util.HashMap;
 import java.util.Map;
 
@@ -11,18 +13,22 @@ public class PluginScriptContext implements ScriptContext {
     /**
      * 上下文参数
      */
+    @Getter
     private final Map<String, Object> parameters = new HashMap<>();
 
     /**
      * 上下文函数
      */
+    @Getter
     private final Map<String, Object> functions = new HashMap<>();
 
     /**
      * 日志函数接口
      */
     public interface LogFunction {
+
         void log(String message);
+
     }
 
     /**
@@ -46,16 +52,6 @@ public class PluginScriptContext implements ScriptContext {
         }
     }
 
-    @Override
-    public Map<String, Object> getParameters() {
-        return parameters;
-    }
-
-    @Override
-    public Map<String, Object> getFunctions() {
-        return functions;
-    }
-
     @Override
     public void setParameter(String key, Object value) {
         parameters.put(key, value);
@@ -71,6 +67,7 @@ public class PluginScriptContext implements ScriptContext {
         functions.put(name, function);
     }
 
+    // TODO @haohao:setParameters?这样的话,with 都是一些比较个性的参数
     /**
      * 批量设置参数
      *
@@ -87,11 +84,13 @@ public class PluginScriptContext implements ScriptContext {
     /**
      * 添加设备相关的上下文参数
      *
-     * @param deviceId   设备ID
+     * @param deviceId   设备 ID
      * @param deviceData 设备数据
      * @return 当前上下文对象
      */
+    // TODO @haohao:是不是加个 (String productKey, String deviceName, Map<String, Object> deviceData) {
     public PluginScriptContext withDeviceContext(String deviceId, Map<String, Object> deviceData) {
+        // TODO @haohao:deviceId 一般是分开,还是合并哈?
         parameters.put("deviceId", deviceId);
         parameters.put("deviceData", deviceData);
         return this;
@@ -110,6 +109,7 @@ public class PluginScriptContext implements ScriptContext {
         return this;
     }
 
+    // TODO @haohao:setParameter 可以融合哈?
     /**
      * 设置单个参数
      *
@@ -121,4 +121,5 @@ public class PluginScriptContext implements ScriptContext {
         parameters.put(key, value);
         return this;
     }
+
 }

+ 3 - 1
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-script/src/main/java/cn/iocoder/yudao/module/iot/plugin/script/context/ScriptContext.java

@@ -37,6 +37,7 @@ public interface ScriptContext {
      */
     Object getParameter(String key);
 
+    // TODO @haohao:这个要不也是 setFunction
     /**
      * 注册函数
      *
@@ -44,4 +45,5 @@ public interface ScriptContext {
      * @param function 函数对象
      */
     void registerFunction(String name, Object function);
-} 
+
+}

+ 1 - 1
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-script/src/main/java/cn/iocoder/yudao/module/iot/plugin/script/engine/AbstractScriptEngine.java

@@ -48,4 +48,4 @@ public abstract class AbstractScriptEngine {
     public void setSandbox(ScriptSandbox sandbox) {
         this.sandbox = sandbox;
     }
-} 
+}

+ 12 - 12
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-script/src/main/java/cn/iocoder/yudao/module/iot/plugin/script/engine/JsScriptEngine.java

@@ -12,8 +12,8 @@ import java.util.concurrent.Callable;
 import java.util.concurrent.ConcurrentHashMap;
 
 /**
- * JavaScript脚本引擎实现
- * 使用JSR-223 Nashorn脚本引擎
+ * JavaScript 脚本引擎实现
+ * 使用 JSR-223 Nashorn 脚本引擎
  */
 @Slf4j
 public class JsScriptEngine extends AbstractScriptEngine {
@@ -24,7 +24,7 @@ public class JsScriptEngine extends AbstractScriptEngine {
     private static final long DEFAULT_TIMEOUT_MS = 5000;
 
     /**
-     * JavaScript引擎名称
+     * JavaScript 引擎名称
      */
     private static final String JS_ENGINE_NAME = "nashorn";
 
@@ -45,25 +45,24 @@ public class JsScriptEngine extends AbstractScriptEngine {
 
     @Override
     public void init() {
-        log.info("初始化JavaScript脚本引擎");
+        log.info("初始化 JavaScript 脚本引擎");
 
         // 创建脚本引擎管理器
         engineManager = new ScriptEngineManager();
 
-        // 获取JavaScript引擎
+        // 获取 JavaScript 引擎
         engine = engineManager.getEngineByName(JS_ENGINE_NAME);
         if (engine == null) {
-            log.error("无法创建JavaScript引擎,尝试使用JavaScript名称获取");
+            log.error("无法创建JavaScript引擎,尝试使用 JavaScript 名称获取");
             engine = engineManager.getEngineByName("JavaScript");
         }
-
         if (engine == null) {
-            throw new IllegalStateException("无法创建JavaScript引擎,请检查环境配置");
+            throw new IllegalStateException("无法创建 JavaScript 引擎,请检查环境配置");
         }
 
         log.info("成功创建JavaScript引擎: {}", engine.getClass().getName());
 
-        // 默认使用JS沙箱
+        // 默认使用 JS 沙箱
         if (sandbox == null) {
             setSandbox(new JsSandbox());
         }
@@ -99,7 +98,7 @@ public class JsScriptEngine extends AbstractScriptEngine {
                 // 执行脚本
                 return engine.eval(script, bindings);
             } catch (ScriptException e) {
-                log.error("执行JavaScript脚本异常: {}", e.getMessage());
+                log.error("执行 JavaScript 脚本异常: {}", e.getMessage());
                 throw new RuntimeException("脚本执行异常: " + e.getMessage(), e);
             }
         };
@@ -136,7 +135,7 @@ public class JsScriptEngine extends AbstractScriptEngine {
                 // 执行脚本
                 return engine.eval(script, bindings);
             } catch (ScriptException e) {
-                log.error("执行JavaScript脚本异常: {}", e.getMessage());
+                log.error("执行 JavaScript 脚本异常: {}", e.getMessage());
                 throw new RuntimeException("脚本执行异常: " + e.getMessage(), e);
             }
         };
@@ -152,9 +151,10 @@ public class JsScriptEngine extends AbstractScriptEngine {
 
     @Override
     public void destroy() {
-        log.info("销毁JavaScript脚本引擎");
+        log.info("销毁 JavaScript 脚本引擎");
         cachedScripts.clear();
         engine = null;
         engineManager = null;
     }
+
 }

+ 6 - 7
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-script/src/main/java/cn/iocoder/yudao/module/iot/plugin/script/engine/ScriptEngineFactory.java

@@ -1,5 +1,6 @@
 package cn.iocoder.yudao.module.iot.plugin.script.engine;
 
+import cn.hutool.core.lang.Assert;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Component;
 
@@ -11,12 +12,12 @@ import org.springframework.stereotype.Component;
 public class ScriptEngineFactory {
 
     /**
-     * 创建JavaScript脚本引擎
+     * 创建 JavaScript 脚本引擎
      *
      * @return JavaScript脚本引擎
      */
     public JsScriptEngine createJsEngine() {
-        log.debug("创建JavaScript脚本引擎");
+        log.debug("创建 JavaScript 脚本引擎");
         return new JsScriptEngine();
     }
 
@@ -27,10 +28,7 @@ public class ScriptEngineFactory {
      * @return 脚本引擎
      */
     public AbstractScriptEngine createEngine(String scriptType) {
-        if (scriptType == null || scriptType.isEmpty()) {
-            throw new IllegalArgumentException("脚本类型不能为空");
-        }
-
+        Assert.notBlank(scriptType, "脚本类型不能为空");
         switch (scriptType.toLowerCase()) {
             case "js":
             case "javascript":
@@ -40,4 +38,5 @@ public class ScriptEngineFactory {
                 throw new IllegalArgumentException("不支持的脚本类型: " + scriptType);
         }
     }
-} 
+
+}

+ 11 - 9
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-script/src/main/java/cn/iocoder/yudao/module/iot/plugin/script/sandbox/JsSandbox.java

@@ -1,5 +1,6 @@
 package cn.iocoder.yudao.module.iot.plugin.script.sandbox;
 
+import cn.hutool.core.util.StrUtil;
 import lombok.extern.slf4j.Slf4j;
 
 import javax.script.ScriptEngine;
@@ -8,8 +9,9 @@ import java.util.HashSet;
 import java.util.Set;
 import java.util.regex.Pattern;
 
+// TODO @haohao:这个是不是融合到 ScriptEngine 里
 /**
- * JavaScript脚本沙箱,限制脚本的执行权限
+ * JavaScript 脚本沙箱,限制脚本的执行权限
  */
 @Slf4j
 public class JsSandbox implements ScriptSandbox {
@@ -34,6 +36,7 @@ public class JsSandbox implements ScriptSandbox {
                     "(?:\\bchild_process\\b)|" +
                     "(?:\\bwindow\\b)");
 
+    // TODO @haohao:这个没用到哈。
     /**
      * 脚本执行超时时间(毫秒)
      */
@@ -44,30 +47,28 @@ public class JsSandbox implements ScriptSandbox {
         if (!(engineContext instanceof ScriptEngine)) {
             throw new IllegalArgumentException("引擎上下文类型不正确,无法应用JavaScript沙箱");
         }
-
         ScriptEngine engine = (ScriptEngine) engineContext;
 
-        // 在Nashorn引擎中,可以通过以下方式设置安全限制
+        // 在 Nashorn 引擎中,可以通过以下方式设置安全限制
         try {
             // 设置严格模式
             String securityPrefix = "'use strict';\n";
 
-            // 禁用Java.type等访问系统资源的功能
+            // 禁用 Java.type 等访问系统资源的功能
             engine.eval("var Java = undefined;");
             engine.eval("var JavaImporter = undefined;");
             engine.eval("var Packages = undefined;");
 
             // 增强安全控制可以在这里添加
-            log.debug("已应用JavaScript安全沙箱限制");
-
+            log.debug("已应用 JavaScript 安全沙箱限制");
         } catch (Exception e) {
-            log.warn("应用JavaScript沙箱限制失败: {}", e.getMessage());
+            log.warn("应用 JavaScript 沙箱限制失败: {}", e.getMessage());
         }
     }
 
     @Override
     public boolean validateScript(String script) {
-        if (script == null || script.isEmpty()) {
+        if (StrUtil.isNotEmpty(script)) {
             return false;
         }
 
@@ -86,11 +87,12 @@ public class JsSandbox implements ScriptSandbox {
         }
 
         // 脚本长度限制
-        if (script.length() > 1024 * 100) { // 限制100KB
+        if (script.length() > 1024 * 100) { // 限制 100 KB
             log.warn("脚本太大,超过了限制");
             return false;
         }
 
         return true;
     }
+
 }

+ 2 - 1
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-script/src/main/java/cn/iocoder/yudao/module/iot/plugin/script/sandbox/ScriptSandbox.java

@@ -20,4 +20,5 @@ public interface ScriptSandbox {
      * @return 是否安全
      */
     boolean validateScript(String script);
-} 
+
+}

+ 6 - 5
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-script/src/main/java/cn/iocoder/yudao/module/iot/plugin/script/service/ScriptService.java

@@ -12,7 +12,7 @@ public interface ScriptService {
     /**
      * 执行脚本
      *
-     * @param scriptType 脚本类型(如js、groovy等)
+     * @param scriptType 脚本类型(如 js、groovy 等)
      * @param script     脚本内容
      * @param context    脚本上下文
      * @return 脚本执行结果
@@ -22,7 +22,7 @@ public interface ScriptService {
     /**
      * 执行脚本
      *
-     * @param scriptType 脚本类型(如js、groovy等)
+     * @param scriptType 脚本类型(如 js、groovy 等)
      * @param script     脚本内容
      * @param params     脚本参数
      * @return 脚本执行结果
@@ -30,7 +30,7 @@ public interface ScriptService {
     Object executeScript(String scriptType, String script, Map<String, Object> params);
 
     /**
-     * 执行JavaScript脚本
+     * 执行 JavaScript 脚本
      *
      * @param script  脚本内容
      * @param context 脚本上下文
@@ -39,7 +39,7 @@ public interface ScriptService {
     Object executeJavaScript(String script, ScriptContext context);
 
     /**
-     * 执行JavaScript脚本
+     * 执行 JavaScript 脚本
      *
      * @param script 脚本内容
      * @param params 脚本参数
@@ -55,4 +55,5 @@ public interface ScriptService {
      * @return 脚本是否安全
      */
     boolean validateScript(String scriptType, String script);
-} 
+
+}

+ 10 - 2
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-script/src/main/java/cn/iocoder/yudao/module/iot/plugin/script/service/ScriptServiceImpl.java

@@ -38,6 +38,7 @@ public class ScriptServiceImpl implements ScriptService {
     @PostConstruct
     public void init() {
         // 初始化常用的脚本引擎和沙箱
+        // TODO @haohao:js 是不是要枚举下哈。
         getEngine("js");
         sandboxCache.put("js", new JsSandbox());
     }
@@ -49,6 +50,7 @@ public class ScriptServiceImpl implements ScriptService {
             try {
                 engine.destroy();
             } catch (Exception e) {
+                // TODO @haohao:engine 类名
                 log.error("销毁脚本引擎失败", e);
             }
         }
@@ -58,6 +60,7 @@ public class ScriptServiceImpl implements ScriptService {
 
     @Override
     public Object executeScript(String scriptType, String script, ScriptContext context) {
+        // TODO @haohao:可以使用 hutool assert
         if (scriptType == null || script == null) {
             throw new IllegalArgumentException("脚本类型和内容不能为空");
         }
@@ -74,6 +77,7 @@ public class ScriptServiceImpl implements ScriptService {
             // 执行脚本
             return engine.execute(script, context);
         } catch (Exception e) {
+            // TODO @haohao:最好把 e 堆栈出来哈;然后,engine 类名
             log.error("执行脚本失败: {}", e.getMessage());
             throw new RuntimeException("执行脚本失败: " + e.getMessage(), e);
         }
@@ -83,16 +87,19 @@ public class ScriptServiceImpl implements ScriptService {
     public Object executeScript(String scriptType, String script, Map<String, Object> params) {
         // 创建默认上下文
         ScriptContext context = new PluginScriptContext(params);
+        // 执行脚本
         return executeScript(scriptType, script, context);
     }
 
     @Override
     public Object executeJavaScript(String script, ScriptContext context) {
+        // TODO @haohao:枚举哈
         return executeScript("js", script, context);
     }
 
     @Override
     public Object executeJavaScript(String script, Map<String, Object> params) {
+        // TODO @haohao:枚举哈
         return executeScript("js", script, params);
     }
 
@@ -100,7 +107,8 @@ public class ScriptServiceImpl implements ScriptService {
     public boolean validateScript(String scriptType, String script) {
         ScriptSandbox sandbox = sandboxCache.get(scriptType.toLowerCase());
         if (sandbox == null) {
-            log.warn("找不到脚本类型[{}]对应的沙箱,使用默认JS沙箱", scriptType);
+            // TODO @haohao:疑问,为啥默认 JsSandbox 哈?
+            log.warn("[validateScript][找不到脚本类型[{}]对应的沙箱,使用默认 JS 沙箱]", scriptType);
             sandbox = new JsSandbox();
             sandboxCache.put(scriptType.toLowerCase(), sandbox);
         }
@@ -120,4 +128,4 @@ public class ScriptServiceImpl implements ScriptService {
             return engine;
         });
     }
-} 
+}

+ 13 - 4
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-script/src/main/java/cn/iocoder/yudao/module/iot/plugin/script/util/ScriptUtils.java

@@ -6,6 +6,9 @@ import lombok.extern.slf4j.Slf4j;
 import java.util.Map;
 import java.util.concurrent.*;
 
+// TODO @haohao:【重要】 ScriptUtil.createGroovyEngine() 可以服用 hutool 的封装么?
+// TODO @haohao:【重要】 js 引擎,可能要看下 jdk8 的兼容性;
+// TODO @haohao:【重要】我们要不 script 配置的时候,支持 scriptType?!感觉会更通用一些???groovy、python、js
 /**
  * 脚本工具类,提供执行脚本的辅助方法
  */
@@ -66,6 +69,7 @@ public class ScriptUtils {
      * 关闭工具类的线程池
      */
     public static void shutdown() {
+        // TODO @芋艿:有没默认工具类,可以 shutdown
         SCRIPT_EXECUTOR.shutdown();
         try {
             if (!SCRIPT_EXECUTOR.awaitTermination(10, TimeUnit.SECONDS)) {
@@ -77,8 +81,9 @@ public class ScriptUtils {
         }
     }
 
+    // TODO @芋艿:要不要使用 JsonUtils
     /**
-     * 将JSON字符串转换为Map
+     * 将 JSON 字符串转换为 Map
      *
      * @param json JSON字符串
      * @return Map对象,转换失败则返回null
@@ -86,19 +91,20 @@ public class ScriptUtils {
     @SuppressWarnings("unchecked")
     public static Map<String, Object> parseJson(String json) {
         try {
-            // 使用hutool的JSONUtil工具类解析JSON
             return JSONUtil.toBean(json, Map.class);
         } catch (Exception e) {
-            log.error("解析JSON失败: {}", e.getMessage());
+            // TODO @haohao:json、e 都打印出来哈
+            log.error("[parseJson][解析JSON失败: {}]", e.getMessage());
             return null;
         }
     }
 
+    // TODO @芋艿:要不要封装成 utils
     /**
      * 尝试将对象转换为整数
      *
      * @param obj 需要转换的对象
-     * @return 转换后的整数,如果无法转换则返回null
+     * @return 转换后的整数,如果无法转换则返回 null
      */
     public static Integer toInteger(Object obj) {
         if (obj == null) {
@@ -122,6 +128,7 @@ public class ScriptUtils {
         return null;
     }
 
+    // TODO @芋艿:要不要封装成 utils
     /**
      * 尝试将对象转换为双精度浮点数
      *
@@ -158,10 +165,12 @@ public class ScriptUtils {
      * @return 如果两个数值相等则返回true,否则返回false
      */
     public static boolean numbersEqual(Number a, Number b) {
+        // TODO @haohao:NumberUtil.equals(1, 1D)
         if (a == null || b == null) {
             return a == b;
         }
 
         return Math.abs(a.doubleValue() - b.doubleValue()) < 0.0000001;
     }
+
 }