fix(flyway): 修复Flyway初始化问题并完善测试覆盖
- 修复数据库连接配置,确保Flyway迁移正常执行 - 完善Repository接口的查询方法,支持审计日志和操作日志查询 - 增强Service层业务逻辑,优化用户、角色、菜单等核心功能 - 补充单元测试和集成测试,确保系统稳定性 - 添加测试数据初始化脚本,支持自动化测试环境搭建 关联任务:Flyway数据库迁移优化
This commit was merged in pull request #5.
This commit is contained in:
+157
@@ -0,0 +1,157 @@
|
||||
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.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;
|
||||
import org.aspectj.lang.annotation.Before;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
|
||||
import org.springframework.stereotype.Component;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@Aspect
|
||||
@Component
|
||||
@Deprecated
|
||||
public class AuditLogAspect {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AuditLogAspect.class);
|
||||
|
||||
private final IAuditLogService auditLogService;
|
||||
|
||||
public AuditLogAspect(IAuditLogService auditLogService) {
|
||||
this.auditLogService = auditLogService;
|
||||
logger.info("=== AuditLogAspect 初始化完成 ===");
|
||||
}
|
||||
|
||||
@Before("execution(* cn.novalon.gym.manage.sys.core.service.impl.SysUserService.createUser(..))")
|
||||
public void testAopWorking() {
|
||||
logger.info("=== AuditLogAspect @Before 测试: SysUserService.createUser 被调用 ===");
|
||||
}
|
||||
|
||||
@Around("@annotation(auditable)")
|
||||
public Object logAuditEvent(ProceedingJoinPoint joinPoint, Auditable auditable) throws Throwable {
|
||||
String methodName = ((MethodSignature) joinPoint.getSignature()).getName();
|
||||
String className = joinPoint.getTarget().getClass().getSimpleName();
|
||||
String entityType = auditable.entityType();
|
||||
String operationType = auditable.operationType();
|
||||
|
||||
logger.debug("审计切面拦截: {}.{}(), entityType={}, operationType={}", className, methodName, entityType, operationType);
|
||||
|
||||
try {
|
||||
Object result = joinPoint.proceed();
|
||||
|
||||
if (result instanceof Mono) {
|
||||
return ((Mono<Object>) result).flatMap(retValue -> {
|
||||
Long entityId = extractIdFromResult(retValue);
|
||||
String afterData = serializeEntity(retValue);
|
||||
return createAndSaveAuditLog(
|
||||
entityType, entityId, operationType,
|
||||
null, afterData
|
||||
).thenReturn(retValue);
|
||||
});
|
||||
} else if (result instanceof Flux) {
|
||||
return ((Flux<Object>) result).collectList()
|
||||
.flatMapMany(list -> {
|
||||
String afterData = serializeEntity(list);
|
||||
return createAndSaveAuditLog(
|
||||
entityType, null, operationType,
|
||||
null, afterData
|
||||
).thenMany(Flux.fromIterable(list));
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (Throwable error) {
|
||||
logger.error("审计日志记录失败: {}.{}()", className, methodName, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
private Mono<Void> createAndSaveAuditLog(String entityType, Long entityId,
|
||||
String operationType, String beforeData,
|
||||
String afterData) {
|
||||
logger.debug("创建审计日志: entityType={}, entityId={}, operationType={}", entityType, entityId, operationType);
|
||||
|
||||
return ReactiveSecurityContextHolder.getContext()
|
||||
.map(ctx -> ctx.getAuthentication().getPrincipal())
|
||||
.defaultIfEmpty("system")
|
||||
.flatMap(principal -> {
|
||||
AuditLog auditLog = new AuditLog();
|
||||
auditLog.setEntityType(entityType);
|
||||
auditLog.setEntityId(entityId != null ? entityId : 0L);
|
||||
auditLog.setOperationType(operationType);
|
||||
auditLog.setOperator(principal instanceof String ? (String) principal : "system");
|
||||
auditLog.setBeforeData(beforeData);
|
||||
auditLog.setAfterData(afterData);
|
||||
auditLog.setDescription(generateDescription(entityType, operationType, entityId));
|
||||
|
||||
return auditLogService.saveAsync(auditLog)
|
||||
.doOnSuccess(saved -> logger.debug("审计日志保存成功: {} - {}, ID={}",
|
||||
entityType, operationType, saved.getId()))
|
||||
.doOnError(error -> logger.error("审计日志保存失败: {}", error.getMessage()))
|
||||
.then();
|
||||
})
|
||||
.onErrorResume(error -> {
|
||||
logger.error("创建审计日志失败,但不影响主流程: {}", error.getMessage(), error);
|
||||
return Mono.empty();
|
||||
});
|
||||
}
|
||||
|
||||
private Long extractIdFromResult(Object result) {
|
||||
if (result == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
var getIdMethod = result.getClass().getMethod("getId");
|
||||
Object id = getIdMethod.invoke(result);
|
||||
if (id instanceof Number) {
|
||||
return ((Number) id).longValue();
|
||||
}
|
||||
if (id instanceof String) {
|
||||
try {
|
||||
return Long.parseLong((String) id);
|
||||
} catch (NumberFormatException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
logger.debug("结果对象没有getId方法: {}", result.getClass().getSimpleName());
|
||||
} catch (Exception e) {
|
||||
logger.debug("提取结果ID失败: {}", e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String serializeEntity(Object entity) {
|
||||
try {
|
||||
ObjectMapper mapper = new ObjectMapper()
|
||||
.registerModule(new JavaTimeModule())
|
||||
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
|
||||
.disable(SerializationFeature.FAIL_ON_SELF_REFERENCES);
|
||||
return mapper.writeValueAsString(entity);
|
||||
} catch (Exception e) {
|
||||
logger.error("序列化实体失败: {}", e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String generateDescription(String entityType, String operationType, Long entityId) {
|
||||
String operation = switch (operationType) {
|
||||
case "CREATE" -> "创建";
|
||||
case "UPDATE" -> "更新";
|
||||
case "DELETE" -> "删除";
|
||||
default -> "操作";
|
||||
};
|
||||
|
||||
return String.format("%s%s (ID: %s)", operation, entityType,
|
||||
entityId != null ? entityId : "未知");
|
||||
}
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
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.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public final class AuditLogHelper {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AuditLogHelper.class);
|
||||
private static final ObjectMapper objectMapper = new ObjectMapper()
|
||||
.registerModule(new JavaTimeModule())
|
||||
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
|
||||
.disable(SerializationFeature.FAIL_ON_SELF_REFERENCES);
|
||||
|
||||
private AuditLogHelper() {}
|
||||
|
||||
public static Mono<Void> record(IAuditLogService auditLogService,
|
||||
String entityType, Long entityId,
|
||||
String operationType, Object afterEntity) {
|
||||
return record(auditLogService, entityType, entityId, operationType, null, afterEntity);
|
||||
}
|
||||
|
||||
public static Mono<Void> record(IAuditLogService auditLogService,
|
||||
String entityType, Long entityId,
|
||||
String operationType, Object beforeEntity, Object afterEntity) {
|
||||
return ReactiveSecurityContextHolder.getContext()
|
||||
.map(ctx -> ctx.getAuthentication().getPrincipal())
|
||||
.defaultIfEmpty("system")
|
||||
.flatMap(principal -> {
|
||||
AuditLog auditLog = new AuditLog();
|
||||
auditLog.generateId();
|
||||
auditLog.setEntityType(entityType);
|
||||
auditLog.setEntityId(entityId != null ? entityId : 0L);
|
||||
auditLog.setOperationType(operationType);
|
||||
auditLog.setOperator(principal instanceof String ? (String) principal : "system");
|
||||
auditLog.setBeforeData(serializeEntity(beforeEntity));
|
||||
auditLog.setAfterData(serializeEntity(afterEntity));
|
||||
auditLog.setDescription(generateDescription(entityType, operationType, entityId));
|
||||
|
||||
logger.info("记录审计日志: {} {} ID={}, operator={}", operationType, entityType, entityId, auditLog.getOperator());
|
||||
|
||||
return auditLogService.saveAsync(auditLog)
|
||||
.doOnSuccess(saved -> logger.info("审计日志保存成功: {} - {}, ID={}",
|
||||
entityType, operationType, saved.getId()))
|
||||
.doOnError(error -> logger.error("审计日志保存失败: {}", error.getMessage()))
|
||||
.then();
|
||||
})
|
||||
.onErrorResume(error -> {
|
||||
logger.error("记录审计日志失败,但不影响主流程: {}", error.getMessage(), error);
|
||||
return Mono.empty();
|
||||
});
|
||||
}
|
||||
|
||||
private static String serializeEntity(Object entity) {
|
||||
try {
|
||||
if (entity == null) return null;
|
||||
return objectMapper.writeValueAsString(entity);
|
||||
} catch (Exception e) {
|
||||
logger.error("序列化实体失败: {}", e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static String generateDescription(String entityType, String operationType, Long entityId) {
|
||||
String operation = switch (operationType) {
|
||||
case "CREATE" -> "创建";
|
||||
case "UPDATE" -> "更新";
|
||||
case "DELETE" -> "删除";
|
||||
default -> "操作";
|
||||
};
|
||||
return String.format("%s%s (ID: %s)", operation, entityType,
|
||||
entityId != null ? entityId : "未知");
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package cn.novalon.gym.manage.sys.audit;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface Auditable {
|
||||
|
||||
String entityType();
|
||||
|
||||
String operationType() default "CREATE";
|
||||
|
||||
String description() default "";
|
||||
}
|
||||
+2
@@ -24,6 +24,8 @@ public interface ISysMenuRepository {
|
||||
|
||||
Mono<SysMenu> save(SysMenu sysMenu);
|
||||
|
||||
Mono<SysMenu> update(SysMenu sysMenu);
|
||||
|
||||
Mono<Void> deleteById(Long id);
|
||||
|
||||
Flux<SysMenu> findAll();
|
||||
|
||||
+2
@@ -28,6 +28,8 @@ public interface ISysUserRepository {
|
||||
|
||||
Mono<SysUser> save(SysUser sysUser);
|
||||
|
||||
Mono<SysUser> update(SysUser sysUser);
|
||||
|
||||
Mono<Void> deleteById(Long id);
|
||||
|
||||
Flux<SysUser> findAll();
|
||||
|
||||
-2
@@ -48,13 +48,11 @@ public class DictionaryService implements IDictionaryService {
|
||||
@Override
|
||||
public Mono<Dictionary> save(Dictionary dictionary) {
|
||||
if (dictionary.getId() == null) {
|
||||
dictionary.setCreatedAt(LocalDateTime.now());
|
||||
return checkTypeAndCodeExists(dictionary.getType(), dictionary.getCode())
|
||||
.flatMap(exists -> {
|
||||
if (exists) {
|
||||
return Mono.error(new DictionaryAlreadyExistsException(dictionary.getType(), dictionary.getCode()));
|
||||
}
|
||||
dictionary.setUpdatedAt(LocalDateTime.now());
|
||||
return repository.save(dictionary);
|
||||
});
|
||||
}
|
||||
|
||||
+12
-13
@@ -1,5 +1,7 @@
|
||||
package cn.novalon.gym.manage.sys.core.service.impl;
|
||||
|
||||
import cn.novalon.gym.manage.sys.audit.AuditLogHelper;
|
||||
import cn.novalon.gym.manage.sys.audit.service.IAuditLogService;
|
||||
import cn.novalon.gym.manage.sys.core.domain.SysConfig;
|
||||
import cn.novalon.gym.manage.sys.core.repository.ISysConfigRepository;
|
||||
import cn.novalon.gym.manage.sys.core.service.ISysConfigService;
|
||||
@@ -7,19 +9,15 @@ import org.springframework.stereotype.Service;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* 系统配置服务实现类
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-14
|
||||
*/
|
||||
@Service
|
||||
public class SysConfigService implements ISysConfigService {
|
||||
|
||||
private final ISysConfigRepository repository;
|
||||
private final IAuditLogService auditLogService;
|
||||
|
||||
public SysConfigService(ISysConfigRepository repository) {
|
||||
public SysConfigService(ISysConfigRepository repository, IAuditLogService auditLogService) {
|
||||
this.repository = repository;
|
||||
this.auditLogService = auditLogService;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -28,27 +26,28 @@ public class SysConfigService implements ISysConfigService {
|
||||
}
|
||||
|
||||
@Override
|
||||
// @Cacheable(value = "sysConfig", key = "#id")
|
||||
public Mono<SysConfig> findById(Long id) {
|
||||
return repository.findById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
// @Cacheable(value = "sysConfig", key = "#configKey")
|
||||
public Mono<SysConfig> findByConfigKey(String configKey) {
|
||||
return repository.findByConfigKeyAndDeletedAtIsNull(configKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
// @CacheEvict(value = "sysConfig", allEntries = true)
|
||||
public Mono<SysConfig> save(SysConfig config) {
|
||||
return repository.save(config);
|
||||
return repository.save(config)
|
||||
.flatMap(saved -> AuditLogHelper.record(auditLogService, "Config", saved.getId(), "CREATE", saved)
|
||||
.thenReturn(saved));
|
||||
}
|
||||
|
||||
@Override
|
||||
// @CacheEvict(value = "sysConfig", key = "#id")
|
||||
public Mono<Void> deleteById(Long id) {
|
||||
return repository.deleteByIdAndDeletedAtIsNull(id);
|
||||
return repository.findById(id)
|
||||
.flatMap(config -> repository.deleteByIdAndDeletedAtIsNull(id)
|
||||
.then(AuditLogHelper.record(auditLogService, "Config", id, "DELETE", config, null)))
|
||||
.then();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+12
-9
@@ -1,5 +1,7 @@
|
||||
package cn.novalon.gym.manage.sys.core.service.impl;
|
||||
|
||||
import cn.novalon.gym.manage.sys.audit.AuditLogHelper;
|
||||
import cn.novalon.gym.manage.sys.audit.service.IAuditLogService;
|
||||
import cn.novalon.gym.manage.sys.core.domain.SysDictType;
|
||||
import cn.novalon.gym.manage.sys.core.repository.ISysDictTypeRepository;
|
||||
import cn.novalon.gym.manage.sys.core.service.ISysDictTypeService;
|
||||
@@ -7,19 +9,15 @@ import org.springframework.stereotype.Service;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* 字典类型服务实现类
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-14
|
||||
*/
|
||||
@Service
|
||||
public class SysDictTypeService implements ISysDictTypeService {
|
||||
|
||||
private final ISysDictTypeRepository repository;
|
||||
private final IAuditLogService auditLogService;
|
||||
|
||||
public SysDictTypeService(ISysDictTypeRepository repository) {
|
||||
public SysDictTypeService(ISysDictTypeRepository repository, IAuditLogService auditLogService) {
|
||||
this.repository = repository;
|
||||
this.auditLogService = auditLogService;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -39,11 +37,16 @@ public class SysDictTypeService implements ISysDictTypeService {
|
||||
|
||||
@Override
|
||||
public Mono<SysDictType> save(SysDictType dictType) {
|
||||
return repository.save(dictType);
|
||||
return repository.save(dictType)
|
||||
.flatMap(saved -> AuditLogHelper.record(auditLogService, "Dict", saved.getId(), "CREATE", saved)
|
||||
.thenReturn(saved));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> deleteById(Long id) {
|
||||
return repository.deleteByIdAndDeletedAtIsNull(id);
|
||||
return repository.findById(id)
|
||||
.flatMap(dict -> repository.deleteByIdAndDeletedAtIsNull(id)
|
||||
.then(AuditLogHelper.record(auditLogService, "Dict", id, "DELETE", dict, null)))
|
||||
.then();
|
||||
}
|
||||
}
|
||||
|
||||
+31
-8
@@ -6,6 +6,8 @@ import cn.novalon.gym.manage.sys.core.service.ISysMenuService;
|
||||
import cn.novalon.gym.manage.sys.core.command.CreateMenuCommand;
|
||||
import cn.novalon.gym.manage.sys.core.command.UpdateMenuCommand;
|
||||
import cn.novalon.gym.manage.common.util.StatusConstants;
|
||||
import cn.novalon.gym.manage.sys.audit.AuditLogHelper;
|
||||
import cn.novalon.gym.manage.sys.audit.service.IAuditLogService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
@@ -24,9 +26,11 @@ import java.util.stream.Collectors;
|
||||
public class SysMenuService implements ISysMenuService {
|
||||
|
||||
private final ISysMenuRepository menuRepository;
|
||||
private final IAuditLogService auditLogService;
|
||||
|
||||
public SysMenuService(ISysMenuRepository menuRepository) {
|
||||
public SysMenuService(ISysMenuRepository menuRepository, IAuditLogService auditLogService) {
|
||||
this.menuRepository = menuRepository;
|
||||
this.auditLogService = auditLogService;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -46,8 +50,9 @@ public class SysMenuService implements ISysMenuService {
|
||||
|
||||
@Override
|
||||
public Mono<SysMenu> createMenu(SysMenu menu) {
|
||||
menu.setCreatedAt(LocalDateTime.now());
|
||||
return menuRepository.save(menu);
|
||||
return menuRepository.save(menu)
|
||||
.flatMap(saved -> AuditLogHelper.record(auditLogService, "Menu", saved.getId(), "CREATE", saved)
|
||||
.thenReturn(saved));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -60,14 +65,18 @@ public class SysMenuService implements ISysMenuService {
|
||||
menu.setComponent(command.component());
|
||||
menu.setPerms(command.perms());
|
||||
menu.setStatus(command.status() != null ? command.status() : StatusConstants.ENABLED);
|
||||
menu.setCreatedAt(LocalDateTime.now());
|
||||
return menuRepository.save(menu);
|
||||
return menuRepository.save(menu)
|
||||
.flatMap(saved -> AuditLogHelper.record(auditLogService, "Menu", saved.getId(), "CREATE", saved)
|
||||
.thenReturn(saved));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SysMenu> updateMenu(SysMenu menu) {
|
||||
menu.setUpdatedAt(LocalDateTime.now());
|
||||
return menuRepository.save(menu);
|
||||
return menuRepository.findById(menu.getId())
|
||||
.flatMap(before -> menuRepository.update(menu)
|
||||
.flatMap(saved -> AuditLogHelper.record(auditLogService, "Menu", saved.getId(), "UPDATE", before, saved)
|
||||
.thenReturn(saved)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -75,6 +84,15 @@ public class SysMenuService implements ISysMenuService {
|
||||
return menuRepository.findById(command.id())
|
||||
.switchIfEmpty(Mono.error(new RuntimeException("Menu not found")))
|
||||
.flatMap(menu -> {
|
||||
SysMenu before = new SysMenu();
|
||||
before.setId(menu.getId());
|
||||
before.setParentId(menu.getParentId());
|
||||
before.setMenuName(menu.getMenuName());
|
||||
before.setMenuType(menu.getMenuType());
|
||||
before.setOrderNum(menu.getOrderNum());
|
||||
before.setComponent(menu.getComponent());
|
||||
before.setPerms(menu.getPerms());
|
||||
before.setStatus(menu.getStatus());
|
||||
if (command.parentId() != null) {
|
||||
menu.setParentId(command.parentId());
|
||||
}
|
||||
@@ -97,13 +115,18 @@ public class SysMenuService implements ISysMenuService {
|
||||
menu.setStatus(command.status());
|
||||
}
|
||||
menu.setUpdatedAt(LocalDateTime.now());
|
||||
return menuRepository.save(menu);
|
||||
return menuRepository.update(menu)
|
||||
.flatMap(saved -> AuditLogHelper.record(auditLogService, "Menu", saved.getId(), "UPDATE", before, saved)
|
||||
.thenReturn(saved));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> deleteMenu(Long id) {
|
||||
return menuRepository.deleteById(id);
|
||||
return menuRepository.findById(id)
|
||||
.flatMap(menu -> menuRepository.deleteById(id)
|
||||
.then(AuditLogHelper.record(auditLogService, "Menu", id, "DELETE", menu, null)))
|
||||
.then();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+29
-5
@@ -1,11 +1,15 @@
|
||||
package cn.novalon.gym.manage.sys.core.service.impl;
|
||||
|
||||
import cn.novalon.gym.manage.common.util.StatusConstants;
|
||||
import cn.novalon.gym.manage.sys.audit.AuditLogHelper;
|
||||
import cn.novalon.gym.manage.sys.audit.service.IAuditLogService;
|
||||
import cn.novalon.gym.manage.sys.core.domain.SysPermission;
|
||||
import cn.novalon.gym.manage.sys.core.domain.SysRolePermission;
|
||||
import cn.novalon.gym.manage.sys.core.repository.ISysPermissionRepository;
|
||||
import cn.novalon.gym.manage.sys.core.repository.ISysRolePermissionRepository;
|
||||
import cn.novalon.gym.manage.sys.core.service.ISysPermissionService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -24,13 +28,18 @@ import java.util.List;
|
||||
@Service
|
||||
public class SysPermissionService implements ISysPermissionService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SysPermissionService.class);
|
||||
|
||||
private final ISysPermissionRepository permissionRepository;
|
||||
private final ISysRolePermissionRepository rolePermissionRepository;
|
||||
private final IAuditLogService auditLogService;
|
||||
|
||||
public SysPermissionService(ISysPermissionRepository permissionRepository,
|
||||
ISysRolePermissionRepository rolePermissionRepository) {
|
||||
ISysRolePermissionRepository rolePermissionRepository,
|
||||
IAuditLogService auditLogService) {
|
||||
this.permissionRepository = permissionRepository;
|
||||
this.rolePermissionRepository = rolePermissionRepository;
|
||||
this.auditLogService = auditLogService;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -60,25 +69,41 @@ public class SysPermissionService implements ISysPermissionService {
|
||||
|
||||
@Override
|
||||
public Mono<SysPermission> createPermission(SysPermission permission) {
|
||||
permission.setCreatedAt(LocalDateTime.now());
|
||||
if (permission.getStatus() == null) {
|
||||
permission.setStatus(StatusConstants.ENABLED);
|
||||
}
|
||||
return permissionRepository.save(permission);
|
||||
return permissionRepository.save(permission)
|
||||
.flatMap(saved -> AuditLogHelper.record(auditLogService, "Permission", saved.getId(), "CREATE", saved)
|
||||
.doOnError(e -> logger.error("Audit log failed for Permission CREATE id={}: {}", saved.getId(), e.getMessage()))
|
||||
.thenReturn(saved));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SysPermission> updatePermission(SysPermission permission) {
|
||||
permission.setUpdatedAt(LocalDateTime.now());
|
||||
return permissionRepository.updatePermission(permission);
|
||||
return permissionRepository.findById(permission.getId())
|
||||
.flatMap(before -> permissionRepository.updatePermission(permission)
|
||||
.flatMap(saved -> AuditLogHelper.record(auditLogService, "Permission", saved.getId(), "UPDATE", before, saved)
|
||||
.thenReturn(saved)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> deletePermission(Long id) {
|
||||
return permissionRepository.findById(id)
|
||||
.flatMap(permission -> {
|
||||
SysPermission before = new SysPermission();
|
||||
before.setId(permission.getId());
|
||||
before.setPermissionName(permission.getPermissionName());
|
||||
before.setPermissionCode(permission.getPermissionCode());
|
||||
before.setResource(permission.getResource());
|
||||
before.setAction(permission.getAction());
|
||||
before.setStatus(permission.getStatus());
|
||||
before.setCreatedAt(permission.getCreatedAt());
|
||||
before.setUpdatedAt(permission.getUpdatedAt());
|
||||
before.setDeletedAt(permission.getDeletedAt());
|
||||
permission.delete();
|
||||
return permissionRepository.updatePermission(permission)
|
||||
.flatMap(saved -> AuditLogHelper.record(auditLogService, "Permission", id, "DELETE", before, saved))
|
||||
.then(rolePermissionRepository.deleteByPermissionId(id));
|
||||
});
|
||||
}
|
||||
@@ -107,7 +132,6 @@ public class SysPermissionService implements ISysPermissionService {
|
||||
SysRolePermission rolePermission = new SysRolePermission();
|
||||
rolePermission.setRoleId(roleId);
|
||||
rolePermission.setPermissionId(permissionId);
|
||||
rolePermission.setCreatedAt(LocalDateTime.now());
|
||||
return rolePermissionRepository.save(rolePermission);
|
||||
})
|
||||
.then());
|
||||
|
||||
+43
-14
@@ -1,6 +1,8 @@
|
||||
package cn.novalon.gym.manage.sys.core.service.impl;
|
||||
|
||||
import cn.novalon.gym.manage.common.util.StatusConstants;
|
||||
import cn.novalon.gym.manage.sys.audit.AuditLogHelper;
|
||||
import cn.novalon.gym.manage.sys.audit.service.IAuditLogService;
|
||||
import cn.novalon.gym.manage.sys.core.domain.SysRole;
|
||||
import cn.novalon.gym.manage.sys.core.query.SysRoleQuery;
|
||||
import cn.novalon.gym.manage.sys.core.repository.ISysRoleRepository;
|
||||
@@ -21,12 +23,6 @@ import reactor.core.publisher.Mono;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 系统角色服务实现类
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-14
|
||||
*/
|
||||
@Service
|
||||
public class SysRoleService implements ISysRoleService {
|
||||
|
||||
@@ -35,13 +31,16 @@ public class SysRoleService implements ISysRoleService {
|
||||
private final ISysUserService userService;
|
||||
private final IUserRoleRepository userRoleRepository;
|
||||
private final ISysRolePermissionRepository rolePermissionRepository;
|
||||
private final IAuditLogService auditLogService;
|
||||
|
||||
public SysRoleService(ISysRoleRepository roleRepository, ISysUserService userService,
|
||||
IUserRoleRepository userRoleRepository, ISysRolePermissionRepository rolePermissionRepository) {
|
||||
IUserRoleRepository userRoleRepository, ISysRolePermissionRepository rolePermissionRepository,
|
||||
IAuditLogService auditLogService) {
|
||||
this.roleRepository = roleRepository;
|
||||
this.userService = userService;
|
||||
this.userRoleRepository = userRoleRepository;
|
||||
this.rolePermissionRepository = rolePermissionRepository;
|
||||
this.auditLogService = auditLogService;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -76,7 +75,9 @@ public class SysRoleService implements ISysRoleService {
|
||||
if (role.getStatus() == null) {
|
||||
role.setStatus(StatusConstants.ENABLED);
|
||||
}
|
||||
return roleRepository.save(role);
|
||||
return roleRepository.save(role)
|
||||
.flatMap(saved -> AuditLogHelper.record(auditLogService, "Role", saved.getId(), "CREATE", saved)
|
||||
.thenReturn(saved));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -88,13 +89,18 @@ public class SysRoleService implements ISysRoleService {
|
||||
role.setRoleSort(command.roleSort());
|
||||
role.setStatus(command.status() != null ? command.status() : StatusConstants.ENABLED);
|
||||
role.setCreatedAt(LocalDateTime.now());
|
||||
return roleRepository.save(role);
|
||||
return roleRepository.save(role)
|
||||
.flatMap(saved -> AuditLogHelper.record(auditLogService, "Role", saved.getId(), "CREATE", saved)
|
||||
.thenReturn(saved));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SysRole> updateRole(SysRole role) {
|
||||
role.setUpdatedAt(LocalDateTime.now());
|
||||
return roleRepository.save(role);
|
||||
return roleRepository.findById(role.getId())
|
||||
.flatMap(before -> roleRepository.updateRole(role)
|
||||
.flatMap(saved -> AuditLogHelper.record(auditLogService, "Role", saved.getId(), "UPDATE", before, saved)
|
||||
.thenReturn(saved)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -102,6 +108,15 @@ public class SysRoleService implements ISysRoleService {
|
||||
return roleRepository.findById(command.id())
|
||||
.switchIfEmpty(Mono.error(new RuntimeException("Role not found")))
|
||||
.flatMap(role -> {
|
||||
SysRole before = new SysRole();
|
||||
before.setId(role.getId());
|
||||
before.setRoleName(role.getRoleName());
|
||||
before.setRoleKey(role.getRoleKey());
|
||||
before.setRoleSort(role.getRoleSort());
|
||||
before.setStatus(role.getStatus());
|
||||
before.setCreatedAt(role.getCreatedAt());
|
||||
before.setUpdatedAt(role.getUpdatedAt());
|
||||
before.setDeletedAt(role.getDeletedAt());
|
||||
if (command.roleName() != null) {
|
||||
role.setRoleName(command.roleName());
|
||||
}
|
||||
@@ -115,7 +130,9 @@ public class SysRoleService implements ISysRoleService {
|
||||
role.setStatus(command.status());
|
||||
}
|
||||
role.setUpdatedAt(LocalDateTime.now());
|
||||
return roleRepository.save(role);
|
||||
return roleRepository.updateRole(role)
|
||||
.flatMap(saved -> AuditLogHelper.record(auditLogService, "Role", saved.getId(), "UPDATE", before, saved)
|
||||
.thenReturn(saved));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -123,7 +140,7 @@ public class SysRoleService implements ISysRoleService {
|
||||
@Transactional(transactionManager = "connectionFactoryTransactionManager")
|
||||
public Mono<Void> deleteRole(Long id) {
|
||||
logger.debug("开始删除角色,ID: {}", id);
|
||||
|
||||
|
||||
return roleRepository.findById(id)
|
||||
.flatMap(role -> {
|
||||
logger.debug("找到角色,开始删除关联记录");
|
||||
@@ -138,7 +155,8 @@ public class SysRoleService implements ISysRoleService {
|
||||
.doOnError(e -> logger.error("更新用户角色ID失败", e))
|
||||
.then(roleRepository.deleteById(id))
|
||||
.doOnSuccess(v -> logger.debug("成功删除角色"))
|
||||
.doOnError(e -> logger.error("删除角色失败", e));
|
||||
.doOnError(e -> logger.error("删除角色失败", e))
|
||||
.then(AuditLogHelper.record(auditLogService, "Role", id, "DELETE", role, null));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -156,8 +174,19 @@ public class SysRoleService implements ISysRoleService {
|
||||
public Mono<SysRole> logicalDeleteRole(Long id) {
|
||||
return roleRepository.findByIdIncludingDeleted(id)
|
||||
.flatMap(role -> {
|
||||
SysRole before = new SysRole();
|
||||
before.setId(role.getId());
|
||||
before.setRoleName(role.getRoleName());
|
||||
before.setRoleKey(role.getRoleKey());
|
||||
before.setRoleSort(role.getRoleSort());
|
||||
before.setStatus(role.getStatus());
|
||||
before.setCreatedAt(role.getCreatedAt());
|
||||
before.setUpdatedAt(role.getUpdatedAt());
|
||||
before.setDeletedAt(role.getDeletedAt());
|
||||
role.delete();
|
||||
return roleRepository.updateRole(role);
|
||||
return roleRepository.updateRole(role)
|
||||
.flatMap(saved -> AuditLogHelper.record(auditLogService, "Role", saved.getId(), "DELETE", before, saved)
|
||||
.thenReturn(saved));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+54
-21
@@ -1,6 +1,8 @@
|
||||
package cn.novalon.gym.manage.sys.core.service.impl;
|
||||
|
||||
import cn.novalon.gym.manage.common.util.StatusConstants;
|
||||
import cn.novalon.gym.manage.sys.audit.AuditLogHelper;
|
||||
import cn.novalon.gym.manage.sys.audit.service.IAuditLogService;
|
||||
import cn.novalon.gym.manage.sys.core.domain.SysUser;
|
||||
import cn.novalon.gym.manage.sys.core.domain.SysRole;
|
||||
import cn.novalon.gym.manage.sys.core.domain.UserRole;
|
||||
@@ -26,16 +28,6 @@ import reactor.core.publisher.Mono;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户服务实现类
|
||||
*
|
||||
* 文件定义:实现用户管理的核心业务逻辑
|
||||
* 涉及业务:用户注册、登录、信息修改、删除、密码修改、逻辑删除等用户生命周期管理
|
||||
* 算法:使用R2DBC进行响应式数据库操作,支持分页查询、条件查询、批量操作
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
@Service
|
||||
public class SysUserService implements ISysUserService {
|
||||
|
||||
@@ -44,15 +36,18 @@ public class SysUserService implements ISysUserService {
|
||||
private final ISysRoleRepository roleRepository;
|
||||
private final IUserRoleRepository userRoleRepository;
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
private final IAuditLogService auditLogService;
|
||||
|
||||
public SysUserService(ISysUserRepository userRepository,
|
||||
ISysRoleRepository roleRepository,
|
||||
IUserRoleRepository userRoleRepository,
|
||||
@Qualifier("passwordEncoder") PasswordEncoder passwordEncoder) {
|
||||
@Qualifier("passwordEncoder") PasswordEncoder passwordEncoder,
|
||||
IAuditLogService auditLogService) {
|
||||
this.userRepository = userRepository;
|
||||
this.roleRepository = roleRepository;
|
||||
this.userRoleRepository = userRoleRepository;
|
||||
this.passwordEncoder = passwordEncoder;
|
||||
this.auditLogService = auditLogService;
|
||||
|
||||
logger.info("使用的密码编码器类型: {}", passwordEncoder.getClass().getName());
|
||||
}
|
||||
@@ -113,7 +108,9 @@ public class SysUserService implements ISysUserService {
|
||||
if (user.getStatus() == null) {
|
||||
user.setStatus(StatusConstants.ENABLED);
|
||||
}
|
||||
return userRepository.save(user);
|
||||
return userRepository.save(user)
|
||||
.flatMap(saved -> AuditLogHelper.record(auditLogService, "User", saved.getId(), "CREATE", saved)
|
||||
.thenReturn(saved));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -127,13 +124,18 @@ public class SysUserService implements ISysUserService {
|
||||
user.setPhone(command.phone());
|
||||
user.setRoleId(command.roleId());
|
||||
user.setStatus(command.status() != null ? command.status() : StatusConstants.ENABLED);
|
||||
return userRepository.save(user);
|
||||
return userRepository.save(user)
|
||||
.flatMap(saved -> AuditLogHelper.record(auditLogService, "User", saved.getId(), "CREATE", saved)
|
||||
.thenReturn(saved));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SysUser> updateUser(SysUser user) {
|
||||
user.setUpdatedAt(LocalDateTime.now());
|
||||
return userRepository.save(user);
|
||||
return userRepository.findById(user.getId())
|
||||
.flatMap(before -> userRepository.update(user)
|
||||
.flatMap(saved -> AuditLogHelper.record(auditLogService, "User", saved.getId(), "UPDATE", before, saved)
|
||||
.thenReturn(saved)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -141,6 +143,17 @@ public class SysUserService implements ISysUserService {
|
||||
return userRepository.findById(command.id())
|
||||
.switchIfEmpty(Mono.error(new RuntimeException("User not found")))
|
||||
.flatMap(user -> {
|
||||
SysUser before = new SysUser();
|
||||
before.setId(user.getId());
|
||||
before.setUsername(user.getUsername());
|
||||
before.setEmail(user.getEmail());
|
||||
before.setNickname(user.getNickname());
|
||||
before.setPhone(user.getPhone());
|
||||
before.setRoleId(user.getRoleId());
|
||||
before.setStatus(user.getStatus());
|
||||
before.setCreatedAt(user.getCreatedAt());
|
||||
before.setUpdatedAt(user.getUpdatedAt());
|
||||
before.setDeletedAt(user.getDeletedAt());
|
||||
if (command.username() != null) {
|
||||
user.setUsername(command.username());
|
||||
}
|
||||
@@ -159,7 +172,10 @@ public class SysUserService implements ISysUserService {
|
||||
user.setStatus(command.status());
|
||||
}
|
||||
user.setUpdatedAt(LocalDateTime.now());
|
||||
return userRepository.save(user);
|
||||
return userRepository.update(user)
|
||||
.flatMap(saved -> AuditLogHelper
|
||||
.record(auditLogService, "User", saved.getId(), "UPDATE", before, saved)
|
||||
.thenReturn(saved));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -177,7 +193,8 @@ public class SysUserService implements ISysUserService {
|
||||
.doOnError(e -> logger.error("删除用户角色关联记录失败", e))
|
||||
.then(userRepository.deleteById(id))
|
||||
.doOnSuccess(v -> logger.debug("成功删除用户"))
|
||||
.doOnError(e -> logger.error("删除用户失败", e));
|
||||
.doOnError(e -> logger.error("删除用户失败", e))
|
||||
.then(AuditLogHelper.record(auditLogService, "User", id, "DELETE", user, null));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -195,7 +212,10 @@ public class SysUserService implements ISysUserService {
|
||||
}
|
||||
user.setPassword(passwordEncoder.encode(newPassword));
|
||||
user.setUpdatedAt(LocalDateTime.now());
|
||||
return userRepository.save(user);
|
||||
return userRepository.update(user)
|
||||
.flatMap(saved -> AuditLogHelper
|
||||
.record(auditLogService, "User", saved.getId(), "UPDATE", saved)
|
||||
.thenReturn(saved));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -217,8 +237,20 @@ public class SysUserService implements ISysUserService {
|
||||
public Mono<Void> logicalDeleteUser(Long id) {
|
||||
return userRepository.findByIdIncludingDeleted(id)
|
||||
.flatMap(user -> {
|
||||
SysUser before = new SysUser();
|
||||
before.setId(user.getId());
|
||||
before.setUsername(user.getUsername());
|
||||
before.setEmail(user.getEmail());
|
||||
before.setNickname(user.getNickname());
|
||||
before.setPhone(user.getPhone());
|
||||
before.setRoleId(user.getRoleId());
|
||||
before.setStatus(user.getStatus());
|
||||
before.setCreatedAt(user.getCreatedAt());
|
||||
before.setUpdatedAt(user.getUpdatedAt());
|
||||
before.setDeletedAt(user.getDeletedAt());
|
||||
user.setDeletedAt(LocalDateTime.now());
|
||||
return userRepository.save(user);
|
||||
return userRepository.save(user)
|
||||
.flatMap(saved -> AuditLogHelper.record(auditLogService, "User", saved.getId(), "DELETE", before, saved));
|
||||
})
|
||||
.then();
|
||||
}
|
||||
@@ -252,7 +284,8 @@ public class SysUserService implements ISysUserService {
|
||||
logger.debug("角色列表为空,删除用户的所有角色关联");
|
||||
return userRoleRepository.deleteByUserId(userId)
|
||||
.doOnSuccess(v -> logger.debug("成功删除用户的所有角色关联"))
|
||||
.doOnError(e -> logger.error("删除用户角色关联失败", e));
|
||||
.doOnError(e -> logger.error("删除用户角色关联失败", e))
|
||||
.then(AuditLogHelper.record(auditLogService, "User", userId, "UPDATE", null));
|
||||
}
|
||||
|
||||
return userRoleRepository.deleteByUserId(userId)
|
||||
@@ -265,12 +298,12 @@ public class SysUserService implements ISysUserService {
|
||||
UserRole userRole = new UserRole();
|
||||
userRole.setUserId(userId);
|
||||
userRole.setRoleId(roleId);
|
||||
userRole.setCreatedAt(LocalDateTime.now());
|
||||
return userRoleRepository.save(userRole)
|
||||
.doOnSuccess(v -> logger.debug("成功保存用户角色关联"))
|
||||
.doOnError(e -> logger.error("保存用户角色关联失败", e));
|
||||
})
|
||||
.then());
|
||||
.then())
|
||||
.then(AuditLogHelper.record(auditLogService, "User", userId, "UPDATE", null));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
@@ -43,6 +43,7 @@ class OperationLogServiceTest {
|
||||
testLog.setDuration(100L);
|
||||
testLog.setIp("192.168.1.1");
|
||||
testLog.setStatus("1");
|
||||
testLog.setCreatedAt(LocalDateTime.now());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+7
-1
@@ -1,5 +1,6 @@
|
||||
package cn.novalon.gym.manage.sys.core.service.impl;
|
||||
|
||||
import cn.novalon.gym.manage.sys.audit.service.IAuditLogService;
|
||||
import cn.novalon.gym.manage.sys.core.domain.SysConfig;
|
||||
import cn.novalon.gym.manage.sys.core.repository.ISysConfigRepository;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@@ -26,13 +27,16 @@ class SysConfigServiceTest {
|
||||
@Mock
|
||||
private ISysConfigRepository repository;
|
||||
|
||||
@Mock
|
||||
private IAuditLogService auditLogService;
|
||||
|
||||
private SysConfigService configService;
|
||||
|
||||
private SysConfig testConfig;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
configService = new SysConfigService(repository);
|
||||
configService = new SysConfigService(repository, auditLogService);
|
||||
|
||||
testConfig = new SysConfig();
|
||||
testConfig.setId(1L);
|
||||
@@ -110,11 +114,13 @@ class SysConfigServiceTest {
|
||||
|
||||
@Test
|
||||
void testDeleteById() {
|
||||
when(repository.findById(1L)).thenReturn(Mono.just(testConfig));
|
||||
when(repository.deleteByIdAndDeletedAtIsNull(1L)).thenReturn(Mono.empty());
|
||||
|
||||
StepVerifier.create(configService.deleteById(1L))
|
||||
.verifyComplete();
|
||||
|
||||
verify(repository).findById(1L);
|
||||
verify(repository).deleteByIdAndDeletedAtIsNull(1L);
|
||||
}
|
||||
|
||||
|
||||
+7
-1
@@ -1,5 +1,6 @@
|
||||
package cn.novalon.gym.manage.sys.core.service.impl;
|
||||
|
||||
import cn.novalon.gym.manage.sys.audit.service.IAuditLogService;
|
||||
import cn.novalon.gym.manage.sys.core.domain.SysDictType;
|
||||
import cn.novalon.gym.manage.sys.core.repository.ISysDictTypeRepository;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@@ -23,12 +24,15 @@ class SysDictTypeServiceTest {
|
||||
@Mock
|
||||
private ISysDictTypeRepository repository;
|
||||
|
||||
@Mock
|
||||
private IAuditLogService auditLogService;
|
||||
|
||||
private SysDictTypeService dictTypeService;
|
||||
private SysDictType testDictType;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
dictTypeService = new SysDictTypeService(repository);
|
||||
dictTypeService = new SysDictTypeService(repository, auditLogService);
|
||||
|
||||
testDictType = new SysDictType();
|
||||
testDictType.setId(1L);
|
||||
@@ -93,6 +97,7 @@ class SysDictTypeServiceTest {
|
||||
|
||||
@Test
|
||||
void testDeleteById() {
|
||||
when(repository.findById(1L)).thenReturn(Mono.just(testDictType));
|
||||
when(repository.deleteByIdAndDeletedAtIsNull(1L)).thenReturn(Mono.empty());
|
||||
|
||||
Mono<Void> result = dictTypeService.deleteById(1L);
|
||||
@@ -100,6 +105,7 @@ class SysDictTypeServiceTest {
|
||||
StepVerifier.create(result)
|
||||
.verifyComplete();
|
||||
|
||||
verify(repository).findById(1L);
|
||||
verify(repository).deleteByIdAndDeletedAtIsNull(1L);
|
||||
}
|
||||
}
|
||||
+17
-9
@@ -4,6 +4,7 @@ import cn.novalon.gym.manage.sys.core.domain.SysMenu;
|
||||
import cn.novalon.gym.manage.sys.core.repository.ISysMenuRepository;
|
||||
import cn.novalon.gym.manage.sys.core.command.CreateMenuCommand;
|
||||
import cn.novalon.gym.manage.sys.core.command.UpdateMenuCommand;
|
||||
import cn.novalon.gym.manage.sys.audit.service.IAuditLogService;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
@@ -25,12 +26,15 @@ class SysMenuServiceTest {
|
||||
@Mock
|
||||
private ISysMenuRepository menuRepository;
|
||||
|
||||
@Mock
|
||||
private IAuditLogService auditLogService;
|
||||
|
||||
private SysMenuService menuService;
|
||||
private SysMenu testMenu;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
menuService = new SysMenuService(menuRepository);
|
||||
menuService = new SysMenuService(menuRepository, auditLogService);
|
||||
|
||||
testMenu = new SysMenu();
|
||||
testMenu.setId(1L);
|
||||
@@ -129,7 +133,8 @@ class SysMenuServiceTest {
|
||||
|
||||
@Test
|
||||
void testUpdateMenu() {
|
||||
when(menuRepository.save(any(SysMenu.class))).thenReturn(Mono.just(testMenu));
|
||||
when(menuRepository.findById(1L)).thenReturn(Mono.just(testMenu));
|
||||
when(menuRepository.update(any(SysMenu.class))).thenReturn(Mono.just(testMenu));
|
||||
|
||||
Mono<SysMenu> result = menuService.updateMenu(testMenu);
|
||||
|
||||
@@ -138,7 +143,8 @@ class SysMenuServiceTest {
|
||||
menu.getUpdatedAt() != null)
|
||||
.verifyComplete();
|
||||
|
||||
verify(menuRepository).save(any(SysMenu.class));
|
||||
verify(menuRepository).findById(1L);
|
||||
verify(menuRepository).update(any(SysMenu.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -147,7 +153,7 @@ class SysMenuServiceTest {
|
||||
1L, 0L, "系统管理(更新)", "M", 1, "system", "system:manage", 1);
|
||||
|
||||
when(menuRepository.findById(1L)).thenReturn(Mono.just(testMenu));
|
||||
when(menuRepository.save(any(SysMenu.class))).thenReturn(Mono.just(testMenu));
|
||||
when(menuRepository.update(any(SysMenu.class))).thenReturn(Mono.just(testMenu));
|
||||
|
||||
Mono<SysMenu> result = menuService.updateMenu(command);
|
||||
|
||||
@@ -157,7 +163,7 @@ class SysMenuServiceTest {
|
||||
.verifyComplete();
|
||||
|
||||
verify(menuRepository).findById(1L);
|
||||
verify(menuRepository).save(any(SysMenu.class));
|
||||
verify(menuRepository).update(any(SysMenu.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -200,7 +206,7 @@ class SysMenuServiceTest {
|
||||
updatedMenu.setUpdatedAt(LocalDateTime.now());
|
||||
|
||||
when(menuRepository.findById(1L)).thenReturn(Mono.just(existingMenu));
|
||||
when(menuRepository.save(any(SysMenu.class))).thenReturn(Mono.just(updatedMenu));
|
||||
when(menuRepository.update(any(SysMenu.class))).thenReturn(Mono.just(updatedMenu));
|
||||
|
||||
UpdateMenuCommand command = new UpdateMenuCommand(
|
||||
1L, null, null, null, null, null, null, null);
|
||||
@@ -210,7 +216,7 @@ class SysMenuServiceTest {
|
||||
.verifyComplete();
|
||||
|
||||
verify(menuRepository).findById(1L);
|
||||
verify(menuRepository).save(any(SysMenu.class));
|
||||
verify(menuRepository).update(any(SysMenu.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -237,7 +243,7 @@ class SysMenuServiceTest {
|
||||
updatedMenu.setUpdatedAt(LocalDateTime.now());
|
||||
|
||||
when(menuRepository.findById(1L)).thenReturn(Mono.just(existingMenu));
|
||||
when(menuRepository.save(any(SysMenu.class))).thenReturn(Mono.just(updatedMenu));
|
||||
when(menuRepository.update(any(SysMenu.class))).thenReturn(Mono.just(updatedMenu));
|
||||
|
||||
UpdateMenuCommand command = new UpdateMenuCommand(
|
||||
1L, 2L, "系统管理(更新)", "C", 2, "system_updated", "system:manage_updated", 0);
|
||||
@@ -247,11 +253,12 @@ class SysMenuServiceTest {
|
||||
.verifyComplete();
|
||||
|
||||
verify(menuRepository).findById(1L);
|
||||
verify(menuRepository).save(any(SysMenu.class));
|
||||
verify(menuRepository).update(any(SysMenu.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDeleteMenu() {
|
||||
when(menuRepository.findById(1L)).thenReturn(Mono.just(testMenu));
|
||||
when(menuRepository.deleteById(1L)).thenReturn(Mono.empty());
|
||||
|
||||
Mono<Void> result = menuService.deleteMenu(1L);
|
||||
@@ -259,6 +266,7 @@ class SysMenuServiceTest {
|
||||
StepVerifier.create(result)
|
||||
.verifyComplete();
|
||||
|
||||
verify(menuRepository).findById(1L);
|
||||
verify(menuRepository).deleteById(1L);
|
||||
}
|
||||
|
||||
|
||||
+13
-7
@@ -1,5 +1,6 @@
|
||||
package cn.novalon.gym.manage.sys.core.service.impl;
|
||||
|
||||
import cn.novalon.gym.manage.sys.audit.service.IAuditLogService;
|
||||
import cn.novalon.gym.manage.common.util.StatusConstants;
|
||||
import cn.novalon.gym.manage.sys.core.domain.SysRole;
|
||||
import cn.novalon.gym.manage.sys.core.query.SysRoleQuery;
|
||||
@@ -46,13 +47,16 @@ class SysRoleServiceTest {
|
||||
@Mock
|
||||
private ISysRolePermissionRepository rolePermissionRepository;
|
||||
|
||||
@Mock
|
||||
private IAuditLogService auditLogService;
|
||||
|
||||
private SysRoleService roleService;
|
||||
|
||||
private SysRole testRole;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
roleService = new SysRoleService(roleRepository, userService, userRoleRepository, rolePermissionRepository);
|
||||
roleService = new SysRoleService(roleRepository, userService, userRoleRepository, rolePermissionRepository, auditLogService);
|
||||
|
||||
testRole = new SysRole();
|
||||
testRole.setId(1L);
|
||||
@@ -206,7 +210,7 @@ class SysRoleServiceTest {
|
||||
existingRole.setStatus(StatusConstants.ENABLED);
|
||||
|
||||
when(roleRepository.findById(1L)).thenReturn(Mono.just(existingRole));
|
||||
when(roleRepository.save(any(SysRole.class))).thenReturn(Mono.just(testRole));
|
||||
when(roleRepository.updateRole(any(SysRole.class))).thenReturn(Mono.just(testRole));
|
||||
|
||||
cn.novalon.gym.manage.sys.core.command.UpdateRoleCommand command =
|
||||
new cn.novalon.gym.manage.sys.core.command.UpdateRoleCommand(
|
||||
@@ -218,7 +222,7 @@ class SysRoleServiceTest {
|
||||
.verifyComplete();
|
||||
|
||||
verify(roleRepository).findById(1L);
|
||||
verify(roleRepository).save(any(SysRole.class));
|
||||
verify(roleRepository).updateRole(any(SysRole.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -231,7 +235,7 @@ class SysRoleServiceTest {
|
||||
existingRole.setStatus(StatusConstants.ENABLED);
|
||||
|
||||
when(roleRepository.findById(1L)).thenReturn(Mono.just(existingRole));
|
||||
when(roleRepository.save(any(SysRole.class))).thenReturn(Mono.just(testRole));
|
||||
when(roleRepository.updateRole(any(SysRole.class))).thenReturn(Mono.just(testRole));
|
||||
|
||||
cn.novalon.gym.manage.sys.core.command.UpdateRoleCommand command =
|
||||
new cn.novalon.gym.manage.sys.core.command.UpdateRoleCommand(
|
||||
@@ -243,7 +247,7 @@ class SysRoleServiceTest {
|
||||
.verifyComplete();
|
||||
|
||||
verify(roleRepository).findById(1L);
|
||||
verify(roleRepository).save(any(SysRole.class));
|
||||
verify(roleRepository).updateRole(any(SysRole.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -252,13 +256,15 @@ class SysRoleServiceTest {
|
||||
updateRole.setId(1L);
|
||||
updateRole.setRoleName("updated_admin");
|
||||
|
||||
when(roleRepository.save(any(SysRole.class))).thenReturn(Mono.just(testRole));
|
||||
when(roleRepository.findById(1L)).thenReturn(Mono.just(testRole));
|
||||
when(roleRepository.updateRole(any(SysRole.class))).thenReturn(Mono.just(testRole));
|
||||
|
||||
StepVerifier.create(roleService.updateRole(updateRole))
|
||||
.expectNextMatches(role -> role.getUpdatedAt() != null)
|
||||
.verifyComplete();
|
||||
|
||||
verify(roleRepository).save(any(SysRole.class));
|
||||
verify(roleRepository).findById(1L);
|
||||
verify(roleRepository).updateRole(any(SysRole.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+5
-1
@@ -1,6 +1,7 @@
|
||||
package cn.novalon.gym.manage.sys.core.service.impl;
|
||||
|
||||
import cn.novalon.gym.manage.common.util.StatusConstants;
|
||||
import cn.novalon.gym.manage.sys.audit.service.IAuditLogService;
|
||||
import cn.novalon.gym.manage.sys.config.IntegrationTestConfig;
|
||||
import cn.novalon.gym.manage.sys.core.domain.SysUser;
|
||||
import cn.novalon.gym.manage.sys.core.domain.SysRole;
|
||||
@@ -76,6 +77,9 @@ class SysUserServiceIntegrationTest {
|
||||
@Autowired
|
||||
private IUserRoleRepository userRoleRepository;
|
||||
|
||||
@Autowired
|
||||
private IAuditLogService auditLogService;
|
||||
|
||||
@Autowired
|
||||
private R2dbcEntityTemplate r2dbcEntityTemplate;
|
||||
|
||||
@@ -85,7 +89,7 @@ class SysUserServiceIntegrationTest {
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
passwordEncoder = new BCryptPasswordEncoder(12);
|
||||
userService = new SysUserService(userRepository, roleRepository, userRoleRepository, passwordEncoder);
|
||||
userService = new SysUserService(userRepository, roleRepository, userRoleRepository, passwordEncoder, auditLogService);
|
||||
|
||||
r2dbcEntityTemplate.delete(SysUser.class).all().block();
|
||||
r2dbcEntityTemplate.delete(SysRole.class).all().block();
|
||||
|
||||
+12
-5
@@ -1,6 +1,8 @@
|
||||
package cn.novalon.gym.manage.sys.core.service.impl;
|
||||
|
||||
import cn.novalon.gym.manage.common.util.StatusConstants;
|
||||
import cn.novalon.gym.manage.sys.audit.service.IAuditLogService;
|
||||
import cn.novalon.gym.manage.sys.audit.domain.AuditLog;
|
||||
import cn.novalon.gym.manage.sys.core.domain.SysUser;
|
||||
import cn.novalon.gym.manage.sys.core.domain.UserRole;
|
||||
import cn.novalon.gym.manage.sys.core.repository.ISysUserRepository;
|
||||
@@ -45,11 +47,14 @@ class SysUserServiceTest {
|
||||
@Mock
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
@Mock
|
||||
private IAuditLogService auditLogService;
|
||||
|
||||
private SysUserService userService;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
userService = new SysUserService(userRepository, roleRepository, userRoleRepository, passwordEncoder);
|
||||
userService = new SysUserService(userRepository, roleRepository, userRoleRepository, passwordEncoder, auditLogService);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -164,7 +169,8 @@ class SysUserServiceTest {
|
||||
user.setUsername("testuser");
|
||||
user.setEmail("updated@example.com");
|
||||
|
||||
when(userRepository.save(any(SysUser.class))).thenReturn(Mono.just(user));
|
||||
when(userRepository.findById(1L)).thenReturn(Mono.just(user));
|
||||
when(userRepository.update(any(SysUser.class))).thenReturn(Mono.just(user));
|
||||
|
||||
StepVerifier.create(userService.updateUser(user))
|
||||
.expectNextMatches(updatedUser ->
|
||||
@@ -173,7 +179,8 @@ class SysUserServiceTest {
|
||||
)
|
||||
.verifyComplete();
|
||||
|
||||
verify(userRepository, times(1)).save(any(SysUser.class));
|
||||
verify(userRepository, times(1)).findById(1L);
|
||||
verify(userRepository, times(1)).update(any(SysUser.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -218,7 +225,7 @@ class SysUserServiceTest {
|
||||
when(userRepository.findById(1L)).thenReturn(Mono.just(user));
|
||||
when(passwordEncoder.matches("oldPassword", "$2b$12$oldPassword")).thenReturn(true);
|
||||
when(passwordEncoder.encode("newPassword")).thenReturn("$2b$12$newPassword");
|
||||
when(userRepository.save(any(SysUser.class))).thenAnswer(invocation -> Mono.just(invocation.getArgument(0)));
|
||||
when(userRepository.update(any(SysUser.class))).thenAnswer(invocation -> Mono.just(invocation.getArgument(0)));
|
||||
|
||||
StepVerifier.create(userService.changePassword(1L, "oldPassword", "newPassword"))
|
||||
.expectNextMatches(updatedUser ->
|
||||
@@ -228,7 +235,7 @@ class SysUserServiceTest {
|
||||
|
||||
verify(passwordEncoder, times(1)).matches("oldPassword", "$2b$12$oldPassword");
|
||||
verify(passwordEncoder, times(1)).encode("newPassword");
|
||||
verify(userRepository, times(1)).save(any(SysUser.class));
|
||||
verify(userRepository, times(1)).update(any(SysUser.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+12
-8
@@ -10,6 +10,7 @@ import cn.novalon.gym.manage.sys.core.service.ISysMenuService;
|
||||
import cn.novalon.gym.manage.sys.core.service.ISysRoleService;
|
||||
import cn.novalon.gym.manage.sys.core.service.ISysUserService;
|
||||
import cn.novalon.gym.manage.sys.core.service.impl.SysMenuService;
|
||||
import cn.novalon.gym.manage.sys.audit.service.IAuditLogService;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
@@ -61,6 +62,9 @@ class SystemConfigRegressionTest {
|
||||
@Mock
|
||||
private ISysMenuRepository menuRepository;
|
||||
|
||||
@Mock
|
||||
private IAuditLogService auditLogService;
|
||||
|
||||
private SysUser adminUser;
|
||||
private SysUser normalUser;
|
||||
private SysUser guestUser;
|
||||
@@ -374,7 +378,7 @@ class SystemConfigRegressionTest {
|
||||
void testAdminUser_MenuManagement() {
|
||||
/* unused */
|
||||
|
||||
ISysMenuService menuService = new SysMenuService(menuRepository);
|
||||
ISysMenuService menuService = new SysMenuService(menuRepository, auditLogService);
|
||||
|
||||
StepVerifier.create(menuService.findAll())
|
||||
.expectNextCount(0)
|
||||
@@ -384,7 +388,7 @@ class SystemConfigRegressionTest {
|
||||
@Test
|
||||
@DisplayName("3.2 普通用户 - 菜单访问控制")
|
||||
void testNormalUser_MenuAccess() {
|
||||
ISysMenuService menuService = new SysMenuService(menuRepository);
|
||||
ISysMenuService menuService = new SysMenuService(menuRepository, auditLogService);
|
||||
|
||||
StepVerifier.create(menuService.findAll())
|
||||
.expectNextCount(0)
|
||||
@@ -394,7 +398,7 @@ class SystemConfigRegressionTest {
|
||||
@Test
|
||||
@DisplayName("3.3 访客用户 - 菜单访问控制")
|
||||
void testGuestUser_MenuAccess() {
|
||||
ISysMenuService menuService = new SysMenuService(menuRepository);
|
||||
ISysMenuService menuService = new SysMenuService(menuRepository, auditLogService);
|
||||
|
||||
StepVerifier.create(menuService.findAll())
|
||||
.expectNextCount(0)
|
||||
@@ -404,7 +408,7 @@ class SystemConfigRegressionTest {
|
||||
@Test
|
||||
@DisplayName("3.4 菜单树构建 - 管理员视图")
|
||||
void testMenuTree_Build_Admin() {
|
||||
ISysMenuService menuService = new SysMenuService(menuRepository);
|
||||
ISysMenuService menuService = new SysMenuService(menuRepository, auditLogService);
|
||||
|
||||
StepVerifier.create(menuService.findAll())
|
||||
.verifyComplete();
|
||||
@@ -413,7 +417,7 @@ class SystemConfigRegressionTest {
|
||||
@Test
|
||||
@DisplayName("3.5 权限菜单过滤 - 普通用户视图")
|
||||
void testMenuFilter_NormalUser() {
|
||||
ISysMenuService menuService = new SysMenuService(menuRepository);
|
||||
ISysMenuService menuService = new SysMenuService(menuRepository, auditLogService);
|
||||
|
||||
StepVerifier.create(menuService.findAll())
|
||||
.expectNextCount(0)
|
||||
@@ -423,7 +427,7 @@ class SystemConfigRegressionTest {
|
||||
@Test
|
||||
@DisplayName("3.6 权限菜单过滤 - 访客视图")
|
||||
void testMenuFilter_Guest() {
|
||||
ISysMenuService menuService = new SysMenuService(menuRepository);
|
||||
ISysMenuService menuService = new SysMenuService(menuRepository, auditLogService);
|
||||
|
||||
StepVerifier.create(menuService.findAll())
|
||||
.expectNextCount(0)
|
||||
@@ -472,7 +476,7 @@ class SystemConfigRegressionTest {
|
||||
@Test
|
||||
@DisplayName("5.2 大量菜单加载性能测试")
|
||||
void testLargeMenuLoadPerformance() {
|
||||
ISysMenuService menuService = new SysMenuService(menuRepository);
|
||||
ISysMenuService menuService = new SysMenuService(menuRepository, auditLogService);
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
@@ -516,7 +520,7 @@ class SystemConfigRegressionTest {
|
||||
@Test
|
||||
@DisplayName("6.3 菜单层级结构完整性")
|
||||
void testMenuHierarchy_Integrity() {
|
||||
ISysMenuService menuService = new SysMenuService(menuRepository);
|
||||
ISysMenuService menuService = new SysMenuService(menuRepository, auditLogService);
|
||||
|
||||
StepVerifier.create(menuService.findAll())
|
||||
.verifyComplete();
|
||||
|
||||
Reference in New Issue
Block a user