From 43eeef808925abb2728003c83bc94587ff5f2fb1 Mon Sep 17 00:00:00 2001 From: Penknife Date: Mon, 18 Aug 2025 10:41:44 +0800 Subject: [PATCH] =?UTF-8?q?feat():OPC=20UA=E7=8E=AF=E5=A2=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- business/pom.xml | 20 +++-- .../domain/msg/AppMeasureEntryMessage.java | 12 +-- .../domain/msg/AppMeasureExitMessage.java | 15 ++-- .../com/fizz/business/scheduled/10086.txt | 1 - .../fizz/business/scheduled/BaseSchedule.java | 74 +++++++++++++++++ .../scheduled/LineMeasureSchedule.java | 33 ++++++++ .../fizz/business/utils/RedisLockUtil.java | 82 +++++++++++++++++++ pom.xml | 9 ++ .../src/main/resources/application.yml | 35 +++++++- ruoyi-common/pom.xml | 2 - 10 files changed, 258 insertions(+), 25 deletions(-) delete mode 100644 business/src/main/java/com/fizz/business/scheduled/10086.txt create mode 100644 business/src/main/java/com/fizz/business/scheduled/BaseSchedule.java create mode 100644 business/src/main/java/com/fizz/business/scheduled/LineMeasureSchedule.java create mode 100644 business/src/main/java/com/fizz/business/utils/RedisLockUtil.java diff --git a/business/pom.xml b/business/pom.xml index 278b63a..d3d546f 100644 --- a/business/pom.xml +++ b/business/pom.xml @@ -47,12 +47,12 @@ ruoyi-framework - - - org.bouncycastle - bcprov-jdk15on - 1.70 - + + + + + + org.springframework.boot @@ -108,6 +108,14 @@ spring-boot-starter-websocket + + + com.kangaroohy + milo-spring-boot-starter + 3.1.4.0.6.15 + + + diff --git a/business/src/main/java/com/fizz/business/domain/msg/AppMeasureEntryMessage.java b/business/src/main/java/com/fizz/business/domain/msg/AppMeasureEntryMessage.java index a493ccd..0d331fb 100644 --- a/business/src/main/java/com/fizz/business/domain/msg/AppMeasureEntryMessage.java +++ b/business/src/main/java/com/fizz/business/domain/msg/AppMeasureEntryMessage.java @@ -36,14 +36,14 @@ public class AppMeasureEntryMessage extends OpcMessage { @Schema(description = "钢带速度 (m/min)") private BigDecimal stripSpeed; - @Schema(description = "入口活套位置最大值 (m)") - private BigDecimal entryLooperPositionMax; + @Schema(description = "入口活套位置(m)") + private BigDecimal celLength; - @Schema(description = "入口活套位置最小值 (m)") - private BigDecimal entryLooperPositionMin; + @Schema(description = "入口活套百分比(m)") + private BigDecimal celCapacity; - @Schema(description = "当前实际活套位置 (m)") - private BigDecimal entryLooperPositionCurrent; + @Schema(description = "入口活套张力(m)") + private BigDecimal tensionCel ; @Schema(description = "清洗电压 (V)") private BigDecimal cleaningVoltage; diff --git a/business/src/main/java/com/fizz/business/domain/msg/AppMeasureExitMessage.java b/business/src/main/java/com/fizz/business/domain/msg/AppMeasureExitMessage.java index 85f15cb..b72c10c 100644 --- a/business/src/main/java/com/fizz/business/domain/msg/AppMeasureExitMessage.java +++ b/business/src/main/java/com/fizz/business/domain/msg/AppMeasureExitMessage.java @@ -21,17 +21,14 @@ public class AppMeasureExitMessage extends OpcMessage { @Schema(description = "钢带张力 BR8 – BR9 (daN)") private BigDecimal tensionBr8Br9; - @Schema(description = "出口活套位置 (m)") - private BigDecimal deliveryLooperPosition; + @Schema(description = "入口活套位置(m)") + private BigDecimal cxlLength; - @Schema(description = "出口活套最大可用百分比 (%)") - private BigDecimal exitLooperMaxPercent; + @Schema(description = "入口活套百分比(m)") + private BigDecimal cxlCapacity; - @Schema(description = "出口活套最小可用百分比 (%)") - private BigDecimal exitLooperMinPercent; - - @Schema(description = "出口活套当前百分比 (%)") - private BigDecimal exitLooperCurrentPercent; + @Schema(description = "入口活套张力(m)") + private BigDecimal tensionCxl ; @Schema(description = "涂油标志 (0=no, 1=yes)") private Integer oilingFlag; diff --git a/business/src/main/java/com/fizz/business/scheduled/10086.txt b/business/src/main/java/com/fizz/business/scheduled/10086.txt deleted file mode 100644 index 56b6510..0000000 --- a/business/src/main/java/com/fizz/business/scheduled/10086.txt +++ /dev/null @@ -1 +0,0 @@ -11111 \ No newline at end of file diff --git a/business/src/main/java/com/fizz/business/scheduled/BaseSchedule.java b/business/src/main/java/com/fizz/business/scheduled/BaseSchedule.java new file mode 100644 index 0000000..171ef04 --- /dev/null +++ b/business/src/main/java/com/fizz/business/scheduled/BaseSchedule.java @@ -0,0 +1,74 @@ +package com.fizz.business.scheduled; + +import com.fizz.business.utils.RedisLockUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Async; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.stereotype.Component; + +import java.util.function.Consumer; + +@Slf4j +@Async("threadPoolTaskExecutor") +@Component +@EnableScheduling +public abstract class BaseSchedule { + + /** + * 默认key过期时间 1800秒 + */ + private static final int DEFAULT_EXPIRE_SECONDS = 1800; + + protected void execute(String taskName, int cacheSeconds, String cacheKey, Runnable func) { + // 执行完2分钟 删除键值 + int delayedSeconds = Math.min(120, cacheSeconds / 10); + execute(taskName, cacheSeconds, delayedSeconds, cacheKey, k -> func.run()); + } + + /** + * 定时任务执行 多服务防止同时执行 + * + * @param taskName: 任务名称 + * @param cacheSeconds: <= 0时默认时间 + * @param delayedSeconds: 任务执行完延时删除key; <0时默认 cacheSeconds/10 + * @param cacheKey: + * @param func: 执行的任务 key: 处理后的cacheKey + */ + protected void execute(String taskName, int cacheSeconds, int delayedSeconds, String cacheKey, Consumer func) { + String threadName = Thread.currentThread().getName(); + cacheKey = "scheduling:" + cacheKey; + if (cacheSeconds <= 0) { + cacheSeconds = DEFAULT_EXPIRE_SECONDS; + } + if (delayedSeconds < 0) { + delayedSeconds = cacheSeconds / 10; + } + // 不存在键值时执行 + String value = "1"; + boolean success = RedisLockUtil.setIfAbsent(cacheKey, value, cacheSeconds); + if (!success) { + log.debug("定时任务: {}, 取消执行. {}", taskName, threadName); + return; + } + log.debug("定时任务: {}, 开始执行. {}", taskName, threadName); + func.accept(cacheKey); + // 执行完后 延时时间内不可重复执行 + if (delayedSeconds == 0) { + RedisLockUtil.delLock(cacheKey, value); + } else { + RedisLockUtil.setIfPresent(cacheKey, value, delayedSeconds); + } + log.debug("定时任务: {}, 执行结束. {}", taskName, threadName); + } + + public void actionCatchException(Runnable func) { + String threadName = Thread.currentThread().getName(); + try { + func.run(); + } catch (Exception e) { + log.error("定时任务执行出错 " + threadName, e); + } + } + + +} diff --git a/business/src/main/java/com/fizz/business/scheduled/LineMeasureSchedule.java b/business/src/main/java/com/fizz/business/scheduled/LineMeasureSchedule.java new file mode 100644 index 0000000..454c960 --- /dev/null +++ b/business/src/main/java/com/fizz/business/scheduled/LineMeasureSchedule.java @@ -0,0 +1,33 @@ +package com.fizz.business.scheduled; + +import cn.hutool.json.JSONUtil; +import com.kangaroohy.milo.model.ReadWriteEntity; +import com.kangaroohy.milo.service.MiloService; +import jdk.nashorn.internal.runtime.Debug; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.Map; + +@Slf4j +//@Component +@AllArgsConstructor +public class LineMeasureSchedule extends BaseSchedule{ + + @Resource + MiloService miloService; + @Scheduled(fixedDelay = 200) + public void L1L2LineMeasure() { + try { + ReadWriteEntity node = miloService.readFromOpcUa("ns=2;s=通道 2.LockStautsRead.lockStauts1"); + log.debug(node.toString()); + node.getValue(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/business/src/main/java/com/fizz/business/utils/RedisLockUtil.java b/business/src/main/java/com/fizz/business/utils/RedisLockUtil.java new file mode 100644 index 0000000..b5f9602 --- /dev/null +++ b/business/src/main/java/com/fizz/business/utils/RedisLockUtil.java @@ -0,0 +1,82 @@ +package com.fizz.business.utils; + +import cn.hutool.core.lang.Pair; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.script.DefaultRedisScript; +import org.springframework.data.redis.core.script.RedisScript; +import org.springframework.stereotype.Component; + +import javax.validation.constraints.NotNull; +import java.util.Collections; +import java.util.concurrent.Callable; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; + +@Component +public class RedisLockUtil { + private static final Logger log = LoggerFactory.getLogger(RedisLockUtil.class); + public static final RedisScript UNLOCK_SCRIPT = new DefaultRedisScript("if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end", Long.class); + private static final String UNLOCK_LUA = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; + private static RedisTemplate REDIS_TEMPLATE; + + @Autowired + public void setRedisTemplate(RedisTemplate redisTemplate) { + REDIS_TEMPLATE = redisTemplate; + } + + private RedisLockUtil() { + } + + public static boolean setIfAbsent(@NotNull String key, @NotNull String value, int seconds) { + Boolean result = REDIS_TEMPLATE.opsForValue().setIfAbsent(key, value, (long)seconds, TimeUnit.SECONDS); + return result != null && result; + } + + public static boolean setIfPresent(@NotNull String key, @NotNull String value, int seconds) { + Boolean result = REDIS_TEMPLATE.opsForValue().setIfPresent(key, value, (long)seconds, TimeUnit.SECONDS); + return result != null && result; + } + + public static void delLock(@NotNull String key, @NotNull String value) { + REDIS_TEMPLATE.execute(UNLOCK_SCRIPT, Collections.singletonList(key), new Object[]{value}); + } + + public static Pair lockHandle(@NotNull String key, @NotNull Callable callable, @NotNull Function> exceptionHandle) { + String threadName = Thread.currentThread().getName(); + String msg = "RedisLockUtil " + threadName + " {}:" + key; + String value = IdUtil.simpleUUID(); + boolean success = setIfAbsent(key, value, 6000); + if (!success) { + log.debug(msg, "锁获取失败"); + return new Pair(false, (Object)null); + } else { + log.debug(msg, "锁获取成功"); + + Pair var8; + try { + V v = callable.call(); + log.debug(msg, "执行完成"); + var8 = new Pair(true, v); + return var8; + } catch (Exception var12) { + log.error(StrUtil.format(msg, new Object[]{"成功获取锁但执行失败"}), var12); + var8 = (Pair)exceptionHandle.apply(var12); + } finally { + delLock(key, value); + } + + return var8; + } + } + + public static Pair lockHandle(@NotNull String key, @NotNull Callable callable) { + return lockHandle(key, callable, (e) -> { + throw new RuntimeException(key + " 成功获取锁但执行失败:" + e.getMessage()); + }); + } +} diff --git a/pom.xml b/pom.xml index 4f8c787..806d31a 100644 --- a/pom.xml +++ b/pom.xml @@ -34,6 +34,9 @@ 4.5.0 1.7.0 3.5.2 + 0.6.3 + 2.12.0 + @@ -212,6 +215,12 @@ + + org.apache.commons + commons-pool2 + ${commons-pool2.version} + + diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index 512e71d..94d9a65 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -101,6 +101,10 @@ spring: enabled: true max-attempts: 1 max-interval: 200 + task: + scheduling: + pool: + size: 8 #配置Scheduled定时任务为多线程 # token配置 token: @@ -160,4 +164,33 @@ knife4j: language: zh-CN # 中文界面 enable-swagger-model: true # 显示模型 enable-document-manage: true # 启用文档管理 - cors: true # 允许跨域 \ No newline at end of file + cors: true # 允许跨域 + +kangaroohy: + milo: + primary: default + config: + default: + endpoint: opc.tcp://127.0.0.1:49320 + security-policy: none + pool: + max-idle: 5 + max-total: 20 + min-idle: 2 + initial-size: 3 + + +#kangaroohy: +# milo: +# primary: default +# config: +# default: +# endpoint: opc.tcp://127.0.0.1:49320 +# security-policy: basic256sha256 +# username: OPCUA +# password: 123456 +# test: +# endpoint: opc.tcp://127.0.0.1:49321 +# security-policy: basic256sha256 +# username: OPCUA +# password: 123456 \ No newline at end of file diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml index 39f6a4e..bfeb5ee 100644 --- a/ruoyi-common/pom.xml +++ b/ruoyi-common/pom.xml @@ -149,8 +149,6 @@ knife4j-openapi3-spring-boot-starter - -