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