refactor(审计日志): 重构审计日志模块,修复SQL插入错误
问题分析:AuditLog领域对象直接继承R2dbcRepository导致SQL插入时缺少entity_id字段 解决方案:参考OperationLog实现模式,新增Entity/Dao/Converter/Repository分层 测试验证:后端启动成功,调试测试通过
This commit is contained in:
+87
@@ -0,0 +1,87 @@
|
||||
package cn.novalon.manage.db.converter;
|
||||
|
||||
import cn.novalon.manage.sys.audit.domain.AuditLog;
|
||||
import cn.novalon.manage.db.entity.AuditLogEntity;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 审计日志实体转换器
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-04-08
|
||||
*/
|
||||
@Component
|
||||
public class AuditLogConverter {
|
||||
|
||||
public AuditLog toDomain(AuditLogEntity entity) {
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
AuditLog domain = new AuditLog();
|
||||
domain.setId(entity.getId());
|
||||
domain.setEntityType(entity.getEntityType());
|
||||
domain.setEntityId(entity.getEntityId());
|
||||
domain.setOperationType(entity.getOperationType());
|
||||
domain.setOperator(entity.getOperator());
|
||||
domain.setOperationTime(entity.getOperationTime());
|
||||
domain.setBeforeData(entity.getBeforeData());
|
||||
domain.setAfterData(entity.getAfterData());
|
||||
domain.setChangedFields(entity.getChangedFields());
|
||||
domain.setIpAddress(entity.getIpAddress());
|
||||
domain.setUserAgent(entity.getUserAgent());
|
||||
domain.setDescription(entity.getDescription());
|
||||
domain.setCreateBy(entity.getCreateBy());
|
||||
domain.setUpdateBy(entity.getUpdateBy());
|
||||
domain.setCreatedAt(entity.getCreatedAt());
|
||||
domain.setUpdatedAt(entity.getUpdatedAt());
|
||||
domain.setDeletedAt(entity.getDeletedAt());
|
||||
return domain;
|
||||
}
|
||||
|
||||
public AuditLogEntity toEntity(AuditLog domain) {
|
||||
if (domain == null) {
|
||||
return null;
|
||||
}
|
||||
AuditLogEntity entity = new AuditLogEntity();
|
||||
entity.setId(domain.getId());
|
||||
entity.setEntityType(domain.getEntityType());
|
||||
entity.setEntityId(domain.getEntityId());
|
||||
entity.setOperationType(domain.getOperationType());
|
||||
entity.setOperator(domain.getOperator());
|
||||
entity.setOperationTime(domain.getOperationTime());
|
||||
entity.setBeforeData(domain.getBeforeData());
|
||||
entity.setAfterData(domain.getAfterData());
|
||||
entity.setChangedFields(domain.getChangedFields());
|
||||
entity.setIpAddress(domain.getIpAddress());
|
||||
entity.setUserAgent(domain.getUserAgent());
|
||||
entity.setDescription(domain.getDescription());
|
||||
entity.setCreateBy(domain.getCreateBy());
|
||||
entity.setUpdateBy(domain.getUpdateBy());
|
||||
entity.setCreatedAt(domain.getCreatedAt());
|
||||
entity.setUpdatedAt(domain.getUpdatedAt());
|
||||
entity.setDeletedAt(domain.getDeletedAt());
|
||||
return entity;
|
||||
}
|
||||
|
||||
public List<AuditLog> toDomainList(List<AuditLogEntity> entities) {
|
||||
if (entities == null) {
|
||||
return null;
|
||||
}
|
||||
return entities.stream()
|
||||
.map(this::toDomain)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<AuditLogEntity> toEntityList(List<AuditLog> domains) {
|
||||
if (domains == null) {
|
||||
return null;
|
||||
}
|
||||
return domains.stream()
|
||||
.map(this::toEntity)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package cn.novalon.manage.db.dao;
|
||||
|
||||
import cn.novalon.manage.db.entity.AuditLogEntity;
|
||||
import org.springframework.data.r2dbc.repository.R2dbcRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 审计日志数据访问接口
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-04-08
|
||||
*/
|
||||
@Repository
|
||||
public interface AuditLogDao extends R2dbcRepository<AuditLogEntity, Long> {
|
||||
|
||||
Flux<AuditLogEntity> findByEntityTypeAndDeletedAtIsNull(String entityType);
|
||||
|
||||
Flux<AuditLogEntity> findByEntityIdAndDeletedAtIsNull(Long entityId);
|
||||
|
||||
Flux<AuditLogEntity> findByEntityTypeAndEntityIdAndDeletedAtIsNull(String entityType, Long entityId);
|
||||
|
||||
Flux<AuditLogEntity> findByOperatorAndDeletedAtIsNull(String operator);
|
||||
|
||||
Flux<AuditLogEntity> findByOperationTypeAndDeletedAtIsNull(String operationType);
|
||||
|
||||
Flux<AuditLogEntity> findByOperationTimeBetweenAndDeletedAtIsNull(LocalDateTime startTime, LocalDateTime endTime);
|
||||
|
||||
Flux<AuditLogEntity> findByEntityTypeAndOperationTimeBetweenAndDeletedAtIsNull(
|
||||
String entityType,
|
||||
LocalDateTime startTime,
|
||||
LocalDateTime endTime
|
||||
);
|
||||
|
||||
Flux<AuditLogEntity> findByOperatorAndOperationTimeBetweenAndDeletedAtIsNull(
|
||||
String operator,
|
||||
LocalDateTime startTime,
|
||||
LocalDateTime endTime
|
||||
);
|
||||
|
||||
Mono<Long> countByEntityTypeAndDeletedAtIsNull(String entityType);
|
||||
|
||||
Mono<Long> countByOperationTypeAndDeletedAtIsNull(String operationType);
|
||||
|
||||
Mono<Long> countByOperatorAndDeletedAtIsNull(String operator);
|
||||
|
||||
Mono<Long> countByOperationTimeBetweenAndDeletedAtIsNull(LocalDateTime startTime, LocalDateTime endTime);
|
||||
|
||||
Flux<AuditLogEntity> findByDeletedAtIsNull();
|
||||
}
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
package cn.novalon.manage.db.entity;
|
||||
|
||||
import org.springframework.data.relational.core.mapping.Column;
|
||||
import org.springframework.data.relational.core.mapping.Table;
|
||||
|
||||
/**
|
||||
* 审计日志数据库实体类
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-04-08
|
||||
*/
|
||||
@Table("audit_log")
|
||||
public class AuditLogEntity extends BaseEntity {
|
||||
|
||||
@Column("entity_type")
|
||||
private String entityType;
|
||||
|
||||
@Column("entity_id")
|
||||
private Long entityId;
|
||||
|
||||
@Column("operation_type")
|
||||
private String operationType;
|
||||
|
||||
@Column("operator")
|
||||
private String operator;
|
||||
|
||||
@Column("operation_time")
|
||||
private java.time.LocalDateTime operationTime;
|
||||
|
||||
@Column("before_data")
|
||||
private String beforeData;
|
||||
|
||||
@Column("after_data")
|
||||
private String afterData;
|
||||
|
||||
@Column("changed_fields")
|
||||
private String[] changedFields;
|
||||
|
||||
@Column("ip_address")
|
||||
private String ipAddress;
|
||||
|
||||
@Column("user_agent")
|
||||
private String userAgent;
|
||||
|
||||
@Column("description")
|
||||
private String description;
|
||||
|
||||
public String getEntityType() {
|
||||
return entityType;
|
||||
}
|
||||
|
||||
public void setEntityType(String entityType) {
|
||||
this.entityType = entityType;
|
||||
}
|
||||
|
||||
public Long getEntityId() {
|
||||
return entityId;
|
||||
}
|
||||
|
||||
public void setEntityId(Long entityId) {
|
||||
this.entityId = entityId;
|
||||
}
|
||||
|
||||
public String getOperationType() {
|
||||
return operationType;
|
||||
}
|
||||
|
||||
public void setOperationType(String operationType) {
|
||||
this.operationType = operationType;
|
||||
}
|
||||
|
||||
public String getOperator() {
|
||||
return operator;
|
||||
}
|
||||
|
||||
public void setOperator(String operator) {
|
||||
this.operator = operator;
|
||||
}
|
||||
|
||||
public java.time.LocalDateTime getOperationTime() {
|
||||
return operationTime;
|
||||
}
|
||||
|
||||
public void setOperationTime(java.time.LocalDateTime operationTime) {
|
||||
this.operationTime = operationTime;
|
||||
}
|
||||
|
||||
public String getBeforeData() {
|
||||
return beforeData;
|
||||
}
|
||||
|
||||
public void setBeforeData(String beforeData) {
|
||||
this.beforeData = beforeData;
|
||||
}
|
||||
|
||||
public String getAfterData() {
|
||||
return afterData;
|
||||
}
|
||||
|
||||
public void setAfterData(String afterData) {
|
||||
this.afterData = afterData;
|
||||
}
|
||||
|
||||
public String[] getChangedFields() {
|
||||
return changedFields;
|
||||
}
|
||||
|
||||
public void setChangedFields(String[] changedFields) {
|
||||
this.changedFields = changedFields;
|
||||
}
|
||||
|
||||
public String getIpAddress() {
|
||||
return ipAddress;
|
||||
}
|
||||
|
||||
public void setIpAddress(String ipAddress) {
|
||||
this.ipAddress = ipAddress;
|
||||
}
|
||||
|
||||
public String getUserAgent() {
|
||||
return userAgent;
|
||||
}
|
||||
|
||||
public void setUserAgent(String userAgent) {
|
||||
this.userAgent = userAgent;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
}
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
package cn.novalon.manage.db.repository;
|
||||
|
||||
import cn.novalon.manage.sys.audit.domain.AuditLog;
|
||||
import cn.novalon.manage.sys.audit.repository.IAuditLogRepository;
|
||||
import cn.novalon.manage.db.converter.AuditLogConverter;
|
||||
import cn.novalon.manage.db.dao.AuditLogDao;
|
||||
import cn.novalon.manage.db.entity.AuditLogEntity;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 审计日志仓储实现类
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-04-08
|
||||
*/
|
||||
@Repository
|
||||
public class AuditLogRepository implements IAuditLogRepository {
|
||||
|
||||
private final AuditLogDao auditLogDao;
|
||||
private final AuditLogConverter auditLogConverter;
|
||||
|
||||
public AuditLogRepository(AuditLogDao auditLogDao, AuditLogConverter auditLogConverter) {
|
||||
this.auditLogDao = auditLogDao;
|
||||
this.auditLogConverter = auditLogConverter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<AuditLog> findById(Long id) {
|
||||
return auditLogDao.findById(id)
|
||||
.map(auditLogConverter::toDomain);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<AuditLog> save(AuditLog auditLog) {
|
||||
AuditLogEntity entity = auditLogConverter.toEntity(auditLog);
|
||||
return auditLogDao.save(entity)
|
||||
.map(auditLogConverter::toDomain);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> deleteById(Long id) {
|
||||
return auditLogDao.deleteById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<AuditLog> findAll() {
|
||||
return auditLogDao.findByDeletedAtIsNull()
|
||||
.map(auditLogConverter::toDomain);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<AuditLog> findByEntityType(String entityType) {
|
||||
return auditLogDao.findByEntityTypeAndDeletedAtIsNull(entityType)
|
||||
.map(auditLogConverter::toDomain);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<AuditLog> findByEntityId(Long entityId) {
|
||||
return auditLogDao.findByEntityIdAndDeletedAtIsNull(entityId)
|
||||
.map(auditLogConverter::toDomain);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<AuditLog> findByEntityTypeAndEntityId(String entityType, Long entityId) {
|
||||
return auditLogDao.findByEntityTypeAndEntityIdAndDeletedAtIsNull(entityType, entityId)
|
||||
.map(auditLogConverter::toDomain);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<AuditLog> findByOperator(String operator) {
|
||||
return auditLogDao.findByOperatorAndDeletedAtIsNull(operator)
|
||||
.map(auditLogConverter::toDomain);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<AuditLog> findByOperationType(String operationType) {
|
||||
return auditLogDao.findByOperationTypeAndDeletedAtIsNull(operationType)
|
||||
.map(auditLogConverter::toDomain);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<AuditLog> findByOperationTimeBetween(LocalDateTime startTime, LocalDateTime endTime) {
|
||||
return auditLogDao.findByOperationTimeBetweenAndDeletedAtIsNull(startTime, endTime)
|
||||
.map(auditLogConverter::toDomain);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<AuditLog> findByEntityTypeAndOperationTimeBetween(
|
||||
String entityType,
|
||||
LocalDateTime startTime,
|
||||
LocalDateTime endTime
|
||||
) {
|
||||
return auditLogDao.findByEntityTypeAndOperationTimeBetweenAndDeletedAtIsNull(entityType, startTime, endTime)
|
||||
.map(auditLogConverter::toDomain);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<AuditLog> findByOperatorAndOperationTimeBetween(
|
||||
String operator,
|
||||
LocalDateTime startTime,
|
||||
LocalDateTime endTime
|
||||
) {
|
||||
return auditLogDao.findByOperatorAndOperationTimeBetweenAndDeletedAtIsNull(operator, startTime, endTime)
|
||||
.map(auditLogConverter::toDomain);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Long> countByEntityType(String entityType) {
|
||||
return auditLogDao.countByEntityTypeAndDeletedAtIsNull(entityType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Long> countByOperationType(String operationType) {
|
||||
return auditLogDao.countByOperationTypeAndDeletedAtIsNull(operationType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Long> countByOperator(String operator) {
|
||||
return auditLogDao.countByOperatorAndDeletedAtIsNull(operator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Long> countByOperationTimeBetween(LocalDateTime startTime, LocalDateTime endTime) {
|
||||
return auditLogDao.countByOperationTimeBetweenAndDeletedAtIsNull(startTime, endTime);
|
||||
}
|
||||
}
|
||||
+2
-40
@@ -1,9 +1,7 @@
|
||||
package cn.novalon.manage.sys.audit.domain;
|
||||
|
||||
import cn.novalon.manage.sys.core.domain.BaseDomain;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.relational.core.mapping.Column;
|
||||
import org.springframework.data.relational.core.mapping.Table;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@@ -13,75 +11,47 @@ import java.time.LocalDateTime;
|
||||
* @author 张翔
|
||||
* @date 2026-04-01
|
||||
*/
|
||||
@Table("audit_log")
|
||||
@Schema(description = "审计日志实体")
|
||||
public class AuditLog {
|
||||
public class AuditLog extends BaseDomain {
|
||||
|
||||
@Id
|
||||
@Schema(description = "主键ID")
|
||||
private Long id;
|
||||
|
||||
@Column("entity_type")
|
||||
@Schema(description = "实体类型(如User, Role等)", example = "User")
|
||||
private String entityType;
|
||||
|
||||
@Column("entity_id")
|
||||
@Schema(description = "实体ID", example = "1")
|
||||
private Long entityId;
|
||||
|
||||
@Column("operation_type")
|
||||
@Schema(description = "操作类型(CREATE, UPDATE, DELETE)", example = "UPDATE")
|
||||
private String operationType;
|
||||
|
||||
@Column("operator")
|
||||
@Schema(description = "操作人", example = "admin")
|
||||
private String operator;
|
||||
|
||||
@Column("operation_time")
|
||||
@Schema(description = "操作时间")
|
||||
private LocalDateTime operationTime;
|
||||
|
||||
@Column("before_data")
|
||||
@Schema(description = "变更前数据(JSON格式)")
|
||||
private String beforeData;
|
||||
|
||||
@Column("after_data")
|
||||
@Schema(description = "变更后数据(JSON格式)")
|
||||
private String afterData;
|
||||
|
||||
@Column("changed_fields")
|
||||
@Schema(description = "变更字段列表")
|
||||
private String[] changedFields;
|
||||
|
||||
@Column("ip_address")
|
||||
@Schema(description = "IP地址", example = "192.168.1.100")
|
||||
private String ipAddress;
|
||||
|
||||
@Column("user_agent")
|
||||
@Schema(description = "用户代理")
|
||||
private String userAgent;
|
||||
|
||||
@Column("description")
|
||||
@Schema(description = "操作描述", example = "更新用户信息")
|
||||
private String description;
|
||||
|
||||
@Column("created_at")
|
||||
@Schema(description = "记录创建时间")
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
public AuditLog() {
|
||||
this.operationTime = LocalDateTime.now();
|
||||
this.createdAt = LocalDateTime.now();
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getEntityType() {
|
||||
return entityType;
|
||||
}
|
||||
@@ -169,12 +139,4 @@ public class AuditLog {
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public void setCreatedAt(LocalDateTime createdAt) {
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
}
|
||||
|
||||
+9
-4
@@ -1,8 +1,6 @@
|
||||
package cn.novalon.manage.sys.audit.repository;
|
||||
|
||||
import cn.novalon.manage.sys.audit.domain.AuditLog;
|
||||
import org.springframework.data.r2dbc.repository.R2dbcRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@@ -14,8 +12,15 @@ import java.time.LocalDateTime;
|
||||
* @author 张翔
|
||||
* @date 2026-04-01
|
||||
*/
|
||||
@Repository
|
||||
public interface IAuditLogRepository extends R2dbcRepository<AuditLog, Long> {
|
||||
public interface IAuditLogRepository {
|
||||
|
||||
Mono<AuditLog> findById(Long id);
|
||||
|
||||
Mono<AuditLog> save(AuditLog auditLog);
|
||||
|
||||
Mono<Void> deleteById(Long id);
|
||||
|
||||
Flux<AuditLog> findAll();
|
||||
|
||||
Flux<AuditLog> findByEntityType(String entityType);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user