【功能优化】IoT: 重构脚本服务实现,启用脚本执行和测试逻辑,更新日志记录方式

This commit is contained in:
安浩浩
2025-03-24 18:11:33 +08:00
parent a9dc654b36
commit 0ae893272b
9 changed files with 132 additions and 137 deletions

View File

@@ -19,7 +19,7 @@
<!-- 引入公共模块 -->
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-module-iot-plugin-common</artifactId>
<artifactId>yudao-module-iot-api</artifactId>
<version>${revision}</version>
</dependency>

View File

@@ -2,8 +2,7 @@ package cn.iocoder.yudao.module.iot.plugin.script;
import cn.iocoder.yudao.module.iot.plugin.script.context.PluginScriptContext;
import cn.iocoder.yudao.module.iot.plugin.script.service.ScriptService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -14,8 +13,8 @@ import java.util.Map;
* 脚本使用示例类
*/
@Component
@Slf4j
public class ScriptExample {
private static final Logger logger = LoggerFactory.getLogger(ScriptExample.class);
@Autowired
private ScriptService scriptService;
@@ -31,7 +30,7 @@ public class ScriptExample {
params.put("b", 20);
Object result = scriptService.executeJavaScript(script, params);
logger.info("脚本执行结果: {}", result);
log.info("脚本执行结果: {}", result);
}
/**
@@ -73,17 +72,17 @@ public class ScriptExample {
Object result = scriptService.executeJavaScript(script, context);
if (result != null) {
// 处理结果
logger.info("设备数据处理结果: {}", result);
log.info("设备数据处理结果: {}", result);
// 安全地将结果转换为Map
if (result instanceof Map) {
return (Map<String, Object>) result;
} else {
logger.warn("脚本返回结果类型不是Map: {}", result.getClass().getName());
log.warn("脚本返回结果类型不是Map: {}", result.getClass().getName());
}
}
} catch (Exception e) {
logger.error("处理设备数据失败: {}", e.getMessage());
log.error("处理设备数据失败: {}", e.getMessage());
}
return new HashMap<>();
@@ -121,10 +120,10 @@ public class ScriptExample {
if (result instanceof String) {
return (String) result;
} else if (result != null) {
logger.warn("脚本返回结果类型不是String: {}", result.getClass().getName());
log.warn("脚本返回结果类型不是String: {}", result.getClass().getName());
}
} catch (Exception e) {
logger.error("生成设备命令失败: {}", e.getMessage());
log.error("生成设备命令失败: {}", e.getMessage());
}
return null;

View File

@@ -4,8 +4,7 @@ import cn.hutool.core.map.MapUtil;
import cn.iocoder.yudao.module.iot.plugin.script.context.ScriptContext;
import cn.iocoder.yudao.module.iot.plugin.script.sandbox.JsSandbox;
import cn.iocoder.yudao.module.iot.plugin.script.util.ScriptUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import lombok.extern.slf4j.Slf4j;
import javax.script.*;
import java.util.Map;
@@ -16,8 +15,8 @@ import java.util.concurrent.ConcurrentHashMap;
* JavaScript脚本引擎实现
* 使用JSR-223 Nashorn脚本引擎
*/
@Slf4j
public class JsScriptEngine extends AbstractScriptEngine {
private static final Logger logger = LoggerFactory.getLogger(JsScriptEngine.class);
/**
* 默认脚本执行超时时间(毫秒)
@@ -46,7 +45,7 @@ public class JsScriptEngine extends AbstractScriptEngine {
@Override
public void init() {
logger.info("初始化JavaScript脚本引擎");
log.info("初始化JavaScript脚本引擎");
// 创建脚本引擎管理器
engineManager = new ScriptEngineManager();
@@ -54,7 +53,7 @@ public class JsScriptEngine extends AbstractScriptEngine {
// 获取JavaScript引擎
engine = engineManager.getEngineByName(JS_ENGINE_NAME);
if (engine == null) {
logger.error("无法创建JavaScript引擎尝试使用JavaScript名称获取");
log.error("无法创建JavaScript引擎尝试使用JavaScript名称获取");
engine = engineManager.getEngineByName("JavaScript");
}
@@ -62,7 +61,7 @@ public class JsScriptEngine extends AbstractScriptEngine {
throw new IllegalStateException("无法创建JavaScript引擎请检查环境配置");
}
logger.info("成功创建JavaScript引擎: {}", engine.getClass().getName());
log.info("成功创建JavaScript引擎: {}", engine.getClass().getName());
// 默认使用JS沙箱
if (sandbox == null) {
@@ -100,7 +99,7 @@ public class JsScriptEngine extends AbstractScriptEngine {
// 执行脚本
return engine.eval(script, bindings);
} catch (ScriptException e) {
logger.error("执行JavaScript脚本异常: {}", e.getMessage());
log.error("执行JavaScript脚本异常: {}", e.getMessage());
throw new RuntimeException("脚本执行异常: " + e.getMessage(), e);
}
};
@@ -109,7 +108,7 @@ public class JsScriptEngine extends AbstractScriptEngine {
// 使用超时执行器执行脚本
return ScriptUtils.executeWithTimeout(task, DEFAULT_TIMEOUT_MS);
} catch (Exception e) {
logger.error("执行JavaScript脚本错误: {}", e.getMessage());
log.error("执行JavaScript脚本错误: {}", e.getMessage());
throw new RuntimeException("脚本执行失败: " + e.getMessage(), e);
}
}
@@ -137,7 +136,7 @@ public class JsScriptEngine extends AbstractScriptEngine {
// 执行脚本
return engine.eval(script, bindings);
} catch (ScriptException e) {
logger.error("执行JavaScript脚本异常: {}", e.getMessage());
log.error("执行JavaScript脚本异常: {}", e.getMessage());
throw new RuntimeException("脚本执行异常: " + e.getMessage(), e);
}
};
@@ -146,14 +145,14 @@ public class JsScriptEngine extends AbstractScriptEngine {
// 使用超时执行器执行脚本
return ScriptUtils.executeWithTimeout(task, DEFAULT_TIMEOUT_MS);
} catch (Exception e) {
logger.error("执行JavaScript脚本错误: {}", e.getMessage());
log.error("执行JavaScript脚本错误: {}", e.getMessage());
throw new RuntimeException("脚本执行失败: " + e.getMessage(), e);
}
}
@Override
public void destroy() {
logger.info("销毁JavaScript脚本引擎");
log.info("销毁JavaScript脚本引擎");
cachedScripts.clear();
engine = null;
engineManager = null;

View File

@@ -1,15 +1,14 @@
package cn.iocoder.yudao.module.iot.plugin.script.engine;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* 脚本引擎工厂,用于创建不同类型的脚本引擎
*/
@Component
@Slf4j
public class ScriptEngineFactory {
private static final Logger logger = LoggerFactory.getLogger(ScriptEngineFactory.class);
/**
* 创建JavaScript脚本引擎
@@ -17,7 +16,7 @@ public class ScriptEngineFactory {
* @return JavaScript脚本引擎
*/
public JsScriptEngine createJsEngine() {
logger.debug("创建JavaScript脚本引擎");
log.debug("创建JavaScript脚本引擎");
return new JsScriptEngine();
}

View File

@@ -1,7 +1,6 @@
package cn.iocoder.yudao.module.iot.plugin.script.sandbox;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import lombok.extern.slf4j.Slf4j;
import javax.script.ScriptEngine;
import java.util.Arrays;
@@ -12,8 +11,8 @@ import java.util.regex.Pattern;
/**
* JavaScript脚本沙箱限制脚本的执行权限
*/
@Slf4j
public class JsSandbox implements ScriptSandbox {
private static final Logger logger = LoggerFactory.getLogger(JsSandbox.class);
/**
* 禁止使用的关键字
@@ -59,10 +58,10 @@ public class JsSandbox implements ScriptSandbox {
engine.eval("var Packages = undefined;");
// 增强安全控制可以在这里添加
logger.debug("已应用JavaScript安全沙箱限制");
log.debug("已应用JavaScript安全沙箱限制");
} catch (Exception e) {
logger.warn("应用JavaScript沙箱限制失败: {}", e.getMessage());
log.warn("应用JavaScript沙箱限制失败: {}", e.getMessage());
}
}
@@ -75,20 +74,20 @@ public class JsSandbox implements ScriptSandbox {
// 检查禁止的关键字
for (String keyword : FORBIDDEN_KEYWORDS) {
if (script.contains(keyword)) {
logger.warn("脚本包含禁止使用的关键字: {}", keyword);
log.warn("脚本包含禁止使用的关键字: {}", keyword);
return false;
}
}
// 使用正则表达式检查更复杂的模式
if (FORBIDDEN_PATTERN.matcher(script).find()) {
logger.warn("脚本包含禁止使用的模式");
log.warn("脚本包含禁止使用的模式");
return false;
}
// 脚本长度限制
if (script.length() > 1024 * 100) { // 限制100KB
logger.warn("脚本太大,超过了限制");
log.warn("脚本太大,超过了限制");
return false;
}

View File

@@ -6,13 +6,12 @@ import cn.iocoder.yudao.module.iot.plugin.script.engine.AbstractScriptEngine;
import cn.iocoder.yudao.module.iot.plugin.script.engine.ScriptEngineFactory;
import cn.iocoder.yudao.module.iot.plugin.script.sandbox.JsSandbox;
import cn.iocoder.yudao.module.iot.plugin.script.sandbox.ScriptSandbox;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -20,10 +19,10 @@ import java.util.concurrent.ConcurrentHashMap;
* 脚本服务实现类
*/
@Service
@Slf4j
public class ScriptServiceImpl implements ScriptService {
private static final Logger logger = LoggerFactory.getLogger(ScriptServiceImpl.class);
@Autowired
@Resource
private ScriptEngineFactory engineFactory;
/**
@@ -50,7 +49,7 @@ public class ScriptServiceImpl implements ScriptService {
try {
engine.destroy();
} catch (Exception e) {
logger.error("销毁脚本引擎失败", e);
log.error("销毁脚本引擎失败", e);
}
}
engineCache.clear();
@@ -75,7 +74,7 @@ public class ScriptServiceImpl implements ScriptService {
// 执行脚本
return engine.execute(script, context);
} catch (Exception e) {
logger.error("执行脚本失败: {}", e.getMessage());
log.error("执行脚本失败: {}", e.getMessage());
throw new RuntimeException("执行脚本失败: " + e.getMessage(), e);
}
}
@@ -101,7 +100,7 @@ public class ScriptServiceImpl implements ScriptService {
public boolean validateScript(String scriptType, String script) {
ScriptSandbox sandbox = sandboxCache.get(scriptType.toLowerCase());
if (sandbox == null) {
logger.warn("找不到脚本类型[{}]对应的沙箱使用默认JS沙箱", scriptType);
log.warn("找不到脚本类型[{}]对应的沙箱使用默认JS沙箱", scriptType);
sandbox = new JsSandbox();
sandboxCache.put(scriptType.toLowerCase(), sandbox);
}

View File

@@ -1,8 +1,7 @@
package cn.iocoder.yudao.module.iot.plugin.script.util;
import cn.hutool.json.JSONUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import lombok.extern.slf4j.Slf4j;
import java.util.Map;
import java.util.concurrent.*;
@@ -10,8 +9,8 @@ import java.util.concurrent.*;
/**
* 脚本工具类,提供执行脚本的辅助方法
*/
@Slf4j
public class ScriptUtils {
private static final Logger logger = LoggerFactory.getLogger(ScriptUtils.class);
/**
* 默认脚本执行超时时间(毫秒)
@@ -90,7 +89,7 @@ public class ScriptUtils {
// 使用hutool的JSONUtil工具类解析JSON
return JSONUtil.toBean(json, Map.class);
} catch (Exception e) {
logger.error("解析JSON失败: {}", e.getMessage());
log.error("解析JSON失败: {}", e.getMessage());
return null;
}
}
@@ -114,12 +113,12 @@ public class ScriptUtils {
try {
return Integer.parseInt((String) obj);
} catch (NumberFormatException e) {
logger.debug("无法将字符串转换为整数: {}", obj);
log.debug("无法将字符串转换为整数: {}", obj);
return null;
}
}
logger.debug("无法将对象转换为整数: {}", obj.getClass().getName());
log.debug("无法将对象转换为整数: {}", obj.getClass().getName());
return null;
}
@@ -142,12 +141,12 @@ public class ScriptUtils {
try {
return Double.parseDouble((String) obj);
} catch (NumberFormatException e) {
logger.debug("无法将字符串转换为双精度浮点数: {}", obj);
log.debug("无法将字符串转换为双精度浮点数: {}", obj);
return null;
}
}
logger.debug("无法将对象转换为双精度浮点数: {}", obj.getClass().getName());
log.debug("无法将对象转换为双精度浮点数: {}", obj.getClass().getName());
return null;
}