feat(audit): 增强审计日志功能
- 添加数据库迁移脚本,为 audit_log 表补充缺失字段(create_by, update_by, updated_at, deleted_at) - 改进审计日志切面,排除对审计日志实体本身的审计,避免循环依赖 - 优化 ObjectMapper 配置,禁用时间戳序列化和自引用失败
This commit is contained in:
+8
@@ -3,6 +3,8 @@ package cn.novalon.gym.manage.app.config;
|
|||||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
|
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||||
|
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
|
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
|
||||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
||||||
@@ -39,6 +41,12 @@ public class JacksonConfig {
|
|||||||
javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(formatter));
|
javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(formatter));
|
||||||
|
|
||||||
objectMapper.registerModule(javaTimeModule);
|
objectMapper.registerModule(javaTimeModule);
|
||||||
|
|
||||||
|
SimpleModule longModule = new SimpleModule();
|
||||||
|
longModule.addSerializer(Long.class, ToStringSerializer.instance);
|
||||||
|
longModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
|
||||||
|
objectMapper.registerModule(longModule);
|
||||||
|
|
||||||
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
|
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
|
||||||
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
|
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
|
||||||
|
|
||||||
|
|||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
-- Novalon管理系统审计日志表补充字段
|
||||||
|
-- 版本: V15
|
||||||
|
-- 描述: 为审计日志表添加缺失的基础字段,与BaseDomain保持一致
|
||||||
|
ALTER TABLE audit_log ADD COLUMN IF NOT EXISTS create_by VARCHAR(50);
|
||||||
|
ALTER TABLE audit_log ADD COLUMN IF NOT EXISTS update_by VARCHAR(50);
|
||||||
|
ALTER TABLE audit_log ADD COLUMN IF NOT EXISTS updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP;
|
||||||
|
ALTER TABLE audit_log ADD COLUMN IF NOT EXISTS deleted_at TIMESTAMP;
|
||||||
|
|
||||||
|
COMMENT ON COLUMN audit_log.create_by IS '创建人';
|
||||||
|
COMMENT ON COLUMN audit_log.update_by IS '更新人';
|
||||||
|
COMMENT ON COLUMN audit_log.updated_at IS '更新时间';
|
||||||
|
COMMENT ON COLUMN audit_log.deleted_at IS '删除时间';
|
||||||
+19
-4
@@ -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.domain.AuditLog;
|
||||||
import cn.novalon.gym.manage.sys.audit.service.IAuditLogService;
|
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.JsonNode;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
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.ProceedingJoinPoint;
|
||||||
import org.aspectj.lang.annotation.Around;
|
import org.aspectj.lang.annotation.Around;
|
||||||
import org.aspectj.lang.annotation.Aspect;
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
@@ -39,12 +43,17 @@ public class AuditLogAspect {
|
|||||||
|
|
||||||
public AuditLogAspect(IAuditLogService auditLogService, ObjectMapper objectMapper) {
|
public AuditLogAspect(IAuditLogService auditLogService, ObjectMapper objectMapper) {
|
||||||
this.auditLogService = auditLogService;
|
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.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 {
|
public Object logAuditEvent(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||||
String methodName = joinPoint.getSignature().getName();
|
String methodName = joinPoint.getSignature().getName();
|
||||||
String className = joinPoint.getTarget().getClass().getSimpleName();
|
String className = joinPoint.getTarget().getClass().getSimpleName();
|
||||||
@@ -72,6 +81,12 @@ public class AuditLogAspect {
|
|||||||
|
|
||||||
private Object handleSaveOperation(ProceedingJoinPoint joinPoint, Object entity,
|
private Object handleSaveOperation(ProceedingJoinPoint joinPoint, Object entity,
|
||||||
String entityType, String operationType) throws Throwable {
|
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 {
|
try {
|
||||||
final String[] beforeDataHolder = {null};
|
final String[] beforeDataHolder = {null};
|
||||||
final Long[] entityIdHolder = {null};
|
final Long[] entityIdHolder = {null};
|
||||||
@@ -197,7 +212,7 @@ public class AuditLogAspect {
|
|||||||
.then();
|
.then();
|
||||||
})
|
})
|
||||||
.onErrorResume(error -> {
|
.onErrorResume(error -> {
|
||||||
logger.error("创建审计日志失败,但不影响主流程: {}", error.getMessage());
|
logger.error("创建审计日志失败,但不影响主流程: {}", error.getMessage(), error);
|
||||||
return Mono.empty();
|
return Mono.empty();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user