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-biz-common/jnpf-biz-common-audit/src/main/java/jnpf/bizcommon/audit/service/support/AuditQueryResponseSanitizer.java |  322 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 322 insertions(+), 0 deletions(-)

diff --git a/jnpf-biz-common/jnpf-biz-common-audit/src/main/java/jnpf/bizcommon/audit/service/support/AuditQueryResponseSanitizer.java b/jnpf-biz-common/jnpf-biz-common-audit/src/main/java/jnpf/bizcommon/audit/service/support/AuditQueryResponseSanitizer.java
new file mode 100644
index 0000000..9896f22
--- /dev/null
+++ b/jnpf-biz-common/jnpf-biz-common-audit/src/main/java/jnpf/bizcommon/audit/service/support/AuditQueryResponseSanitizer.java
@@ -0,0 +1,322 @@
+package jnpf.bizcommon.audit.service.support;
+
+import com.alibaba.fastjson.JSON;
+import jnpf.audit.diff.AuditFieldDiff;
+
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+/** 瀹¤鏌ヨ鍝嶅簲鐨勫瓧娈靛悕瑁呴グ涓庣鍚嶅嚟璇佽劚鏁忥紱涓嶄慨鏀瑰師濮嬩簨浠躲�� */
+public final class AuditQueryResponseSanitizer {
+
+    public static final String SIGN_REFERENCE_LABEL = "鐢靛瓙绛惧悕宸插叧鑱�";
+
+    private AuditQueryResponseSanitizer() {
+    }
+
+    /**
+     * 瑁呴グ field_diffs 鐨勫睍绀哄悕锛屽苟瀵瑰巻鍙� biz_sign / *_sign 鍊煎仛鍝嶅簲绾ц劚鏁忋��
+     * JSON 宸叉崯鍧忔椂杩斿洖 null锛岄伩鍏嶇粫杩囩粨鏋勫寲鑴辨晱銆�
+     */
+    @SuppressWarnings("unchecked")
+    public static String sanitizeFieldDiffs(
+            String json, Map<String, AuditFieldDiff.FieldMeta> metadata) {
+        if (json == null || json.trim().isEmpty()) {
+            return json;
+        }
+        try {
+            Object parsed = JSON.parse(json);
+            if (!(parsed instanceof List)) {
+                return null;
+            }
+            List<Object> effective = new ArrayList<>();
+            for (Object raw : (List<?>) parsed) {
+                if (!(raw instanceof Map)) {
+                    continue;
+                }
+                Map<String, Object> item = (Map<String, Object>) raw;
+                if (isNoopDiff(item)) {
+                    continue;
+                }
+                sanitizeChildDiff(item);
+                String field = string(item.get("field"));
+                if (field == null) {
+                    continue;
+                }
+                AuditFieldDiff.FieldMeta meta = lookup(metadata, field);
+                if (isCredentialReference(field, item, meta)) {
+                    item.put("fieldName", SIGN_REFERENCE_LABEL);
+                    item.put("masked", true);
+                    item.put("valueType", "masked");
+                    item.put("componentType", "sign");
+                    if (item.containsKey("oldData")) {
+                        item.put("oldData", AuditFieldDiff.MASKED);
+                    }
+                    if (item.containsKey("newData")) {
+                        item.put("newData", AuditFieldDiff.MASKED);
+                    }
+                    item.remove("oldDisplay");
+                    item.remove("newDisplay");
+                    effective.add(item);
+                    continue;
+                }
+
+                String fieldName = string(item.get("fieldName"));
+                if (fieldName == null || (field != null && fieldName.equalsIgnoreCase(field))) {
+                    String label = meta == null ? null : meta.label();
+                    item.put("fieldName", label == null || label.trim().isEmpty()
+                            ? databaseFieldName(metadata, field) : label);
+                }
+                effective.add(item);
+            }
+            return JSON.toJSONString(effective);
+        } catch (Throwable t) {
+            return null;
+        }
+    }
+
+    /** 娣卞害鑴辨晱 extra / data_snapshot 涓互鏁忔劅閿壙杞界殑鍑瘉鍊笺�� */
+    public static String sanitizeJson(String json) {
+        return sanitizeJson(json, null);
+    }
+
+    /** 娣卞害鑴辨晱锛屽苟鐢ㄥ瓧娈靛厓鏁版嵁璇嗗埆闈炲浐瀹氬垪鍚嶇殑绛惧悕鎺т欢銆� */
+    public static String sanitizeJson(
+            String json, Map<String, AuditFieldDiff.FieldMeta> metadata) {
+        if (json == null || json.trim().isEmpty()) {
+            return json;
+        }
+        try {
+            Object parsed = JSON.parse(json);
+            sanitizeValue(parsed, metadata);
+            return JSON.toJSONString(parsed);
+        } catch (Throwable t) {
+            return null;
+        }
+    }
+
+    /** 浠庡眰 0 extra 鍙� sourceModelId锛屽彧鐢ㄤ簬鏌ヨ褰撳墠瀛楁鍏冩暟鎹�� */
+    @SuppressWarnings("unchecked")
+    public static String sourceModelId(String extra) {
+        if (extra == null || extra.trim().isEmpty()) {
+            return null;
+        }
+        try {
+            Object parsed = JSON.parse(extra);
+            if (!(parsed instanceof Map)) {
+                return null;
+            }
+            return string(((Map<String, Object>) parsed).get("sourceModelId"));
+        } catch (Throwable t) {
+            return null;
+        }
+    }
+
+    public static boolean hidesTargetId(String targetTable) {
+        return targetTable != null && "lims_sign".equalsIgnoreCase(targetTable.trim());
+    }
+
+    /** 鍒楄〃鎽樿涓庤鎯呭叡鐢ㄧ殑鏈夋晥 diff 璁℃暟锛涗細鎺掗櫎绌哄埌绌哄強鐩稿悓鍊间吉鍙樻洿銆� */
+    @SuppressWarnings("unchecked")
+    public static int effectiveDiffCount(String json) {
+        return effectiveDiffFields(json).size();
+    }
+
+    /** 杩斿洖鏈夋晥鍙樻洿瀛楁锛屼緵鍚屼竴鎿嶄綔鐨勫鏉′笟鍔′簨浠舵寜瀛楁骞堕泦鍚堝苟鎽樿銆� */
+    @SuppressWarnings("unchecked")
+    public static Set<String> effectiveDiffFields(String json) {
+        Set<String> fields = new LinkedHashSet<>();
+        if (json == null || json.trim().isEmpty()) {
+            return fields;
+        }
+        try {
+            Object parsed = JSON.parse(json);
+            if (!(parsed instanceof List)) {
+                return fields;
+            }
+            for (Object raw : (List<?>) parsed) {
+                if (!(raw instanceof Map)) {
+                    continue;
+                }
+                Map<String, Object> item = (Map<String, Object>) raw;
+                String field = string(item.get("field"));
+                if (field != null && !isNoopDiff(item)) {
+                    String targetTable = string(item.get("targetTable"));
+                    fields.add(AuditDiffKey.of(targetTable, field));
+                }
+            }
+        } catch (Throwable ignored) {
+            // 闈炴硶鍘嗗彶 JSON 鎸夋棤鍙樻洿闄嶇骇锛屼笉鑳藉奖鍝嶅垪琛ㄦ煡璇€��
+        }
+        return fields;
+    }
+
+    public static boolean isCredentialReference(String field) {
+        if (field == null) {
+            return false;
+        }
+        String trimmed = field.trim();
+        String lower = trimmed.toLowerCase(Locale.ROOT);
+        return "biz_sign".equals(lower)
+                || "bizsign".equals(lower)
+                || "sign_id".equals(lower)
+                || "signid".equals(lower)
+                || lower.endsWith("_sign")
+                || trimmed.endsWith("Sign")
+                || trimmed.endsWith("SignId");
+    }
+
+    /** 瀛楁鍚嶃�佷簨浠跺揩鐓у厓鏁版嵁鍜屽綋鍓嶈〃鍗曞厓鏁版嵁浠讳竴纭鏄鍚嶅嚟璇侊紝閮藉繀椤昏劚鏁忋�� */
+    public static boolean isCredentialReference(String field, Map<String, Object> item,
+                                                AuditFieldDiff.FieldMeta metadata) {
+        return isCredentialReference(field)
+                || bool(item == null ? null : item.get("masked"))
+                || "masked".equalsIgnoreCase(string(item == null ? null : item.get("valueType")))
+                || isSignComponent(item == null ? null : item.get("componentType"))
+                || isSignComponent(item == null ? null : item.get("jnpfKey"))
+                || AuditFieldDiff.isCredentialMetadata(metadata);
+    }
+
+    private static boolean isNoopDiff(Map<String, Object> item) {
+        // 鍘嗗彶鍧忔暟鎹彲鑳藉彧淇濈暀 field/fieldName銆傛病鏈夊畬鏁村墠鍚庡�兼椂鏃犳硶璇佹槑鏄吉鍙樻洿锛�
+        // 搴旂户缁繑鍥炰緵璇佹嵁杩借釜锛涘彧鏈変袱渚у�奸敭閮藉瓨鍦ㄦ椂鎵嶈繃婊ょ┖鍒扮┖鎴栧畬鍏ㄧ浉鍚屻��
+        if (!item.containsKey("oldData") || !item.containsKey("newData")) {
+            return false;
+        }
+        Object oldValue = item.get("oldData");
+        Object newValue = item.get("newData");
+        if (AuditFieldDiff.MASKED.equals(String.valueOf(oldValue))
+                || AuditFieldDiff.MASKED.equals(String.valueOf(newValue))) {
+            return false;
+        }
+        return canonical(oldValue).equals(canonical(newValue));
+    }
+
+    @SuppressWarnings("unchecked")
+    private static void sanitizeChildDiff(Map<String, Object> item) {
+        Object fieldsRaw = item.get("chidField");
+        Object dataRaw = item.get("chidData");
+        if (!(fieldsRaw instanceof List) || !(dataRaw instanceof List)) {
+            return;
+        }
+        for (Object rawField : (List<?>) fieldsRaw) {
+            if (!(rawField instanceof Map)) {
+                continue;
+            }
+            Map<String, Object> field = (Map<String, Object>) rawField;
+            String prop = string(field.get("prop"));
+            boolean credential = prop != null && (isCredentialReference(prop)
+                    || isSignComponent(field.get("jnpfKey"))
+                    || bool(field.get("masked")));
+            if (!credential) {
+                continue;
+            }
+            field.put("masked", true);
+            for (Object rawRow : (List<?>) dataRaw) {
+                if (!(rawRow instanceof Map)) {
+                    continue;
+                }
+                Map<String, Object> row = (Map<String, Object>) rawRow;
+                if (row.containsKey(prop)) {
+                    row.put(prop, AuditFieldDiff.MASKED);
+                }
+                String oldProp = "jnpf_old_" + prop;
+                if (row.containsKey(oldProp)) {
+                    row.put(oldProp, AuditFieldDiff.MASKED);
+                }
+            }
+        }
+    }
+
+    private static String canonical(Object value) {
+        if (value == null) {
+            return "";
+        }
+        if (value instanceof CharSequence) {
+            String text = value.toString();
+            return text.trim().isEmpty() ? "" : "string:" + text;
+        }
+        if (value instanceof java.util.Collection && ((java.util.Collection<?>) value).isEmpty()) {
+            return "";
+        }
+        if (value instanceof Map && ((Map<?, ?>) value).isEmpty()) {
+            return "";
+        }
+        return "json:" + JSON.toJSONString(value);
+    }
+
+    @SuppressWarnings("unchecked")
+    private static void sanitizeValue(
+            Object value, Map<String, AuditFieldDiff.FieldMeta> metadata) {
+        if (value instanceof Map) {
+            Map<Object, Object> map = (Map<Object, Object>) value;
+            for (Map.Entry<Object, Object> entry : map.entrySet()) {
+                String field = String.valueOf(entry.getKey());
+                if (isCredentialReference(field)
+                        || AuditFieldDiff.isCredentialMetadata(lookup(metadata, field))) {
+                    entry.setValue(AuditFieldDiff.MASKED);
+                } else {
+                    sanitizeValue(entry.getValue(), metadata);
+                }
+            }
+        } else if (value instanceof List) {
+            for (Object item : (List<?>) value) {
+                sanitizeValue(item, metadata);
+            }
+        }
+    }
+
+    private static boolean isSignComponent(Object value) {
+        String component = string(value);
+        return "sign".equalsIgnoreCase(component) || "signature".equalsIgnoreCase(component);
+    }
+
+    private static boolean bool(Object value) {
+        return value instanceof Boolean ? (Boolean) value
+                : value != null && "true".equalsIgnoreCase(String.valueOf(value));
+    }
+
+    private static AuditFieldDiff.FieldMeta lookup(
+            Map<String, AuditFieldDiff.FieldMeta> metadata, String field) {
+        if (metadata == null || field == null) {
+            return null;
+        }
+        AuditFieldDiff.FieldMeta exact = metadata.get(field);
+        if (exact != null) {
+            return exact;
+        }
+        AuditFieldDiff.FieldMeta normalized = metadata.get(field.toLowerCase(Locale.ROOT));
+        return normalized != null ? normalized : metadata.get(camelToSnake(field));
+    }
+
+    private static String databaseFieldName(
+            Map<String, AuditFieldDiff.FieldMeta> metadata, String field) {
+        String snake = camelToSnake(field);
+        return metadata != null && metadata.containsKey(snake) ? snake : field;
+    }
+
+    private static String camelToSnake(String value) {
+        StringBuilder out = new StringBuilder(value.length() + 8);
+        for (int i = 0; i < value.length(); i++) {
+            char ch = value.charAt(i);
+            if (Character.isUpperCase(ch)) {
+                out.append('_').append(Character.toLowerCase(ch));
+            } else {
+                out.append(Character.toLowerCase(ch));
+            }
+        }
+        return out.toString();
+    }
+
+    private static String string(Object value) {
+        if (value == null) {
+            return null;
+        }
+        String text = String.valueOf(value).trim();
+        return text.isEmpty() ? null : text;
+    }
+}

--
Gitblit v1.8.0