package jnpf.audit.sdk; import jnpf.audit.model.AuditEventDTO; /** * 层 3 审计入口(Task 7 Step 4):业务方唯一入口。 * *
{@code record(dto)} = 校验 eventType/actionCode 非空 → {@link AuditContextCollector#fill(AuditEventDTO)} * 填充冻结 → {@code sourceLayer} 缺省补 3(层 3 入口默认 sourceLayer=3;调用方已显式传值则不覆盖,见下) * → {@link AuditTxHolder#submit(AuditEventDTO, AuditEventPublisher)} 交事务 holder 缓冲 * (有事务则 afterCommit 才发、回滚不发;无事务直发)。 * *
{@code audit.enabled=false} 或当前请求不在 {@link AuditRequestScopeFilter} 允许范围内时, * {@code record} 直接 no-op。 */ public class AuditClient { private final AuditContextCollector collector; private final AuditEventPublisher publisher; private final boolean enabled; private final AuditRequestScopeFilter requestScopeFilter; public AuditClient(AuditContextCollector collector, AuditEventPublisher publisher, boolean enabled) { this(collector, publisher, enabled, new AuditRequestScopeFilter(false, "")); } public AuditClient(AuditContextCollector collector, AuditEventPublisher publisher, boolean enabled, AuditRequestScopeFilter requestScopeFilter) { this.collector = collector; this.publisher = publisher; this.enabled = enabled; this.requestScopeFilter = requestScopeFilter; } public void record(AuditEventDTO dto) { if (!enabled || !requestScopeFilter.acceptsCurrentRequest()) { return; } if (dto == null) { throw new IllegalArgumentException("审计事件 dto 不能为空"); } if (isBlank(dto.getEventType())) { throw new IllegalArgumentException("eventType 不能为空"); } if (isBlank(dto.getActionCode())) { throw new IllegalArgumentException("actionCode 不能为空"); } collector.fill(dto); if (dto.getSourceLayer() == null) { // 裁定修复 B:本 SDK 是层 3 显式接口入口,语义上 sourceLayer 恒为 3; // 调用方未显式传值时在此补齐,否则服务端 validate(sourceLayer 非空硬校验)会拒收该事件。 // 调用方已显式传值(如上层框架转发已知层号)则尊重不覆盖。 dto.setSourceLayer(3); } AuditTxHolder.submit(dto, publisher); } private static boolean isBlank(String s) { return s == null || s.trim().isEmpty(); } }