feat(audit): 增强审计日志功能

- 添加数据库迁移脚本,为 audit_log 表补充缺失字段(create_by, update_by, updated_at, deleted_at)
- 改进审计日志切面,排除对审计日志实体本身的审计,避免循环依赖
- 优化 ObjectMapper 配置,禁用时间戳序列化和自引用失败
This commit is contained in:
张翔
2026-04-18 13:04:26 +08:00
parent a64857fe2e
commit aedca161ec
3 changed files with 39 additions and 4 deletions
@@ -2,8 +2,12 @@ package cn.novalon.gym.manage.sys.audit;
import cn.novalon.gym.manage.sys.audit.domain.AuditLog;
import cn.novalon.gym.manage.sys.audit.service.IAuditLogService;
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
@@ -39,12 +43,17 @@ public class AuditLogAspect {
public AuditLogAspect(IAuditLogService auditLogService, ObjectMapper objectMapper) {
this.auditLogService = auditLogService;
this.objectMapper = objectMapper;
this.objectMapper = new ObjectMapper()
.registerModule(new JavaTimeModule())
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.disable(SerializationFeature.FAIL_ON_SELF_REFERENCES);
}
@Around("execution(* cn.novalon.gym.manage.db.repository.*Repository.save(..)) || " +
@Around("(execution(* cn.novalon.gym.manage.db.repository.*Repository.save(..)) || " +
"execution(* cn.novalon.gym.manage.db.repository.*Repository.delete(..)) || " +
"execution(* cn.novalon.gym.manage.db.repository.*Repository.deleteById(..))")
"execution(* cn.novalon.gym.manage.db.repository.*Repository.deleteById(..))) && " +
"!execution(* cn.novalon.gym.manage.db.repository.AuditLogRepository.*(..)) && " +
"!execution(* cn.novalon.gym.manage.db.dao.AuditLogDao.*(..))")
public Object logAuditEvent(ProceedingJoinPoint joinPoint) throws Throwable {
String methodName = joinPoint.getSignature().getName();
String className = joinPoint.getTarget().getClass().getSimpleName();
@@ -72,6 +81,12 @@ public class AuditLogAspect {
private Object handleSaveOperation(ProceedingJoinPoint joinPoint, Object entity,
String entityType, String operationType) throws Throwable {
String entityClassName = entity.getClass().getSimpleName();
if (entityClassName.contains("AuditLog") || entityClassName.contains("AuditLogEntity")) {
logger.debug("跳过审计日志实体的审计记录: {}", entityClassName);
return joinPoint.proceed();
}
try {
final String[] beforeDataHolder = {null};
final Long[] entityIdHolder = {null};
@@ -197,7 +212,7 @@ public class AuditLogAspect {
.then();
})
.onErrorResume(error -> {
logger.error("创建审计日志失败,但不影响主流程: {}", error.getMessage());
logger.error("创建审计日志失败,但不影响主流程: {}", error.getMessage(), error);
return Mono.empty();
});
}