refactor(审计日志): 优化审计日志架构和 E2E 测试质量
架构改进: - 引入审计日志服务层,实现业务逻辑与数据访问分离 - 添加 Spring Data 审计注解,自动填充创建人、创建时间等字段 - 修复切面范围,避免 Repository 和 Dao 层重复记录 代码优化: - 移除构造函数中的冗余 info 日志,降低生产环境日志量 - 恢复 SQL 文件格式,提高可读性 - 优化 E2E 测试等待策略,移除硬编码等待时间,提高测试稳定性 影响范围: - 后端:审计日志模块(Service、Repository、Aspect、Entity) - 前端:E2E 测试文件(4 个 workflow 测试) - 数据库:审计日志表结构
This commit was merged in pull request #2.
This commit is contained in:
+15
-5
@@ -1,7 +1,7 @@
|
||||
package cn.novalon.manage.sys.audit;
|
||||
|
||||
import cn.novalon.manage.sys.audit.domain.AuditLog;
|
||||
import cn.novalon.manage.sys.audit.repository.IAuditLogRepository;
|
||||
import cn.novalon.manage.sys.audit.service.IAuditLogService;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
@@ -34,11 +34,11 @@ public class AuditLogAspect {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AuditLogAspect.class);
|
||||
|
||||
private final IAuditLogRepository auditLogRepository;
|
||||
private final IAuditLogService auditLogService;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
public AuditLogAspect(IAuditLogRepository auditLogRepository, ObjectMapper objectMapper) {
|
||||
this.auditLogRepository = auditLogRepository;
|
||||
public AuditLogAspect(IAuditLogService auditLogService, ObjectMapper objectMapper) {
|
||||
this.auditLogService = auditLogService;
|
||||
this.objectMapper = objectMapper;
|
||||
}
|
||||
|
||||
@@ -99,6 +99,9 @@ public class AuditLogAspect {
|
||||
String finalOperationType = operationTypeHolder[0];
|
||||
String finalBeforeData = beforeDataHolder[0];
|
||||
|
||||
logger.debug("保存操作审计日志: entityType={}, entityIdHolder={}, extractedEntityId={}, finalEntityId={}",
|
||||
entityType, entityIdHolder[0], extractEntityId(savedEntity), finalEntityId);
|
||||
|
||||
return createAndSaveAuditLog(
|
||||
entityType, finalEntityId, finalOperationType,
|
||||
finalBeforeData, afterData, savedEntity
|
||||
@@ -163,6 +166,7 @@ public class AuditLogAspect {
|
||||
private Mono<Void> createAndSaveAuditLog(String entityType, Long entityId,
|
||||
String operationType, String beforeData,
|
||||
String afterData, Object entity) {
|
||||
logger.debug("创建审计日志: entityType={}, entityId={}, operationType={}", entityType, entityId, operationType);
|
||||
return ReactiveSecurityContextHolder.getContext()
|
||||
.map(ctx -> ctx.getAuthentication().getPrincipal())
|
||||
.defaultIfEmpty("system")
|
||||
@@ -175,6 +179,9 @@ public class AuditLogAspect {
|
||||
auditLog.setBeforeData(beforeData);
|
||||
auditLog.setAfterData(afterData);
|
||||
|
||||
logger.debug("审计日志对象: entityId={}, entityType={}, operationType={}",
|
||||
auditLog.getEntityId(), auditLog.getEntityType(), auditLog.getOperationType());
|
||||
|
||||
if (beforeData != null && afterData != null) {
|
||||
String[] changedFields = extractChangedFields(beforeData, afterData);
|
||||
auditLog.setChangedFields(changedFields);
|
||||
@@ -182,7 +189,7 @@ public class AuditLogAspect {
|
||||
|
||||
auditLog.setDescription(generateDescription(entityType, operationType, entityId));
|
||||
|
||||
return auditLogRepository.save(auditLog)
|
||||
return auditLogService.save(auditLog)
|
||||
.doOnSuccess(saved -> logger.debug("审计日志保存成功: {} - {}",
|
||||
entityType, operationType))
|
||||
.doOnError(error -> logger.error("审计日志保存失败: {}",
|
||||
@@ -231,11 +238,14 @@ public class AuditLogAspect {
|
||||
}
|
||||
|
||||
private Long extractEntityId(Object entity) {
|
||||
logger.debug("提取实体ID: entity class={}", entity.getClass().getName());
|
||||
if (entity instanceof Persistable) {
|
||||
Persistable<?> persistable = (Persistable<?>) entity;
|
||||
Object id = persistable.getId();
|
||||
logger.debug("Persistable实体ID: id={}, isNew={}", id, persistable.isNew());
|
||||
return id != null ? ((Number) id).longValue() : null;
|
||||
}
|
||||
logger.debug("实体不是Persistable类型");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
-1
@@ -49,7 +49,6 @@ public class AuditLog extends BaseDomain {
|
||||
|
||||
public AuditLog() {
|
||||
this.operationTime = LocalDateTime.now();
|
||||
this.createdAt = LocalDateTime.now();
|
||||
}
|
||||
|
||||
public String getEntityType() {
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package cn.novalon.manage.sys.audit.service;
|
||||
|
||||
import cn.novalon.manage.sys.audit.domain.AuditLog;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* 审计日志服务接口
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-04-08
|
||||
*/
|
||||
public interface IAuditLogService {
|
||||
|
||||
Mono<AuditLog> save(AuditLog auditLog);
|
||||
|
||||
Mono<AuditLog> findById(Long id);
|
||||
|
||||
Flux<AuditLog> findAll();
|
||||
|
||||
Flux<AuditLog> findByEntityType(String entityType);
|
||||
|
||||
Flux<AuditLog> findByEntityId(Long entityId);
|
||||
|
||||
Flux<AuditLog> findByEntityTypeAndEntityId(String entityType, Long entityId);
|
||||
|
||||
Flux<AuditLog> findByOperator(String operator);
|
||||
|
||||
Flux<AuditLog> findByOperationType(String operationType);
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
package cn.novalon.manage.sys.audit.service.impl;
|
||||
|
||||
import cn.novalon.manage.sys.audit.domain.AuditLog;
|
||||
import cn.novalon.manage.sys.audit.repository.IAuditLogRepository;
|
||||
import cn.novalon.manage.sys.audit.service.IAuditLogService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* 审计日志服务实现类
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-04-08
|
||||
*/
|
||||
@Service
|
||||
public class AuditLogService implements IAuditLogService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AuditLogService.class);
|
||||
|
||||
private final IAuditLogRepository auditLogRepository;
|
||||
|
||||
public AuditLogService(IAuditLogRepository auditLogRepository) {
|
||||
this.auditLogRepository = auditLogRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<AuditLog> save(AuditLog auditLog) {
|
||||
return auditLogRepository.save(auditLog);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<AuditLog> findById(Long id) {
|
||||
return auditLogRepository.findById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<AuditLog> findAll() {
|
||||
return auditLogRepository.findAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<AuditLog> findByEntityType(String entityType) {
|
||||
return auditLogRepository.findByEntityType(entityType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<AuditLog> findByEntityId(Long entityId) {
|
||||
return auditLogRepository.findByEntityId(entityId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<AuditLog> findByEntityTypeAndEntityId(String entityType, Long entityId) {
|
||||
return auditLogRepository.findByEntityTypeAndEntityId(entityType, entityId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<AuditLog> findByOperator(String operator) {
|
||||
return auditLogRepository.findByOperator(operator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<AuditLog> findByOperationType(String operationType) {
|
||||
return auditLogRepository.findByOperationType(operationType);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user