Commit eeb1dc4a077b451652dddde2cb1628082917daef
1 parent
0ae89327
【代码评审】IoT:产品脚本的逻辑
Showing
20 changed files
with
111 additions
and
75 deletions
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> { | @@ -43,4 +43,5 @@ public enum IotProductScriptLanguageEnum implements ArrayValuable<String> { | ||
| 43 | .findFirst() | 43 | .findFirst() |
| 44 | .orElse(null); | 44 | .orElse(null); |
| 45 | } | 45 | } |
| 46 | + | ||
| 46 | } | 47 | } |
| 47 | \ No newline at end of file | 48 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductScriptStatusEnum.java
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductScriptDO.java
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 | @@ -26,6 +26,7 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU | ||
| 26 | import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_NOT_EXISTS; | 26 | import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_NOT_EXISTS; |
| 27 | import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_SCRIPT_NOT_EXISTS; | 27 | import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_SCRIPT_NOT_EXISTS; |
| 28 | 28 | ||
| 29 | +// TODO @芋艿:后续再 review 哈! | ||
| 29 | /** | 30 | /** |
| 30 | * IoT 产品脚本信息 Service 实现类 | 31 | * IoT 产品脚本信息 Service 实现类 |
| 31 | * | 32 | * |
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; | @@ -5,17 +5,15 @@ import org.springframework.boot.SpringApplication; | ||
| 5 | import org.springframework.boot.WebApplicationType; | 5 | import org.springframework.boot.WebApplicationType; |
| 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; | 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; |
| 7 | 7 | ||
| 8 | +// TODO @芋艿:是不是搞成 cn.iocoder.yudao.module.iot.plugin?或者 common、script 要自动配置 | ||
| 8 | /** | 9 | /** |
| 9 | * 独立运行入口 | 10 | * 独立运行入口 |
| 10 | */ | 11 | */ |
| 11 | @Slf4j | 12 | @Slf4j |
| 12 | @SpringBootApplication(scanBasePackages = { | 13 | @SpringBootApplication(scanBasePackages = { |
| 13 | - // common 的包 | ||
| 14 | - "cn.iocoder.yudao.module.iot.plugin.common", | ||
| 15 | - // http 的包 | ||
| 16 | - "cn.iocoder.yudao.module.iot.plugin.http", | ||
| 17 | - // script 的包 | ||
| 18 | - "cn.iocoder.yudao.module.iot.plugin.script" | 14 | + "cn.iocoder.yudao.module.iot.plugin.common", // common 的包 |
| 15 | + "cn.iocoder.yudao.module.iot.plugin.http", // http 的包 | ||
| 16 | + "cn.iocoder.yudao.module.iot.plugin.script" // script 的包 | ||
| 19 | }) | 17 | }) |
| 20 | public class IotHttpPluginApplication { | 18 | public class IotHttpPluginApplication { |
| 21 | 19 |
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; | @@ -13,7 +13,7 @@ import java.util.Map; | ||
| 13 | import java.util.concurrent.ConcurrentHashMap; | 13 | import java.util.concurrent.ConcurrentHashMap; |
| 14 | 14 | ||
| 15 | /** | 15 | /** |
| 16 | - * HTTP协议脚本处理服务 | 16 | + * HTTP 协议脚本处理服务 |
| 17 | * 用于管理和执行设备数据解析脚本 | 17 | * 用于管理和执行设备数据解析脚本 |
| 18 | * | 18 | * |
| 19 | * @author haohao | 19 | * @author haohao |
| @@ -25,8 +25,10 @@ public class HttpScriptService { | @@ -25,8 +25,10 @@ public class HttpScriptService { | ||
| 25 | 25 | ||
| 26 | private final ScriptService scriptService; | 26 | private final ScriptService scriptService; |
| 27 | 27 | ||
| 28 | + // TODO @haohao:后续可以考虑放到 guava 缓存 | ||
| 29 | + // TODO @haohao:可能要抽一个 script factory 之类的?方便多个 emqx、http 之类复用? | ||
| 28 | /** | 30 | /** |
| 29 | - * 脚本缓存,按产品Key缓存脚本内容 | 31 | + * 脚本缓存,按产品 Key 缓存脚本内容 |
| 30 | */ | 32 | */ |
| 31 | private final Map<String, String> scriptCache = new ConcurrentHashMap<>(); | 33 | private final Map<String, String> scriptCache = new ConcurrentHashMap<>(); |
| 32 | 34 | ||
| @@ -76,6 +78,7 @@ public class HttpScriptService { | @@ -76,6 +78,7 @@ public class HttpScriptService { | ||
| 76 | productKey, deviceName, e); | 78 | productKey, deviceName, e); |
| 77 | } | 79 | } |
| 78 | 80 | ||
| 81 | + // TODO @芋艿:解析失败,是不是不能返回空?! | ||
| 79 | // 解析失败,返回空数据 | 82 | // 解析失败,返回空数据 |
| 80 | return new HashMap<>(); | 83 | return new HashMap<>(); |
| 81 | } | 84 | } |
| @@ -115,13 +118,14 @@ public class HttpScriptService { | @@ -115,13 +118,14 @@ public class HttpScriptService { | ||
| 115 | productKey, deviceName, identifier, payload, result); | 118 | productKey, deviceName, identifier, payload, result); |
| 116 | 119 | ||
| 117 | // 处理结果 | 120 | // 处理结果 |
| 121 | + // TODO @haohao:处理结果,可以复用么? | ||
| 118 | if (result instanceof Map) { | 122 | if (result instanceof Map) { |
| 119 | return (Map<String, Object>) result; | 123 | return (Map<String, Object>) result; |
| 120 | } else if (result instanceof String) { | 124 | } else if (result instanceof String) { |
| 121 | try { | 125 | try { |
| 122 | return new JsonObject((String) result).getMap(); | 126 | return new JsonObject((String) result).getMap(); |
| 123 | } catch (Exception e) { | 127 | } catch (Exception e) { |
| 124 | - log.warn("[parseEventData][脚本返回的字符串不是有效的JSON] result:{}", result); | 128 | + log.warn("[parseEventData][脚本返回的字符串不是有效的 JSON] result:{}", result); |
| 125 | } | 129 | } |
| 126 | } | 130 | } |
| 127 | } catch (Exception e) { | 131 | } catch (Exception e) { |
| @@ -129,6 +133,7 @@ public class HttpScriptService { | @@ -129,6 +133,7 @@ public class HttpScriptService { | ||
| 129 | productKey, deviceName, identifier, e); | 133 | productKey, deviceName, identifier, e); |
| 130 | } | 134 | } |
| 131 | 135 | ||
| 136 | + // TODO @芋艿:解析失败,是不是不能返回空?! | ||
| 132 | // 解析失败,返回空数据 | 137 | // 解析失败,返回空数据 |
| 133 | return new HashMap<>(); | 138 | return new HashMap<>(); |
| 134 | } | 139 | } |
| @@ -191,10 +196,11 @@ public class HttpScriptService { | @@ -191,10 +196,11 @@ public class HttpScriptService { | ||
| 191 | /** | 196 | /** |
| 192 | * 设置产品解析脚本 | 197 | * 设置产品解析脚本 |
| 193 | * | 198 | * |
| 194 | - * @param productKey 产品Key | 199 | + * @param productKey 产品 Key |
| 195 | * @param script 脚本内容 | 200 | * @param script 脚本内容 |
| 196 | */ | 201 | */ |
| 197 | public void setScript(String productKey, String script) { | 202 | public void setScript(String productKey, String script) { |
| 203 | + // TODO @haohao:if return 会好点哈 | ||
| 198 | if (StrUtil.isNotBlank(productKey) && StrUtil.isNotBlank(script)) { | 204 | if (StrUtil.isNotBlank(productKey) && StrUtil.isNotBlank(script)) { |
| 199 | // 验证脚本是否有效 | 205 | // 验证脚本是否有效 |
| 200 | if (scriptService.validateScript("js", script)) { | 206 | if (scriptService.validateScript("js", script)) { |
| @@ -209,13 +215,14 @@ public class HttpScriptService { | @@ -209,13 +215,14 @@ public class HttpScriptService { | ||
| 209 | /** | 215 | /** |
| 210 | * 清除产品解析脚本 | 216 | * 清除产品解析脚本 |
| 211 | * | 217 | * |
| 212 | - * @param productKey 产品Key | 218 | + * @param productKey 产品 Key |
| 213 | */ | 219 | */ |
| 214 | public void clearScript(String productKey) { | 220 | public void clearScript(String productKey) { |
| 215 | - if (StrUtil.isNotBlank(productKey)) { | ||
| 216 | - scriptCache.remove(productKey); | ||
| 217 | - log.info("[clearScript][清除产品:{}的解析脚本]", productKey); | 221 | + if (StrUtil.isBlank(productKey)) { |
| 222 | + return; | ||
| 218 | } | 223 | } |
| 224 | + scriptCache.remove(productKey); | ||
| 225 | + log.info("[clearScript][清除产品({})的解析脚本]", productKey); | ||
| 219 | } | 226 | } |
| 220 | 227 | ||
| 221 | /** | 228 | /** |
| @@ -225,4 +232,5 @@ public class HttpScriptService { | @@ -225,4 +232,5 @@ public class HttpScriptService { | ||
| 225 | scriptCache.clear(); | 232 | scriptCache.clear(); |
| 226 | log.info("[clearAllScripts][清除所有脚本缓存]"); | 233 | log.info("[clearAllScripts][清除所有脚本缓存]"); |
| 227 | } | 234 | } |
| 235 | + | ||
| 228 | } | 236 | } |
| 229 | \ No newline at end of file | 237 | \ No newline at end of file |
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 { | @@ -35,8 +35,7 @@ public class IotDeviceUpstreamServer { | ||
| 35 | router.route().handler(BodyHandler.create()); // 处理 Body | 35 | router.route().handler(BodyHandler.create()); // 处理 Body |
| 36 | 36 | ||
| 37 | // 使用统一的 Handler 处理所有上行请求 | 37 | // 使用统一的 Handler 处理所有上行请求 |
| 38 | - IotDeviceUpstreamVertxHandler upstreamHandler = new IotDeviceUpstreamVertxHandler(deviceUpstreamApi, | ||
| 39 | - applicationContext); | 38 | + IotDeviceUpstreamVertxHandler upstreamHandler = new IotDeviceUpstreamVertxHandler(deviceUpstreamApi, applicationContext); |
| 40 | router.post(IotDeviceUpstreamVertxHandler.PROPERTY_PATH).handler(upstreamHandler); | 39 | router.post(IotDeviceUpstreamVertxHandler.PROPERTY_PATH).handler(upstreamHandler); |
| 41 | router.post(IotDeviceUpstreamVertxHandler.EVENT_PATH).handler(upstreamHandler); | 40 | router.post(IotDeviceUpstreamVertxHandler.EVENT_PATH).handler(upstreamHandler); |
| 42 | 41 |
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 | package cn.iocoder.yudao.module.iot.plugin.http.upstream.router; | 1 | package cn.iocoder.yudao.module.iot.plugin.http.upstream.router; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.collection.CollUtil; | ||
| 3 | import cn.hutool.core.util.IdUtil; | 4 | import cn.hutool.core.util.IdUtil; |
| 4 | import cn.hutool.core.util.ObjUtil; | 5 | import cn.hutool.core.util.ObjUtil; |
| 5 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 6 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| @@ -150,10 +151,11 @@ public class IotDeviceUpstreamVertxHandler implements Handler<RoutingContext> { | @@ -150,10 +151,11 @@ public class IotDeviceUpstreamVertxHandler implements Handler<RoutingContext> { | ||
| 150 | Map<String, Object> properties = scriptService.parsePropertyData(productKey, deviceName, body); | 151 | Map<String, Object> properties = scriptService.parsePropertyData(productKey, deviceName, body); |
| 151 | 152 | ||
| 152 | // 如果脚本解析结果为空,使用默认解析逻辑 | 153 | // 如果脚本解析结果为空,使用默认解析逻辑 |
| 153 | - if (properties.isEmpty()) { | 154 | + // TODO @芋艿:注释说明一下,为什么要这么处理? |
| 155 | + if (CollUtil.isNotEmpty(properties)) { | ||
| 154 | properties = new HashMap<>(); | 156 | properties = new HashMap<>(); |
| 155 | - Map<String, Object> params = body.getJsonObject("params") != null ? body.getJsonObject("params").getMap() | ||
| 156 | - : null; | 157 | + Map<String, Object> params = body.getJsonObject("params") != null ? |
| 158 | + body.getJsonObject("params").getMap() : null; | ||
| 157 | if (params != null) { | 159 | if (params != null) { |
| 158 | // 将标准格式的 params 转换为平台需要的 properties 格式 | 160 | // 将标准格式的 params 转换为平台需要的 properties 格式 |
| 159 | for (Map.Entry<String, Object> entry : params.entrySet()) { | 161 | for (Map.Entry<String, Object> entry : params.entrySet()) { |
| @@ -193,7 +195,7 @@ public class IotDeviceUpstreamVertxHandler implements Handler<RoutingContext> { | @@ -193,7 +195,7 @@ public class IotDeviceUpstreamVertxHandler implements Handler<RoutingContext> { | ||
| 193 | Map<String, Object> params = scriptService.parseEventData(productKey, deviceName, identifier, body); | 195 | Map<String, Object> params = scriptService.parseEventData(productKey, deviceName, identifier, body); |
| 194 | 196 | ||
| 195 | // 如果脚本解析结果为空,使用默认解析逻辑 | 197 | // 如果脚本解析结果为空,使用默认解析逻辑 |
| 196 | - if (params.isEmpty()) { | 198 | + if (CollUtil.isNotEmpty(params)) { |
| 197 | if (body.containsKey("params")) { | 199 | if (body.containsKey("params")) { |
| 198 | params = body.getJsonObject("params").getMap(); | 200 | params = body.getJsonObject("params").getMap(); |
| 199 | } else { | 201 | } else { |
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; | @@ -9,6 +9,7 @@ import org.springframework.stereotype.Component; | ||
| 9 | import java.util.HashMap; | 9 | import java.util.HashMap; |
| 10 | import java.util.Map; | 10 | import java.util.Map; |
| 11 | 11 | ||
| 12 | +// TODO @haohao:写到单测类里; | ||
| 12 | /** | 13 | /** |
| 13 | * 脚本使用示例类 | 14 | * 脚本使用示例类 |
| 14 | */ | 15 | */ |
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; | @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.iot.plugin.script.service.ScriptServiceImpl; | ||
| 6 | import org.springframework.context.annotation.Bean; | 6 | import org.springframework.context.annotation.Bean; |
| 7 | import org.springframework.context.annotation.Configuration; | 7 | import org.springframework.context.annotation.Configuration; |
| 8 | 8 | ||
| 9 | +// TODO @haohao:这个模块,是不是融合到 plugin-common 里哈? | ||
| 9 | /** | 10 | /** |
| 10 | * 脚本模块配置类 | 11 | * 脚本模块配置类 |
| 11 | */ | 12 | */ |
| @@ -31,7 +32,7 @@ public class ScriptConfiguration { | @@ -31,7 +32,7 @@ public class ScriptConfiguration { | ||
| 31 | @Bean | 32 | @Bean |
| 32 | public ScriptService scriptService(ScriptEngineFactory engineFactory) { | 33 | public ScriptService scriptService(ScriptEngineFactory engineFactory) { |
| 33 | ScriptServiceImpl service = new ScriptServiceImpl(); | 34 | ScriptServiceImpl service = new ScriptServiceImpl(); |
| 34 | - // 如果有其他配置可以在这里设置 | 35 | + // TODO @haohao:如果有其他配置可以在这里设置 |
| 35 | return service; | 36 | return service; |
| 36 | } | 37 | } |
| 37 | -} | ||
| 38 | \ No newline at end of file | 38 | \ No newline at end of file |
| 39 | +} | ||
| 39 | \ No newline at end of file | 40 | \ No newline at end of file |
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 | package cn.iocoder.yudao.module.iot.plugin.script.context; | 1 | package cn.iocoder.yudao.module.iot.plugin.script.context; |
| 2 | 2 | ||
| 3 | +import lombok.Getter; | ||
| 4 | + | ||
| 3 | import java.util.HashMap; | 5 | import java.util.HashMap; |
| 4 | import java.util.Map; | 6 | import java.util.Map; |
| 5 | 7 | ||
| @@ -11,18 +13,22 @@ public class PluginScriptContext implements ScriptContext { | @@ -11,18 +13,22 @@ public class PluginScriptContext implements ScriptContext { | ||
| 11 | /** | 13 | /** |
| 12 | * 上下文参数 | 14 | * 上下文参数 |
| 13 | */ | 15 | */ |
| 16 | + @Getter | ||
| 14 | private final Map<String, Object> parameters = new HashMap<>(); | 17 | private final Map<String, Object> parameters = new HashMap<>(); |
| 15 | 18 | ||
| 16 | /** | 19 | /** |
| 17 | * 上下文函数 | 20 | * 上下文函数 |
| 18 | */ | 21 | */ |
| 22 | + @Getter | ||
| 19 | private final Map<String, Object> functions = new HashMap<>(); | 23 | private final Map<String, Object> functions = new HashMap<>(); |
| 20 | 24 | ||
| 21 | /** | 25 | /** |
| 22 | * 日志函数接口 | 26 | * 日志函数接口 |
| 23 | */ | 27 | */ |
| 24 | public interface LogFunction { | 28 | public interface LogFunction { |
| 29 | + | ||
| 25 | void log(String message); | 30 | void log(String message); |
| 31 | + | ||
| 26 | } | 32 | } |
| 27 | 33 | ||
| 28 | /** | 34 | /** |
| @@ -47,16 +53,6 @@ public class PluginScriptContext implements ScriptContext { | @@ -47,16 +53,6 @@ public class PluginScriptContext implements ScriptContext { | ||
| 47 | } | 53 | } |
| 48 | 54 | ||
| 49 | @Override | 55 | @Override |
| 50 | - public Map<String, Object> getParameters() { | ||
| 51 | - return parameters; | ||
| 52 | - } | ||
| 53 | - | ||
| 54 | - @Override | ||
| 55 | - public Map<String, Object> getFunctions() { | ||
| 56 | - return functions; | ||
| 57 | - } | ||
| 58 | - | ||
| 59 | - @Override | ||
| 60 | public void setParameter(String key, Object value) { | 56 | public void setParameter(String key, Object value) { |
| 61 | parameters.put(key, value); | 57 | parameters.put(key, value); |
| 62 | } | 58 | } |
| @@ -71,6 +67,7 @@ public class PluginScriptContext implements ScriptContext { | @@ -71,6 +67,7 @@ public class PluginScriptContext implements ScriptContext { | ||
| 71 | functions.put(name, function); | 67 | functions.put(name, function); |
| 72 | } | 68 | } |
| 73 | 69 | ||
| 70 | + // TODO @haohao:setParameters?这样的话,with 都是一些比较个性的参数 | ||
| 74 | /** | 71 | /** |
| 75 | * 批量设置参数 | 72 | * 批量设置参数 |
| 76 | * | 73 | * |
| @@ -87,11 +84,13 @@ public class PluginScriptContext implements ScriptContext { | @@ -87,11 +84,13 @@ public class PluginScriptContext implements ScriptContext { | ||
| 87 | /** | 84 | /** |
| 88 | * 添加设备相关的上下文参数 | 85 | * 添加设备相关的上下文参数 |
| 89 | * | 86 | * |
| 90 | - * @param deviceId 设备ID | 87 | + * @param deviceId 设备 ID |
| 91 | * @param deviceData 设备数据 | 88 | * @param deviceData 设备数据 |
| 92 | * @return 当前上下文对象 | 89 | * @return 当前上下文对象 |
| 93 | */ | 90 | */ |
| 91 | + // TODO @haohao:是不是加个 (String productKey, String deviceName, Map<String, Object> deviceData) { | ||
| 94 | public PluginScriptContext withDeviceContext(String deviceId, Map<String, Object> deviceData) { | 92 | public PluginScriptContext withDeviceContext(String deviceId, Map<String, Object> deviceData) { |
| 93 | + // TODO @haohao:deviceId 一般是分开,还是合并哈? | ||
| 95 | parameters.put("deviceId", deviceId); | 94 | parameters.put("deviceId", deviceId); |
| 96 | parameters.put("deviceData", deviceData); | 95 | parameters.put("deviceData", deviceData); |
| 97 | return this; | 96 | return this; |
| @@ -110,6 +109,7 @@ public class PluginScriptContext implements ScriptContext { | @@ -110,6 +109,7 @@ public class PluginScriptContext implements ScriptContext { | ||
| 110 | return this; | 109 | return this; |
| 111 | } | 110 | } |
| 112 | 111 | ||
| 112 | + // TODO @haohao:setParameter 可以融合哈? | ||
| 113 | /** | 113 | /** |
| 114 | * 设置单个参数 | 114 | * 设置单个参数 |
| 115 | * | 115 | * |
| @@ -121,4 +121,5 @@ public class PluginScriptContext implements ScriptContext { | @@ -121,4 +121,5 @@ public class PluginScriptContext implements ScriptContext { | ||
| 121 | parameters.put(key, value); | 121 | parameters.put(key, value); |
| 122 | return this; | 122 | return this; |
| 123 | } | 123 | } |
| 124 | + | ||
| 124 | } | 125 | } |
| 125 | \ No newline at end of file | 126 | \ No newline at end of file |
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 { | @@ -37,6 +37,7 @@ public interface ScriptContext { | ||
| 37 | */ | 37 | */ |
| 38 | Object getParameter(String key); | 38 | Object getParameter(String key); |
| 39 | 39 | ||
| 40 | + // TODO @haohao:这个要不也是 setFunction | ||
| 40 | /** | 41 | /** |
| 41 | * 注册函数 | 42 | * 注册函数 |
| 42 | * | 43 | * |
| @@ -44,4 +45,5 @@ public interface ScriptContext { | @@ -44,4 +45,5 @@ public interface ScriptContext { | ||
| 44 | * @param function 函数对象 | 45 | * @param function 函数对象 |
| 45 | */ | 46 | */ |
| 46 | void registerFunction(String name, Object function); | 47 | void registerFunction(String name, Object function); |
| 47 | -} | ||
| 48 | \ No newline at end of file | 48 | \ No newline at end of file |
| 49 | + | ||
| 50 | +} | ||
| 49 | \ No newline at end of file | 51 | \ No newline at end of file |
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 { | @@ -48,4 +48,4 @@ public abstract class AbstractScriptEngine { | ||
| 48 | public void setSandbox(ScriptSandbox sandbox) { | 48 | public void setSandbox(ScriptSandbox sandbox) { |
| 49 | this.sandbox = sandbox; | 49 | this.sandbox = sandbox; |
| 50 | } | 50 | } |
| 51 | -} | ||
| 52 | \ No newline at end of file | 51 | \ No newline at end of file |
| 52 | +} | ||
| 53 | \ No newline at end of file | 53 | \ No newline at end of file |
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; | @@ -12,8 +12,8 @@ import java.util.concurrent.Callable; | ||
| 12 | import java.util.concurrent.ConcurrentHashMap; | 12 | import java.util.concurrent.ConcurrentHashMap; |
| 13 | 13 | ||
| 14 | /** | 14 | /** |
| 15 | - * JavaScript脚本引擎实现 | ||
| 16 | - * 使用JSR-223 Nashorn脚本引擎 | 15 | + * JavaScript 脚本引擎实现 |
| 16 | + * 使用 JSR-223 Nashorn 脚本引擎 | ||
| 17 | */ | 17 | */ |
| 18 | @Slf4j | 18 | @Slf4j |
| 19 | public class JsScriptEngine extends AbstractScriptEngine { | 19 | public class JsScriptEngine extends AbstractScriptEngine { |
| @@ -24,7 +24,7 @@ public class JsScriptEngine extends AbstractScriptEngine { | @@ -24,7 +24,7 @@ public class JsScriptEngine extends AbstractScriptEngine { | ||
| 24 | private static final long DEFAULT_TIMEOUT_MS = 5000; | 24 | private static final long DEFAULT_TIMEOUT_MS = 5000; |
| 25 | 25 | ||
| 26 | /** | 26 | /** |
| 27 | - * JavaScript引擎名称 | 27 | + * JavaScript 引擎名称 |
| 28 | */ | 28 | */ |
| 29 | private static final String JS_ENGINE_NAME = "nashorn"; | 29 | private static final String JS_ENGINE_NAME = "nashorn"; |
| 30 | 30 | ||
| @@ -45,25 +45,24 @@ public class JsScriptEngine extends AbstractScriptEngine { | @@ -45,25 +45,24 @@ public class JsScriptEngine extends AbstractScriptEngine { | ||
| 45 | 45 | ||
| 46 | @Override | 46 | @Override |
| 47 | public void init() { | 47 | public void init() { |
| 48 | - log.info("初始化JavaScript脚本引擎"); | 48 | + log.info("初始化 JavaScript 脚本引擎"); |
| 49 | 49 | ||
| 50 | // 创建脚本引擎管理器 | 50 | // 创建脚本引擎管理器 |
| 51 | engineManager = new ScriptEngineManager(); | 51 | engineManager = new ScriptEngineManager(); |
| 52 | 52 | ||
| 53 | - // 获取JavaScript引擎 | 53 | + // 获取 JavaScript 引擎 |
| 54 | engine = engineManager.getEngineByName(JS_ENGINE_NAME); | 54 | engine = engineManager.getEngineByName(JS_ENGINE_NAME); |
| 55 | if (engine == null) { | 55 | if (engine == null) { |
| 56 | - log.error("无法创建JavaScript引擎,尝试使用JavaScript名称获取"); | 56 | + log.error("无法创建JavaScript引擎,尝试使用 JavaScript 名称获取"); |
| 57 | engine = engineManager.getEngineByName("JavaScript"); | 57 | engine = engineManager.getEngineByName("JavaScript"); |
| 58 | } | 58 | } |
| 59 | - | ||
| 60 | if (engine == null) { | 59 | if (engine == null) { |
| 61 | - throw new IllegalStateException("无法创建JavaScript引擎,请检查环境配置"); | 60 | + throw new IllegalStateException("无法创建 JavaScript 引擎,请检查环境配置"); |
| 62 | } | 61 | } |
| 63 | 62 | ||
| 64 | log.info("成功创建JavaScript引擎: {}", engine.getClass().getName()); | 63 | log.info("成功创建JavaScript引擎: {}", engine.getClass().getName()); |
| 65 | 64 | ||
| 66 | - // 默认使用JS沙箱 | 65 | + // 默认使用 JS 沙箱 |
| 67 | if (sandbox == null) { | 66 | if (sandbox == null) { |
| 68 | setSandbox(new JsSandbox()); | 67 | setSandbox(new JsSandbox()); |
| 69 | } | 68 | } |
| @@ -99,7 +98,7 @@ public class JsScriptEngine extends AbstractScriptEngine { | @@ -99,7 +98,7 @@ public class JsScriptEngine extends AbstractScriptEngine { | ||
| 99 | // 执行脚本 | 98 | // 执行脚本 |
| 100 | return engine.eval(script, bindings); | 99 | return engine.eval(script, bindings); |
| 101 | } catch (ScriptException e) { | 100 | } catch (ScriptException e) { |
| 102 | - log.error("执行JavaScript脚本异常: {}", e.getMessage()); | 101 | + log.error("执行 JavaScript 脚本异常: {}", e.getMessage()); |
| 103 | throw new RuntimeException("脚本执行异常: " + e.getMessage(), e); | 102 | throw new RuntimeException("脚本执行异常: " + e.getMessage(), e); |
| 104 | } | 103 | } |
| 105 | }; | 104 | }; |
| @@ -136,7 +135,7 @@ public class JsScriptEngine extends AbstractScriptEngine { | @@ -136,7 +135,7 @@ public class JsScriptEngine extends AbstractScriptEngine { | ||
| 136 | // 执行脚本 | 135 | // 执行脚本 |
| 137 | return engine.eval(script, bindings); | 136 | return engine.eval(script, bindings); |
| 138 | } catch (ScriptException e) { | 137 | } catch (ScriptException e) { |
| 139 | - log.error("执行JavaScript脚本异常: {}", e.getMessage()); | 138 | + log.error("执行 JavaScript 脚本异常: {}", e.getMessage()); |
| 140 | throw new RuntimeException("脚本执行异常: " + e.getMessage(), e); | 139 | throw new RuntimeException("脚本执行异常: " + e.getMessage(), e); |
| 141 | } | 140 | } |
| 142 | }; | 141 | }; |
| @@ -152,9 +151,10 @@ public class JsScriptEngine extends AbstractScriptEngine { | @@ -152,9 +151,10 @@ public class JsScriptEngine extends AbstractScriptEngine { | ||
| 152 | 151 | ||
| 153 | @Override | 152 | @Override |
| 154 | public void destroy() { | 153 | public void destroy() { |
| 155 | - log.info("销毁JavaScript脚本引擎"); | 154 | + log.info("销毁 JavaScript 脚本引擎"); |
| 156 | cachedScripts.clear(); | 155 | cachedScripts.clear(); |
| 157 | engine = null; | 156 | engine = null; |
| 158 | engineManager = null; | 157 | engineManager = null; |
| 159 | } | 158 | } |
| 159 | + | ||
| 160 | } | 160 | } |
| 161 | \ No newline at end of file | 161 | \ No newline at end of file |
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 | package cn.iocoder.yudao.module.iot.plugin.script.engine; | 1 | package cn.iocoder.yudao.module.iot.plugin.script.engine; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.lang.Assert; | ||
| 3 | import lombok.extern.slf4j.Slf4j; | 4 | import lombok.extern.slf4j.Slf4j; |
| 4 | import org.springframework.stereotype.Component; | 5 | import org.springframework.stereotype.Component; |
| 5 | 6 | ||
| @@ -11,12 +12,12 @@ import org.springframework.stereotype.Component; | @@ -11,12 +12,12 @@ import org.springframework.stereotype.Component; | ||
| 11 | public class ScriptEngineFactory { | 12 | public class ScriptEngineFactory { |
| 12 | 13 | ||
| 13 | /** | 14 | /** |
| 14 | - * 创建JavaScript脚本引擎 | 15 | + * 创建 JavaScript 脚本引擎 |
| 15 | * | 16 | * |
| 16 | * @return JavaScript脚本引擎 | 17 | * @return JavaScript脚本引擎 |
| 17 | */ | 18 | */ |
| 18 | public JsScriptEngine createJsEngine() { | 19 | public JsScriptEngine createJsEngine() { |
| 19 | - log.debug("创建JavaScript脚本引擎"); | 20 | + log.debug("创建 JavaScript 脚本引擎"); |
| 20 | return new JsScriptEngine(); | 21 | return new JsScriptEngine(); |
| 21 | } | 22 | } |
| 22 | 23 | ||
| @@ -27,10 +28,7 @@ public class ScriptEngineFactory { | @@ -27,10 +28,7 @@ public class ScriptEngineFactory { | ||
| 27 | * @return 脚本引擎 | 28 | * @return 脚本引擎 |
| 28 | */ | 29 | */ |
| 29 | public AbstractScriptEngine createEngine(String scriptType) { | 30 | public AbstractScriptEngine createEngine(String scriptType) { |
| 30 | - if (scriptType == null || scriptType.isEmpty()) { | ||
| 31 | - throw new IllegalArgumentException("脚本类型不能为空"); | ||
| 32 | - } | ||
| 33 | - | 31 | + Assert.notBlank(scriptType, "脚本类型不能为空"); |
| 34 | switch (scriptType.toLowerCase()) { | 32 | switch (scriptType.toLowerCase()) { |
| 35 | case "js": | 33 | case "js": |
| 36 | case "javascript": | 34 | case "javascript": |
| @@ -40,4 +38,5 @@ public class ScriptEngineFactory { | @@ -40,4 +38,5 @@ public class ScriptEngineFactory { | ||
| 40 | throw new IllegalArgumentException("不支持的脚本类型: " + scriptType); | 38 | throw new IllegalArgumentException("不支持的脚本类型: " + scriptType); |
| 41 | } | 39 | } |
| 42 | } | 40 | } |
| 43 | -} | ||
| 44 | \ No newline at end of file | 41 | \ No newline at end of file |
| 42 | + | ||
| 43 | +} | ||
| 45 | \ No newline at end of file | 44 | \ No newline at end of file |
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 | package cn.iocoder.yudao.module.iot.plugin.script.sandbox; | 1 | package cn.iocoder.yudao.module.iot.plugin.script.sandbox; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.util.StrUtil; | ||
| 3 | import lombok.extern.slf4j.Slf4j; | 4 | import lombok.extern.slf4j.Slf4j; |
| 4 | 5 | ||
| 5 | import javax.script.ScriptEngine; | 6 | import javax.script.ScriptEngine; |
| @@ -8,8 +9,9 @@ import java.util.HashSet; | @@ -8,8 +9,9 @@ import java.util.HashSet; | ||
| 8 | import java.util.Set; | 9 | import java.util.Set; |
| 9 | import java.util.regex.Pattern; | 10 | import java.util.regex.Pattern; |
| 10 | 11 | ||
| 12 | +// TODO @haohao:这个是不是融合到 ScriptEngine 里 | ||
| 11 | /** | 13 | /** |
| 12 | - * JavaScript脚本沙箱,限制脚本的执行权限 | 14 | + * JavaScript 脚本沙箱,限制脚本的执行权限 |
| 13 | */ | 15 | */ |
| 14 | @Slf4j | 16 | @Slf4j |
| 15 | public class JsSandbox implements ScriptSandbox { | 17 | public class JsSandbox implements ScriptSandbox { |
| @@ -34,6 +36,7 @@ public class JsSandbox implements ScriptSandbox { | @@ -34,6 +36,7 @@ public class JsSandbox implements ScriptSandbox { | ||
| 34 | "(?:\\bchild_process\\b)|" + | 36 | "(?:\\bchild_process\\b)|" + |
| 35 | "(?:\\bwindow\\b)"); | 37 | "(?:\\bwindow\\b)"); |
| 36 | 38 | ||
| 39 | + // TODO @haohao:这个没用到哈。 | ||
| 37 | /** | 40 | /** |
| 38 | * 脚本执行超时时间(毫秒) | 41 | * 脚本执行超时时间(毫秒) |
| 39 | */ | 42 | */ |
| @@ -44,30 +47,28 @@ public class JsSandbox implements ScriptSandbox { | @@ -44,30 +47,28 @@ public class JsSandbox implements ScriptSandbox { | ||
| 44 | if (!(engineContext instanceof ScriptEngine)) { | 47 | if (!(engineContext instanceof ScriptEngine)) { |
| 45 | throw new IllegalArgumentException("引擎上下文类型不正确,无法应用JavaScript沙箱"); | 48 | throw new IllegalArgumentException("引擎上下文类型不正确,无法应用JavaScript沙箱"); |
| 46 | } | 49 | } |
| 47 | - | ||
| 48 | ScriptEngine engine = (ScriptEngine) engineContext; | 50 | ScriptEngine engine = (ScriptEngine) engineContext; |
| 49 | 51 | ||
| 50 | - // 在Nashorn引擎中,可以通过以下方式设置安全限制 | 52 | + // 在 Nashorn 引擎中,可以通过以下方式设置安全限制 |
| 51 | try { | 53 | try { |
| 52 | // 设置严格模式 | 54 | // 设置严格模式 |
| 53 | String securityPrefix = "'use strict';\n"; | 55 | String securityPrefix = "'use strict';\n"; |
| 54 | 56 | ||
| 55 | - // 禁用Java.type等访问系统资源的功能 | 57 | + // 禁用 Java.type 等访问系统资源的功能 |
| 56 | engine.eval("var Java = undefined;"); | 58 | engine.eval("var Java = undefined;"); |
| 57 | engine.eval("var JavaImporter = undefined;"); | 59 | engine.eval("var JavaImporter = undefined;"); |
| 58 | engine.eval("var Packages = undefined;"); | 60 | engine.eval("var Packages = undefined;"); |
| 59 | 61 | ||
| 60 | // 增强安全控制可以在这里添加 | 62 | // 增强安全控制可以在这里添加 |
| 61 | - log.debug("已应用JavaScript安全沙箱限制"); | ||
| 62 | - | 63 | + log.debug("已应用 JavaScript 安全沙箱限制"); |
| 63 | } catch (Exception e) { | 64 | } catch (Exception e) { |
| 64 | - log.warn("应用JavaScript沙箱限制失败: {}", e.getMessage()); | 65 | + log.warn("应用 JavaScript 沙箱限制失败: {}", e.getMessage()); |
| 65 | } | 66 | } |
| 66 | } | 67 | } |
| 67 | 68 | ||
| 68 | @Override | 69 | @Override |
| 69 | public boolean validateScript(String script) { | 70 | public boolean validateScript(String script) { |
| 70 | - if (script == null || script.isEmpty()) { | 71 | + if (StrUtil.isNotEmpty(script)) { |
| 71 | return false; | 72 | return false; |
| 72 | } | 73 | } |
| 73 | 74 | ||
| @@ -86,11 +87,12 @@ public class JsSandbox implements ScriptSandbox { | @@ -86,11 +87,12 @@ public class JsSandbox implements ScriptSandbox { | ||
| 86 | } | 87 | } |
| 87 | 88 | ||
| 88 | // 脚本长度限制 | 89 | // 脚本长度限制 |
| 89 | - if (script.length() > 1024 * 100) { // 限制100KB | 90 | + if (script.length() > 1024 * 100) { // 限制 100 KB |
| 90 | log.warn("脚本太大,超过了限制"); | 91 | log.warn("脚本太大,超过了限制"); |
| 91 | return false; | 92 | return false; |
| 92 | } | 93 | } |
| 93 | 94 | ||
| 94 | return true; | 95 | return true; |
| 95 | } | 96 | } |
| 97 | + | ||
| 96 | } | 98 | } |
| 97 | \ No newline at end of file | 99 | \ No newline at end of file |
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 { | @@ -20,4 +20,5 @@ public interface ScriptSandbox { | ||
| 20 | * @return 是否安全 | 20 | * @return 是否安全 |
| 21 | */ | 21 | */ |
| 22 | boolean validateScript(String script); | 22 | boolean validateScript(String script); |
| 23 | -} | ||
| 24 | \ No newline at end of file | 23 | \ No newline at end of file |
| 24 | + | ||
| 25 | +} | ||
| 25 | \ No newline at end of file | 26 | \ No newline at end of file |
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 { | @@ -12,7 +12,7 @@ public interface ScriptService { | ||
| 12 | /** | 12 | /** |
| 13 | * 执行脚本 | 13 | * 执行脚本 |
| 14 | * | 14 | * |
| 15 | - * @param scriptType 脚本类型(如js、groovy等) | 15 | + * @param scriptType 脚本类型(如 js、groovy 等) |
| 16 | * @param script 脚本内容 | 16 | * @param script 脚本内容 |
| 17 | * @param context 脚本上下文 | 17 | * @param context 脚本上下文 |
| 18 | * @return 脚本执行结果 | 18 | * @return 脚本执行结果 |
| @@ -22,7 +22,7 @@ public interface ScriptService { | @@ -22,7 +22,7 @@ public interface ScriptService { | ||
| 22 | /** | 22 | /** |
| 23 | * 执行脚本 | 23 | * 执行脚本 |
| 24 | * | 24 | * |
| 25 | - * @param scriptType 脚本类型(如js、groovy等) | 25 | + * @param scriptType 脚本类型(如 js、groovy 等) |
| 26 | * @param script 脚本内容 | 26 | * @param script 脚本内容 |
| 27 | * @param params 脚本参数 | 27 | * @param params 脚本参数 |
| 28 | * @return 脚本执行结果 | 28 | * @return 脚本执行结果 |
| @@ -30,7 +30,7 @@ public interface ScriptService { | @@ -30,7 +30,7 @@ public interface ScriptService { | ||
| 30 | Object executeScript(String scriptType, String script, Map<String, Object> params); | 30 | Object executeScript(String scriptType, String script, Map<String, Object> params); |
| 31 | 31 | ||
| 32 | /** | 32 | /** |
| 33 | - * 执行JavaScript脚本 | 33 | + * 执行 JavaScript 脚本 |
| 34 | * | 34 | * |
| 35 | * @param script 脚本内容 | 35 | * @param script 脚本内容 |
| 36 | * @param context 脚本上下文 | 36 | * @param context 脚本上下文 |
| @@ -39,7 +39,7 @@ public interface ScriptService { | @@ -39,7 +39,7 @@ public interface ScriptService { | ||
| 39 | Object executeJavaScript(String script, ScriptContext context); | 39 | Object executeJavaScript(String script, ScriptContext context); |
| 40 | 40 | ||
| 41 | /** | 41 | /** |
| 42 | - * 执行JavaScript脚本 | 42 | + * 执行 JavaScript 脚本 |
| 43 | * | 43 | * |
| 44 | * @param script 脚本内容 | 44 | * @param script 脚本内容 |
| 45 | * @param params 脚本参数 | 45 | * @param params 脚本参数 |
| @@ -55,4 +55,5 @@ public interface ScriptService { | @@ -55,4 +55,5 @@ public interface ScriptService { | ||
| 55 | * @return 脚本是否安全 | 55 | * @return 脚本是否安全 |
| 56 | */ | 56 | */ |
| 57 | boolean validateScript(String scriptType, String script); | 57 | boolean validateScript(String scriptType, String script); |
| 58 | -} | ||
| 59 | \ No newline at end of file | 58 | \ No newline at end of file |
| 59 | + | ||
| 60 | +} | ||
| 60 | \ No newline at end of file | 61 | \ No newline at end of file |
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 { | @@ -38,6 +38,7 @@ public class ScriptServiceImpl implements ScriptService { | ||
| 38 | @PostConstruct | 38 | @PostConstruct |
| 39 | public void init() { | 39 | public void init() { |
| 40 | // 初始化常用的脚本引擎和沙箱 | 40 | // 初始化常用的脚本引擎和沙箱 |
| 41 | + // TODO @haohao:js 是不是要枚举下哈。 | ||
| 41 | getEngine("js"); | 42 | getEngine("js"); |
| 42 | sandboxCache.put("js", new JsSandbox()); | 43 | sandboxCache.put("js", new JsSandbox()); |
| 43 | } | 44 | } |
| @@ -49,6 +50,7 @@ public class ScriptServiceImpl implements ScriptService { | @@ -49,6 +50,7 @@ public class ScriptServiceImpl implements ScriptService { | ||
| 49 | try { | 50 | try { |
| 50 | engine.destroy(); | 51 | engine.destroy(); |
| 51 | } catch (Exception e) { | 52 | } catch (Exception e) { |
| 53 | + // TODO @haohao:engine 类名 | ||
| 52 | log.error("销毁脚本引擎失败", e); | 54 | log.error("销毁脚本引擎失败", e); |
| 53 | } | 55 | } |
| 54 | } | 56 | } |
| @@ -58,6 +60,7 @@ public class ScriptServiceImpl implements ScriptService { | @@ -58,6 +60,7 @@ public class ScriptServiceImpl implements ScriptService { | ||
| 58 | 60 | ||
| 59 | @Override | 61 | @Override |
| 60 | public Object executeScript(String scriptType, String script, ScriptContext context) { | 62 | public Object executeScript(String scriptType, String script, ScriptContext context) { |
| 63 | + // TODO @haohao:可以使用 hutool assert | ||
| 61 | if (scriptType == null || script == null) { | 64 | if (scriptType == null || script == null) { |
| 62 | throw new IllegalArgumentException("脚本类型和内容不能为空"); | 65 | throw new IllegalArgumentException("脚本类型和内容不能为空"); |
| 63 | } | 66 | } |
| @@ -74,6 +77,7 @@ public class ScriptServiceImpl implements ScriptService { | @@ -74,6 +77,7 @@ public class ScriptServiceImpl implements ScriptService { | ||
| 74 | // 执行脚本 | 77 | // 执行脚本 |
| 75 | return engine.execute(script, context); | 78 | return engine.execute(script, context); |
| 76 | } catch (Exception e) { | 79 | } catch (Exception e) { |
| 80 | + // TODO @haohao:最好把 e 堆栈出来哈;然后,engine 类名 | ||
| 77 | log.error("执行脚本失败: {}", e.getMessage()); | 81 | log.error("执行脚本失败: {}", e.getMessage()); |
| 78 | throw new RuntimeException("执行脚本失败: " + e.getMessage(), e); | 82 | throw new RuntimeException("执行脚本失败: " + e.getMessage(), e); |
| 79 | } | 83 | } |
| @@ -83,16 +87,19 @@ public class ScriptServiceImpl implements ScriptService { | @@ -83,16 +87,19 @@ public class ScriptServiceImpl implements ScriptService { | ||
| 83 | public Object executeScript(String scriptType, String script, Map<String, Object> params) { | 87 | public Object executeScript(String scriptType, String script, Map<String, Object> params) { |
| 84 | // 创建默认上下文 | 88 | // 创建默认上下文 |
| 85 | ScriptContext context = new PluginScriptContext(params); | 89 | ScriptContext context = new PluginScriptContext(params); |
| 90 | + // 执行脚本 | ||
| 86 | return executeScript(scriptType, script, context); | 91 | return executeScript(scriptType, script, context); |
| 87 | } | 92 | } |
| 88 | 93 | ||
| 89 | @Override | 94 | @Override |
| 90 | public Object executeJavaScript(String script, ScriptContext context) { | 95 | public Object executeJavaScript(String script, ScriptContext context) { |
| 96 | + // TODO @haohao:枚举哈 | ||
| 91 | return executeScript("js", script, context); | 97 | return executeScript("js", script, context); |
| 92 | } | 98 | } |
| 93 | 99 | ||
| 94 | @Override | 100 | @Override |
| 95 | public Object executeJavaScript(String script, Map<String, Object> params) { | 101 | public Object executeJavaScript(String script, Map<String, Object> params) { |
| 102 | + // TODO @haohao:枚举哈 | ||
| 96 | return executeScript("js", script, params); | 103 | return executeScript("js", script, params); |
| 97 | } | 104 | } |
| 98 | 105 | ||
| @@ -100,7 +107,8 @@ public class ScriptServiceImpl implements ScriptService { | @@ -100,7 +107,8 @@ public class ScriptServiceImpl implements ScriptService { | ||
| 100 | public boolean validateScript(String scriptType, String script) { | 107 | public boolean validateScript(String scriptType, String script) { |
| 101 | ScriptSandbox sandbox = sandboxCache.get(scriptType.toLowerCase()); | 108 | ScriptSandbox sandbox = sandboxCache.get(scriptType.toLowerCase()); |
| 102 | if (sandbox == null) { | 109 | if (sandbox == null) { |
| 103 | - log.warn("找不到脚本类型[{}]对应的沙箱,使用默认JS沙箱", scriptType); | 110 | + // TODO @haohao:疑问,为啥默认 JsSandbox 哈? |
| 111 | + log.warn("[validateScript][找不到脚本类型[{}]对应的沙箱,使用默认 JS 沙箱]", scriptType); | ||
| 104 | sandbox = new JsSandbox(); | 112 | sandbox = new JsSandbox(); |
| 105 | sandboxCache.put(scriptType.toLowerCase(), sandbox); | 113 | sandboxCache.put(scriptType.toLowerCase(), sandbox); |
| 106 | } | 114 | } |
| @@ -120,4 +128,4 @@ public class ScriptServiceImpl implements ScriptService { | @@ -120,4 +128,4 @@ public class ScriptServiceImpl implements ScriptService { | ||
| 120 | return engine; | 128 | return engine; |
| 121 | }); | 129 | }); |
| 122 | } | 130 | } |
| 123 | -} | ||
| 124 | \ No newline at end of file | 131 | \ No newline at end of file |
| 132 | +} | ||
| 125 | \ No newline at end of file | 133 | \ No newline at end of file |
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; | @@ -6,6 +6,9 @@ import lombok.extern.slf4j.Slf4j; | ||
| 6 | import java.util.Map; | 6 | import java.util.Map; |
| 7 | import java.util.concurrent.*; | 7 | import java.util.concurrent.*; |
| 8 | 8 | ||
| 9 | +// TODO @haohao:【重要】 ScriptUtil.createGroovyEngine() 可以服用 hutool 的封装么? | ||
| 10 | +// TODO @haohao:【重要】 js 引擎,可能要看下 jdk8 的兼容性; | ||
| 11 | +// TODO @haohao:【重要】我们要不 script 配置的时候,支持 scriptType?!感觉会更通用一些???groovy、python、js | ||
| 9 | /** | 12 | /** |
| 10 | * 脚本工具类,提供执行脚本的辅助方法 | 13 | * 脚本工具类,提供执行脚本的辅助方法 |
| 11 | */ | 14 | */ |
| @@ -66,6 +69,7 @@ public class ScriptUtils { | @@ -66,6 +69,7 @@ public class ScriptUtils { | ||
| 66 | * 关闭工具类的线程池 | 69 | * 关闭工具类的线程池 |
| 67 | */ | 70 | */ |
| 68 | public static void shutdown() { | 71 | public static void shutdown() { |
| 72 | + // TODO @芋艿:有没默认工具类,可以 shutdown | ||
| 69 | SCRIPT_EXECUTOR.shutdown(); | 73 | SCRIPT_EXECUTOR.shutdown(); |
| 70 | try { | 74 | try { |
| 71 | if (!SCRIPT_EXECUTOR.awaitTermination(10, TimeUnit.SECONDS)) { | 75 | if (!SCRIPT_EXECUTOR.awaitTermination(10, TimeUnit.SECONDS)) { |
| @@ -77,8 +81,9 @@ public class ScriptUtils { | @@ -77,8 +81,9 @@ public class ScriptUtils { | ||
| 77 | } | 81 | } |
| 78 | } | 82 | } |
| 79 | 83 | ||
| 84 | + // TODO @芋艿:要不要使用 JsonUtils | ||
| 80 | /** | 85 | /** |
| 81 | - * 将JSON字符串转换为Map | 86 | + * 将 JSON 字符串转换为 Map |
| 82 | * | 87 | * |
| 83 | * @param json JSON字符串 | 88 | * @param json JSON字符串 |
| 84 | * @return Map对象,转换失败则返回null | 89 | * @return Map对象,转换失败则返回null |
| @@ -86,19 +91,20 @@ public class ScriptUtils { | @@ -86,19 +91,20 @@ public class ScriptUtils { | ||
| 86 | @SuppressWarnings("unchecked") | 91 | @SuppressWarnings("unchecked") |
| 87 | public static Map<String, Object> parseJson(String json) { | 92 | public static Map<String, Object> parseJson(String json) { |
| 88 | try { | 93 | try { |
| 89 | - // 使用hutool的JSONUtil工具类解析JSON | ||
| 90 | return JSONUtil.toBean(json, Map.class); | 94 | return JSONUtil.toBean(json, Map.class); |
| 91 | } catch (Exception e) { | 95 | } catch (Exception e) { |
| 92 | - log.error("解析JSON失败: {}", e.getMessage()); | 96 | + // TODO @haohao:json、e 都打印出来哈 |
| 97 | + log.error("[parseJson][解析JSON失败: {}]", e.getMessage()); | ||
| 93 | return null; | 98 | return null; |
| 94 | } | 99 | } |
| 95 | } | 100 | } |
| 96 | 101 | ||
| 102 | + // TODO @芋艿:要不要封装成 utils | ||
| 97 | /** | 103 | /** |
| 98 | * 尝试将对象转换为整数 | 104 | * 尝试将对象转换为整数 |
| 99 | * | 105 | * |
| 100 | * @param obj 需要转换的对象 | 106 | * @param obj 需要转换的对象 |
| 101 | - * @return 转换后的整数,如果无法转换则返回null | 107 | + * @return 转换后的整数,如果无法转换则返回 null |
| 102 | */ | 108 | */ |
| 103 | public static Integer toInteger(Object obj) { | 109 | public static Integer toInteger(Object obj) { |
| 104 | if (obj == null) { | 110 | if (obj == null) { |
| @@ -122,6 +128,7 @@ public class ScriptUtils { | @@ -122,6 +128,7 @@ public class ScriptUtils { | ||
| 122 | return null; | 128 | return null; |
| 123 | } | 129 | } |
| 124 | 130 | ||
| 131 | + // TODO @芋艿:要不要封装成 utils | ||
| 125 | /** | 132 | /** |
| 126 | * 尝试将对象转换为双精度浮点数 | 133 | * 尝试将对象转换为双精度浮点数 |
| 127 | * | 134 | * |
| @@ -158,10 +165,12 @@ public class ScriptUtils { | @@ -158,10 +165,12 @@ public class ScriptUtils { | ||
| 158 | * @return 如果两个数值相等则返回true,否则返回false | 165 | * @return 如果两个数值相等则返回true,否则返回false |
| 159 | */ | 166 | */ |
| 160 | public static boolean numbersEqual(Number a, Number b) { | 167 | public static boolean numbersEqual(Number a, Number b) { |
| 168 | + // TODO @haohao:NumberUtil.equals(1, 1D) | ||
| 161 | if (a == null || b == null) { | 169 | if (a == null || b == null) { |
| 162 | return a == b; | 170 | return a == b; |
| 163 | } | 171 | } |
| 164 | 172 | ||
| 165 | return Math.abs(a.doubleValue() - b.doubleValue()) < 0.0000001; | 173 | return Math.abs(a.doubleValue() - b.doubleValue()) < 0.0000001; |
| 166 | } | 174 | } |
| 175 | + | ||
| 167 | } | 176 | } |
| 168 | \ No newline at end of file | 177 | \ No newline at end of file |