package jnpf.bizcommon.audit.service; import jnpf.audit.diff.AuditFieldDiff; import jnpf.bizcommon.audit.entity.AuditEventEntity; import jnpf.bizcommon.audit.entity.model.AuditEventListVO; import jnpf.bizcommon.audit.entity.model.AuditOperationGroupRow; import jnpf.bizcommon.audit.service.impl.AuditQueryServiceImpl; import jnpf.bizcommon.audit.service.support.AuditEventCategories; import jnpf.bizcommon.audit.service.support.AuditQueryResponseSanitizer; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; /** 发布表单/COMMENT fallback 与查询脱敏纯 JVM 探针。 */ public final class AuditQuerySemanticsProbe { private static int passed; private static int failed; public static void main(String[] args) { String fields = "[{\"vModel\":\"status\",\"config\":{\"label\":\"表单状态\"," + "\"jnpfKey\":\"select\",\"dataType\":\"dynamic\",\"children\":[" + "{\"vModel\":\"child_name\",\"config\":{\"label\":\"子项名称\"," + "\"jnpfKey\":\"input\",\"dataType\":\"static\"}}]}}," + "{\"vModel\":\"sampleCode\",\"config\":{\"label\":\"样品编码\"," + "\"jnpfKey\":\"input\",\"dataType\":\"static\"}}]"; String formData = "{\"fields\":" + quote(fields) + "}"; Map published = AuditFormRegistry.parsePublishedFieldMetadata(formData); check("发布表单解析 vModel -> label", "表单状态".equals(published.get("status").label()), String.valueOf(published)); check("发布表单递归解析 children", "子项名称".equals(published.get("child_name").label()), String.valueOf(published)); check("动态 select 标记 nameModified", Boolean.TRUE.equals(published.get("status").nameModified()), String.valueOf(published.get("status").nameModified())); Map camelCaseRow = new LinkedHashMap<>(); camelCaseRow.put("sampleCode", "S-001"); String camelCaseDiff = AuditFieldDiff.diff( Collections.emptyMap(), camelCaseRow, Collections.emptySet(), published); check("camelCase vModel 可匹配小写元数据键", camelCaseDiff.contains("\"fieldName\":\"样品编码\""), camelCaseDiff); Map comments = new LinkedHashMap<>(); comments.put("status", new AuditFieldDiff.FieldMeta("COMMENT 状态", null, null)); comments.put("comment_only", new AuditFieldDiff.FieldMeta("COMMENT 专属字段", null, null)); Map merged = AuditFormRegistry.mergeFieldMetadata(comments, published); check("发布表单名称优先于 COMMENT", "表单状态".equals(merged.get("status").label()), merged.get("status").label()); check("表单缺失时使用 COMMENT fallback", "COMMENT 专属字段".equals(merged.get("comment_only").label()), merged.get("comment_only").label()); Map event = new LinkedHashMap<>(); event.put("status", new AuditFieldDiff.FieldMeta("事件当时状态", "select", true)); Map finalMeta = AuditFormRegistry.mergeFieldMetadata(merged, event); check("事件 listLog 优先于当前发布表单", "事件当时状态".equals(finalMeta.get("status").label()), finalMeta.get("status").label()); String diffs = "[{\"field\":\"status\",\"fieldName\":\"status\",\"oldData\":\"a\",\"newData\":\"b\"}," + "{\"field\":\"unknown_col\",\"fieldName\":\"unknown_col\",\"oldData\":\"a\",\"newData\":\"b\"}," + "{\"field\":\"biz_sign\",\"fieldName\":\"biz_sign\",\"oldData\":\"secret-1\",\"newData\":\"secret-2\"}]"; String sanitized = AuditQueryResponseSanitizer.sanitizeFieldDiffs(diffs, finalMeta); check("历史技术名按当前元数据装饰", sanitized.contains("\"fieldName\":\"事件当时状态\""), sanitized); check("元数据和 COMMENT 都缺失时回落数据库字段名", sanitized.contains("\"fieldName\":\"unknown_col\""), sanitized); check("biz_sign 在历史 diff 中不暴露", !sanitized.contains("secret-1") && !sanitized.contains("secret-2") && sanitized.contains("电子签名已关联"), sanitized); String json = "{\"biz_sign\":\"credential\",\"nested\":{\"approveSignId\":\"credential-2\"," + "\"targetId\":\"business-id\"}}"; String safeJson = AuditQueryResponseSanitizer.sanitizeJson(json); check("extra/snapshot 深度脱敏签名凭证", !safeJson.contains("credential") && safeJson.contains("business-id"), safeJson); String childDiff = "[{\"field\":\"tableField1\",\"jnpfKey\":\"table\"," + "\"chidField\":[{\"prop\":\"item_name\",\"label\":\"项目\"}," + "{\"prop\":\"review_sign\",\"label\":\"复审签名\",\"jnpfKey\":\"sign\"}]," + "\"chidData\":[{\"item_name\":\"含量\",\"review_sign\":\"child-secret-new\"," + "\"jnpf_old_review_sign\":\"child-secret-old\",\"jnpf_type\":1}]}]"; String safeChildDiff = AuditQueryResponseSanitizer.sanitizeFieldDiffs( childDiff, Collections.emptyMap()); check("子表签名列的新旧凭证均脱敏且普通列保留", safeChildDiff != null && !safeChildDiff.contains("child-secret") && safeChildDiff.contains("含量") && safeChildDiff.contains("\"masked\":true"), safeChildDiff); check("lims_sign targetId 不返回普通查询", AuditQueryResponseSanitizer.hidesTargetId("LIMS_SIGN"), "未命中"); String missing = AuditQueryResponseSanitizer.sanitizeFieldDiffs( "[{\"field\":\"x\",\"fieldName\":\"x\"}]", Collections.emptyMap()); check("空元数据回落数据库字段名", missing != null && missing.contains("\"fieldName\":\"x\""), missing); Map databaseMeta = new LinkedHashMap<>(); databaseMeta.put("biz_status", new AuditFieldDiff.FieldMeta("业务状态", null, null)); databaseMeta.put("creator_time", new AuditFieldDiff.FieldMeta(null, null, null)); String historical = AuditQueryResponseSanitizer.sanitizeFieldDiffs( "[{\"field\":\"bizStatus\",\"fieldName\":\"bizStatus\"}," + "{\"field\":\"creatorTime\",\"fieldName\":\"creatorTime\"}]", databaseMeta); check("历史 Java 属性名可映射数据库备注", historical.contains("\"fieldName\":\"业务状态\""), historical); check("历史 Java 属性名在备注为空时回落数据库列名", historical.contains("\"fieldName\":\"creator_time\""), historical); String repeatedFields = "[{\"field\":\"status\",\"oldData\":\"a\",\"newData\":\"b\"}," + "{\"field\":\"status\",\"oldData\":\"b\",\"newData\":\"c\"}," + "{\"field\":\"amount\",\"oldData\":1,\"newData\":2}]"; check("重复字段按字段并集计数", AuditQueryResponseSanitizer.effectiveDiffCount(repeatedFields) == 2, String.valueOf(AuditQueryResponseSanitizer.effectiveDiffFields(repeatedFields))); String sameFieldAcrossTables = "[{\"targetTable\":\"main_table\",\"field\":\"status\"," + "\"oldData\":\"a\",\"newData\":\"b\"}," + "{\"targetTable\":\"child_table\",\"field\":\"status\"," + "\"oldData\":\"x\",\"newData\":\"y\"}," + "{\"targetTable\":\"child_table\",\"field\":\"status\"," + "\"oldData\":\"y\",\"newData\":\"z\"}]"; check("主子表同名字段按物理表分别计数", AuditQueryResponseSanitizer.effectiveDiffCount(sameFieldAcrossTables) == 2, String.valueOf(AuditQueryResponseSanitizer.effectiveDiffFields(sameFieldAcrossTables))); String batchSameField = "[{\"targetTable\":\"lims_task\",\"targetId\":\"row-1\"," + "\"field\":\"status\",\"oldData\":\"a\",\"newData\":\"b\"}," + "{\"targetTable\":\"lims_task\",\"targetId\":\"row-2\"," + "\"field\":\"status\",\"oldData\":\"x\",\"newData\":\"b\"}]"; check("批量逐记录差异的摘要仍按表和字段计为一个", AuditQueryResponseSanitizer.effectiveDiffCount(batchSameField) == 1, String.valueOf(AuditQueryResponseSanitizer.effectiveDiffFields(batchSameField))); verifyOperationDisplayGrouping(); System.out.println("=== 查询语义断言:" + passed + " 通过 / " + failed + " 失败 ==="); System.exit(failed == 0 ? 0 : 1); } @SuppressWarnings("unchecked") private static void verifyOperationDisplayGrouping() { AuditEventEntity business = event(101L, AuditEventCategories.BUSINESS, "BIZ_ACTION", "[{\"field\":\"status\",\"oldData\":\"a\",\"newData\":\"b\"}]"); AuditEventEntity primary = event(102L, AuditEventCategories.PRIMARY_SIGN, "E_SIGNATURE", "[{\"field\":\"sign_a\"},{\"field\":\"sign_b\"}]"); AuditEventEntity review = event(103L, AuditEventCategories.REVIEW_SIGN, "E_SIGNATURE", null); AuditOperationGroupRow group = new AuditOperationGroupRow(); group.setGid("op-display-1"); try { Method method = AuditQueryServiceImpl.class.getDeclaredMethod( "buildOperationRows", List.class, List.class); method.setAccessible(true); List rows = (List) method.invoke( new AuditQueryServiceImpl(), Collections.singletonList(group), Arrays.asList(primary, business, review)); AuditEventListVO main = rows.isEmpty() ? null : rows.get(0); check("operationId 列表只返回 BUSINESS 主行", rows.size() == 1 && main != null && Long.valueOf(101L).equals(main.getId()), String.valueOf(rows)); check("主签名与复审签名作为两条关联明细", main != null && main.getSubEvents() != null && main.getSubEvents().size() == 2 && "PRIMARY".equals(main.getSubEvents().get(0).getSignatureRole()) && "REVIEW".equals(main.getSubEvents().get(1).getSignatureRole()), main == null ? "null" : String.valueOf(main.getSubEvents())); check("查询层不累加签名差异数", main != null && Integer.valueOf(1).equals(main.getDiffCount()), main == null ? "null" : String.valueOf(main.getDiffCount())); } catch (ReflectiveOperationException ex) { throw new AssertionError("无法执行 operationId 展示组装探针", ex); } } private static AuditEventEntity event(Long id, String category, String eventType, String fieldDiffs) { AuditEventEntity event = new AuditEventEntity(); event.setId(id); event.setOperationId("op-display-1"); event.setClientEventId("client-" + id); event.setEventCategory(category); event.setEventType(eventType); event.setFieldDiffs(fieldDiffs); return event; } private static String quote(String value) { return "\"" + value.replace("\\", "\\\\").replace("\"", "\\\"") + "\""; } private static void check(String name, boolean ok, String detail) { if (ok) { passed++; System.out.println(" [PASS] " + name); } else { failed++; System.out.println(" [FAIL] " + name + " -- " + detail); } } private AuditQuerySemanticsProbe() { } }