package jnpf.audit.sdk;
|
|
import jnpf.audit.model.AuditEventDTO;
|
|
/**
|
* 层 3 审计入口(Task 7 Step 4):业务方唯一入口。
|
*
|
* <p>{@code record(dto)} = 校验 eventType/actionCode 非空 → {@link AuditContextCollector#fill(AuditEventDTO)}
|
* 填充冻结 → {@code sourceLayer} 缺省补 3(层 3 入口默认 sourceLayer=3;调用方已显式传值则不覆盖,见下)
|
* → {@link AuditTxHolder#submit(AuditEventDTO, AuditEventPublisher)} 交事务 holder 缓冲
|
* (有事务则 afterCommit 才发、回滚不发;无事务直发)。
|
*
|
* <p>{@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();
|
}
|
}
|