From 34981c30a78e8bbd7791131059a9210f9928b62c Mon Sep 17 00:00:00 2001
From: 刘光辉 <347230014@qq.com>
Date: 星期四, 17 九月 2026 09:24:09 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master' into master
---
jnpf-lims/jnpf-lims-biz/src/main/java/jnpf/limsService/support/LimsSignUsageSupport.java | 217 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 217 insertions(+), 0 deletions(-)
diff --git a/jnpf-lims/jnpf-lims-biz/src/main/java/jnpf/limsService/support/LimsSignUsageSupport.java b/jnpf-lims/jnpf-lims-biz/src/main/java/jnpf/limsService/support/LimsSignUsageSupport.java
new file mode 100644
index 0000000..d8eb55a
--- /dev/null
+++ b/jnpf-lims/jnpf-lims-biz/src/main/java/jnpf/limsService/support/LimsSignUsageSupport.java
@@ -0,0 +1,217 @@
+package jnpf.limsService.support;
+
+import jnpf.limsEntity.LimsSignEntity;
+import jnpf.limsEntity.LimsSignUsageTarget;
+import jnpf.limsEntity.SignOpType;
+
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.TimeZone;
+
+/** 鐢靛瓙绛惧悕浣跨敤浜嬩欢鐨勮鑼冨寲銆佸垎缁勫拰骞傜瓑閿敓鎴愩�� */
+public final class LimsSignUsageSupport {
+
+ public static final int SCHEMA_VERSION = 1;
+ public static final String ACTION_SIGN_USED = "SIGN_USED";
+
+ private LimsSignUsageSupport() {
+ }
+
+ /**
+ * 娓呯悊绌虹洰鏍囧苟鎸� table + id 鍘婚噸锛屼繚鎸佷笟鍔℃墽琛岄『搴忋��
+ */
+ public static List<LimsSignUsageTarget> normalizeTargets(Collection<LimsSignUsageTarget> targets) {
+ if (targets == null || targets.isEmpty()) {
+ return Collections.emptyList();
+ }
+ List<LimsSignUsageTarget> normalized = new ArrayList<>();
+ Set<String> seen = new LinkedHashSet<>();
+ for (LimsSignUsageTarget target : targets) {
+ if (target == null || isBlank(target.getTargetTable()) || isBlank(target.getTargetId())
+ || isBlank(target.getBizType()) || isBlank(target.getBizModule())
+ || isBlank(target.getBizCode())) {
+ continue;
+ }
+ String key = target.getTargetTable().trim().toLowerCase(Locale.ROOT)
+ + "\n" + target.getTargetId().trim();
+ if (!seen.add(key)) {
+ continue;
+ }
+ normalized.add(LimsSignUsageTarget.builder()
+ .targetTable(target.getTargetTable().trim().toLowerCase(Locale.ROOT))
+ .targetId(target.getTargetId().trim())
+ .bizType(target.getBizType().trim())
+ .bizModule(target.getBizModule().trim())
+ .bizCode(target.getBizCode().trim())
+ .build());
+ }
+ return normalized;
+ }
+
+ /** 姣忎釜鍞竴 bizCode 褰㈡垚涓�涓椂闂寸嚎浜嬩欢锛涚粍鍐呬繚鐣欏疄闄呯洰鏍囥�� */
+ public static List<UsageGroup> groupByBizCode(Collection<LimsSignUsageTarget> targets) {
+ Map<String, UsageGroup> groups = new LinkedHashMap<>();
+ for (LimsSignUsageTarget target : normalizeTargets(targets)) {
+ UsageGroup group = groups.get(target.getBizCode());
+ if (group == null) {
+ group = new UsageGroup(target.getBizType(), target.getBizModule(), target.getBizCode());
+ groups.put(target.getBizCode(), group);
+ }
+ group.targets.add(target);
+ }
+ return new ArrayList<>(groups.values());
+ }
+
+ /**
+ * SIGN_USED 鐨勭‘瀹氭�у箓绛夐敭銆傜洰鏍囬『搴忎笌閲嶅椤逛笉浼氭敼鍙樼粨鏋滐紝闀垮害鍥哄畾涓� 67锛屽皬浜� DB varchar(70)銆�
+ */
+ public static String clientEventId(String signId, SignOpType opType, UsageGroup group) {
+ List<String> targetKeys = new ArrayList<>();
+ for (LimsSignUsageTarget target : group.targets) {
+ targetKeys.add(target.getTargetTable() + ":" + target.getTargetId());
+ }
+ targetKeys.sort(Comparator.naturalOrder());
+ String source = value(signId) + "\n" + (opType == null ? "" : opType.getCode())
+ + "\n" + value(group.bizType) + "\n" + value(group.bizModule)
+ + "\n" + value(group.bizCode)
+ + "\n" + String.join("\n", targetKeys);
+ return "SU-" + sha256(source);
+ }
+
+ /** lims_sign.extra_json锛氳姹傜洰鏍囦粎浣滆姹傛憳瑕侊紝affectedTargets 鎵嶆槸鎵ц浜嬪疄銆� */
+ public static Map<String, Object> signExtra(Collection<String> requestedTargetIds,
+ Collection<LimsSignUsageTarget> actualTargets) {
+ List<LimsSignUsageTarget> targets = normalizeTargets(actualTargets);
+ targets.sort(Comparator.comparing(LimsSignUsageTarget::getTargetTable)
+ .thenComparing(LimsSignUsageTarget::getTargetId)
+ .thenComparing(LimsSignUsageTarget::getBizType)
+ .thenComparing(LimsSignUsageTarget::getBizModule)
+ .thenComparing(LimsSignUsageTarget::getBizCode));
+ Map<String, Object> extra = new LinkedHashMap<>();
+ extra.put("schemaVersion", SCHEMA_VERSION);
+ extra.put("requestedTargets", normalizeIds(requestedTargetIds));
+ List<Map<String, Object>> affectedTargets = new ArrayList<>();
+ for (LimsSignUsageTarget target : targets) {
+ Map<String, Object> item = new LinkedHashMap<>();
+ item.put("targetTable", target.getTargetTable());
+ item.put("targetId", target.getTargetId());
+ item.put("bizType", target.getBizType());
+ item.put("bizModule", target.getBizModule());
+ item.put("bizCode", target.getBizCode());
+ affectedTargets.add(item);
+ }
+ extra.put("affectedTargets", affectedTargets);
+ extra.put("affected", targets.size());
+ return extra;
+ }
+
+ /** 鍗曚釜 SIGN_USED 浜嬩欢鐨� extra锛屼粎鍖呭惈璇� bizCode 涓嬬殑瀹為檯鎴愬姛鐩爣銆� */
+ public static Map<String, Object> eventExtra(LimsSignEntity sign, SignOpType opType, UsageGroup group) {
+ Map<String, Object> extra = new LinkedHashMap<>();
+ extra.put("schemaVersion", SCHEMA_VERSION);
+ extra.put("opType", opType == null ? null : opType.getCode());
+ extra.put("bizModule", group.getBizModule());
+ extra.put("signerUserId", sign == null ? null : sign.getCreatorUserId());
+ extra.put("signerAccount", sign == null ? null : sign.getAccountName());
+ extra.put("signedAt", sign == null ? null : formatDate(sign.getCreatorTime()));
+
+ Set<String> tables = new LinkedHashSet<>();
+ List<String> ids = new ArrayList<>();
+ for (LimsSignUsageTarget target : group.targets) {
+ tables.add(target.getTargetTable());
+ ids.add(target.getTargetId());
+ }
+ extra.put("businessTargetTable", tables.size() == 1 ? tables.iterator().next() : null);
+ extra.put("affectedTargetIds", ids);
+ extra.put("affected", ids.size());
+ return extra;
+ }
+
+ private static List<String> normalizeIds(Collection<String> ids) {
+ if (ids == null || ids.isEmpty()) {
+ return Collections.emptyList();
+ }
+ Set<String> normalized = new LinkedHashSet<>();
+ for (String id : ids) {
+ if (!isBlank(id)) {
+ normalized.add(id.trim());
+ }
+ }
+ List<String> result = new ArrayList<>(normalized);
+ result.sort(Comparator.naturalOrder());
+ return result;
+ }
+
+ private static String formatDate(Date date) {
+ if (date == null) {
+ return null;
+ }
+ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX", Locale.ROOT);
+ format.setTimeZone(TimeZone.getDefault());
+ return format.format(date);
+ }
+
+ private static String sha256(String value) {
+ try {
+ byte[] digest = MessageDigest.getInstance("SHA-256").digest(value.getBytes(StandardCharsets.UTF_8));
+ StringBuilder out = new StringBuilder(digest.length * 2);
+ for (byte b : digest) {
+ out.append(String.format(Locale.ROOT, "%02x", b & 0xff));
+ }
+ return out.toString();
+ } catch (NoSuchAlgorithmException e) {
+ throw new IllegalStateException("JDK 缂哄皯 SHA-256", e);
+ }
+ }
+
+ private static String value(String value) {
+ return value == null ? "" : value;
+ }
+
+ private static boolean isBlank(String value) {
+ return value == null || value.trim().isEmpty();
+ }
+
+ /** 涓�涓鑼冧笟鍔$紪鍙峰搴旂殑绛惧悕浣跨敤浜嬩欢鍒嗙粍銆� */
+ public static final class UsageGroup {
+ private final String bizType;
+ private final String bizModule;
+ private final String bizCode;
+ private final List<LimsSignUsageTarget> targets = new ArrayList<>();
+
+ private UsageGroup(String bizType, String bizModule, String bizCode) {
+ this.bizType = bizType;
+ this.bizModule = bizModule;
+ this.bizCode = bizCode;
+ }
+
+ public String getBizType() {
+ return bizType;
+ }
+
+ public String getBizCode() {
+ return bizCode;
+ }
+
+ public String getBizModule() {
+ return bizModule;
+ }
+
+ public List<LimsSignUsageTarget> getTargets() {
+ return Collections.unmodifiableList(targets);
+ }
+ }
+}
--
Gitblit v1.8.0