refactor(backend): 重命名后端项目为 gym-manage-api,修改包名为 cn.novalon.gym.manage
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<suppressions xmlns="https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.3.xsd">
|
||||
</suppressions>
|
||||
@@ -0,0 +1,223 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>cn.novalon.gym.manage</groupId>
|
||||
<artifactId>gym-manage-api</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>manage-sys</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Manage Sys</name>
|
||||
<description>System Management Module</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.novalon.gym.manage</groupId>
|
||||
<artifactId>manage-common</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-starter-webflux-ui</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-commons</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.resilience4j</groupId>
|
||||
<artifactId>resilience4j-spring-boot3</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.resilience4j</groupId>
|
||||
<artifactId>resilience4j-reactor</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>testcontainers</artifactId>
|
||||
<version>1.21.4</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>1.21.4</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>1.21.4</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.r2dbc</groupId>
|
||||
<artifactId>r2dbc-h2</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>r2dbc-postgresql</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi-ooxml</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.4.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>default-jar</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.11.0</version>
|
||||
<configuration>
|
||||
<source>21</source>
|
||||
<target>21</target>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>org.mapstruct</groupId>
|
||||
<artifactId>mapstruct-processor</artifactId>
|
||||
<version>1.5.5.Final</version>
|
||||
</path>
|
||||
<path>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${lombok.version}</version>
|
||||
</path>
|
||||
<path>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok-mapstruct-binding</artifactId>
|
||||
<version>0.2.0</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<version>0.8.12</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>prepare-agent</id>
|
||||
<goals>
|
||||
<goal>prepare-agent</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>report</id>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>report</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>check</id>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<rules>
|
||||
<rule>
|
||||
<element>BUNDLE</element>
|
||||
<limits>
|
||||
<limit>
|
||||
<counter>INSTRUCTION</counter>
|
||||
<value>COVEREDRATIO</value>
|
||||
<minimum>0.80</minimum>
|
||||
</limit>
|
||||
</limits>
|
||||
</rule>
|
||||
</rules>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>com.github.spotbugs</groupId>
|
||||
<artifactId>spotbugs-maven-plugin</artifactId>
|
||||
<version>4.8.6.0</version>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.github.spotbugs</groupId>
|
||||
<artifactId>spotbugs</artifactId>
|
||||
<version>4.8.6</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>spotbugs-check</id>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<effort>Max</effort>
|
||||
<threshold>High</threshold>
|
||||
<failOnError>true</failOnError>
|
||||
<excludeFilterFile>spotbugs-exclude.xml</excludeFilterFile>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<FindBugsFilter>
|
||||
<Match>
|
||||
<Class name="~.*\.entity\..*" />
|
||||
</Match>
|
||||
<Match>
|
||||
<Class name="~.*\.dto\..*" />
|
||||
</Match>
|
||||
<Match>
|
||||
<Class name="~.*\.converter\..*" />
|
||||
</Match>
|
||||
<Match>
|
||||
<Class name="~.*\.mapper\..*Impl" />
|
||||
</Match>
|
||||
<Match>
|
||||
<Package name="~cn\.novalon\.manage\.sys\.ManageSysApplication" />
|
||||
</Match>
|
||||
</FindBugsFilter>
|
||||
+300
@@ -0,0 +1,300 @@
|
||||
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.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.domain.Persistable;
|
||||
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
|
||||
import org.springframework.stereotype.Component;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 审计日志切面
|
||||
*
|
||||
* 文件定义:使用AOP自动拦截Repository操作,记录审计日志
|
||||
* 涉及业务:自动记录所有数据变更操作,包括变更前后对比
|
||||
* 算法:使用异步方式记录日志,不阻塞主流程
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-04-01
|
||||
*/
|
||||
@Aspect
|
||||
@Component
|
||||
public class AuditLogAspect {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AuditLogAspect.class);
|
||||
|
||||
private final IAuditLogService auditLogService;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
public AuditLogAspect(IAuditLogService auditLogService, ObjectMapper objectMapper) {
|
||||
this.auditLogService = auditLogService;
|
||||
this.objectMapper = objectMapper;
|
||||
}
|
||||
|
||||
@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(..))")
|
||||
public Object logAuditEvent(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||
String methodName = joinPoint.getSignature().getName();
|
||||
String className = joinPoint.getTarget().getClass().getSimpleName();
|
||||
Object[] args = joinPoint.getArgs();
|
||||
|
||||
String operationType = determineOperationType(methodName);
|
||||
String entityType = extractEntityType(className);
|
||||
|
||||
logger.debug("拦截审计操作: {}.{}, 操作类型: {}, 实体类型: {}",
|
||||
className, methodName, operationType, entityType);
|
||||
|
||||
try {
|
||||
if ("save".equals(methodName) && args.length > 0) {
|
||||
return handleSaveOperation(joinPoint, args[0], entityType, operationType);
|
||||
} else if ("delete".equals(methodName) || "deleteById".equals(methodName)) {
|
||||
return handleDeleteOperation(joinPoint, args, entityType, operationType);
|
||||
}
|
||||
|
||||
return joinPoint.proceed();
|
||||
} catch (Throwable error) {
|
||||
logger.error("审计日志记录失败: {}", error.getMessage(), error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
private Object handleSaveOperation(ProceedingJoinPoint joinPoint, Object entity,
|
||||
String entityType, String operationType) throws Throwable {
|
||||
try {
|
||||
final String[] beforeDataHolder = {null};
|
||||
final Long[] entityIdHolder = {null};
|
||||
final String[] operationTypeHolder = {operationType};
|
||||
|
||||
if (entity instanceof Persistable) {
|
||||
Persistable<?> persistable = (Persistable<?>) entity;
|
||||
entityIdHolder[0] = persistable.getId() != null ?
|
||||
((Number) persistable.getId()).longValue() : null;
|
||||
|
||||
if (entityIdHolder[0] != null) {
|
||||
beforeDataHolder[0] = fetchEntityBeforeData(entityType, entityIdHolder[0]);
|
||||
operationTypeHolder[0] = "UPDATE";
|
||||
} else {
|
||||
operationTypeHolder[0] = "CREATE";
|
||||
}
|
||||
}
|
||||
|
||||
Object result = joinPoint.proceed();
|
||||
|
||||
if (result instanceof Mono) {
|
||||
return ((Mono<?>) result).flatMap(savedEntity -> {
|
||||
String afterData = serializeEntity(savedEntity);
|
||||
Long finalEntityId = entityIdHolder[0] != null ? entityIdHolder[0] : extractEntityId(savedEntity);
|
||||
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
|
||||
).thenReturn(savedEntity);
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (Throwable error) {
|
||||
logger.error("保存操作审计日志记录失败", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
private Object handleDeleteOperation(ProceedingJoinPoint joinPoint, Object[] args,
|
||||
String entityType, String operationType) throws Throwable {
|
||||
try {
|
||||
Long entityId = null;
|
||||
String beforeData = null;
|
||||
|
||||
if (args.length > 0) {
|
||||
if (args[0] instanceof Number) {
|
||||
entityId = ((Number) args[0]).longValue();
|
||||
beforeData = fetchEntityBeforeData(entityType, entityId);
|
||||
} else if (args[0] instanceof Persistable) {
|
||||
Persistable<?> persistable = (Persistable<?>) args[0];
|
||||
entityId = persistable.getId() != null ?
|
||||
((Number) persistable.getId()).longValue() : null;
|
||||
beforeData = serializeEntity(args[0]);
|
||||
}
|
||||
}
|
||||
|
||||
Object result = joinPoint.proceed();
|
||||
|
||||
if (result instanceof Mono) {
|
||||
Long finalEntityId = entityId;
|
||||
String finalBeforeData = beforeData;
|
||||
return ((Mono<?>) result).flatMap(deleted ->
|
||||
createAndSaveAuditLog(
|
||||
entityType, finalEntityId, "DELETE",
|
||||
finalBeforeData, null, null
|
||||
).thenReturn(deleted)
|
||||
);
|
||||
} else if (result instanceof Flux) {
|
||||
Long finalEntityId = entityId;
|
||||
String finalBeforeData = beforeData;
|
||||
return ((Flux<?>) result).flatMap(deleted ->
|
||||
createAndSaveAuditLog(
|
||||
entityType, finalEntityId, "DELETE",
|
||||
finalBeforeData, null, null
|
||||
).thenReturn(deleted)
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (Throwable error) {
|
||||
logger.error("删除操作审计日志记录失败", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
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")
|
||||
.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);
|
||||
|
||||
logger.debug("审计日志对象: entityId={}, entityType={}, operationType={}",
|
||||
auditLog.getEntityId(), auditLog.getEntityType(), auditLog.getOperationType());
|
||||
|
||||
if (beforeData != null && afterData != null) {
|
||||
String[] changedFields = extractChangedFields(beforeData, afterData);
|
||||
auditLog.setChangedFields(changedFields);
|
||||
}
|
||||
|
||||
auditLog.setDescription(generateDescription(entityType, operationType, entityId));
|
||||
|
||||
return auditLogService.save(auditLog)
|
||||
.doOnSuccess(saved -> logger.debug("审计日志保存成功: {} - {}",
|
||||
entityType, operationType))
|
||||
.doOnError(error -> logger.error("审计日志保存失败: {}",
|
||||
error.getMessage()))
|
||||
.then();
|
||||
})
|
||||
.onErrorResume(error -> {
|
||||
logger.error("创建审计日志失败,但不影响主流程: {}", error.getMessage());
|
||||
return Mono.empty();
|
||||
});
|
||||
}
|
||||
|
||||
private String determineOperationType(String methodName) {
|
||||
if (methodName.startsWith("save")) {
|
||||
return "SAVE";
|
||||
} else if (methodName.startsWith("delete")) {
|
||||
return "DELETE";
|
||||
}
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
private String extractEntityType(String className) {
|
||||
if (className.contains("User")) {
|
||||
return "User";
|
||||
} else if (className.contains("Role")) {
|
||||
return "Role";
|
||||
} else if (className.contains("Menu")) {
|
||||
return "Menu";
|
||||
} else if (className.contains("Permission")) {
|
||||
return "Permission";
|
||||
}
|
||||
return className.replace("Repository", "").replace("Impl", "");
|
||||
}
|
||||
|
||||
private String fetchEntityBeforeData(String entityType, Long entityId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
private String serializeEntity(Object entity) {
|
||||
try {
|
||||
return objectMapper.writeValueAsString(entity);
|
||||
} catch (Exception e) {
|
||||
logger.error("序列化实体失败: {}", e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private String[] extractChangedFields(String beforeData, String afterData) {
|
||||
try {
|
||||
JsonNode beforeNode = objectMapper.readTree(beforeData);
|
||||
JsonNode afterNode = objectMapper.readTree(afterData);
|
||||
|
||||
List<String> changedFields = new ArrayList<>();
|
||||
|
||||
beforeNode.fieldNames().forEachRemaining(fieldName -> {
|
||||
JsonNode beforeValue = beforeNode.get(fieldName);
|
||||
JsonNode afterValue = afterNode.get(fieldName);
|
||||
|
||||
if (afterValue == null || !beforeValue.equals(afterValue)) {
|
||||
changedFields.add(fieldName);
|
||||
}
|
||||
});
|
||||
|
||||
afterNode.fieldNames().forEachRemaining(fieldName -> {
|
||||
if (!beforeNode.has(fieldName)) {
|
||||
changedFields.add(fieldName);
|
||||
}
|
||||
});
|
||||
|
||||
return changedFields.toArray(new String[0]);
|
||||
} catch (Exception e) {
|
||||
logger.error("提取变更字段失败: {}", e.getMessage());
|
||||
return new String[0];
|
||||
}
|
||||
}
|
||||
|
||||
private String generateDescription(String entityType, String operationType, Long entityId) {
|
||||
String operation = "";
|
||||
switch (operationType) {
|
||||
case "CREATE":
|
||||
operation = "创建";
|
||||
break;
|
||||
case "UPDATE":
|
||||
operation = "更新";
|
||||
break;
|
||||
case "DELETE":
|
||||
operation = "删除";
|
||||
break;
|
||||
default:
|
||||
operation = "操作";
|
||||
}
|
||||
|
||||
return String.format("%s%s (ID: %s)", operation, entityType,
|
||||
entityId != null ? entityId : "未知");
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package cn.novalon.gym.manage.sys.audit;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 操作日志注解
|
||||
* 标记需要记录操作日志的方法
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-04-03
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface OperationLog {
|
||||
|
||||
/**
|
||||
* 操作名称
|
||||
* 例如:"创建用户"、"删除角色"
|
||||
*/
|
||||
String operation();
|
||||
|
||||
/**
|
||||
* 模块名称
|
||||
* 例如:"用户管理"、"角色管理"
|
||||
*/
|
||||
String module();
|
||||
}
|
||||
+154
@@ -0,0 +1,154 @@
|
||||
package cn.novalon.gym.manage.sys.audit;
|
||||
|
||||
import cn.novalon.gym.manage.sys.core.domain.OperationLog;
|
||||
import cn.novalon.gym.manage.sys.core.service.IOperationLogService;
|
||||
import cn.novalon.gym.manage.sys.util.IpUtils;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.reactive.function.server.ServerRequest;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@Aspect
|
||||
@Component
|
||||
public class OperationLogAspect {
|
||||
private static final Logger logger = LoggerFactory.getLogger(OperationLogAspect.class);
|
||||
private static final int MAX_PARAM_LENGTH = 2000;
|
||||
private static final int MAX_RESULT_LENGTH = 5000;
|
||||
|
||||
private final IOperationLogService logService;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
public OperationLogAspect(IOperationLogService logService, ObjectMapper objectMapper) {
|
||||
this.logService = logService;
|
||||
this.objectMapper = objectMapper;
|
||||
}
|
||||
|
||||
@Around("@annotation(operationLogAnnotation)")
|
||||
public Object around(ProceedingJoinPoint point, cn.novalon.gym.manage.sys.audit.OperationLog operationLogAnnotation) throws Throwable {
|
||||
long startTime = System.currentTimeMillis();
|
||||
ServerRequest serverRequest = extractServerRequest(point.getArgs());
|
||||
String ip = IpUtils.getClientIp(serverRequest);
|
||||
String method = point.getSignature().toShortString();
|
||||
String params = serializeParams(point.getArgs());
|
||||
|
||||
try {
|
||||
Object result = point.proceed();
|
||||
|
||||
if (result instanceof Mono) {
|
||||
return getCurrentUsername()
|
||||
.flatMap(username -> ((Mono<?>) result)
|
||||
.flatMap(res -> {
|
||||
long duration = System.currentTimeMillis() - startTime;
|
||||
return saveLogAsync(operationLogAnnotation, username, ip, method, params, res, duration, "0", null)
|
||||
.onErrorResume(e -> Mono.empty())
|
||||
.thenReturn(res);
|
||||
})
|
||||
.onErrorResume(error -> {
|
||||
long duration = System.currentTimeMillis() - startTime;
|
||||
return saveLogAsync(operationLogAnnotation, username, ip, method, params, null, duration, "1", error.getMessage())
|
||||
.onErrorResume(e -> Mono.empty())
|
||||
.then(Mono.error(error));
|
||||
})
|
||||
);
|
||||
} else if (result instanceof Flux) {
|
||||
return getCurrentUsername()
|
||||
.flatMapMany(username -> ((Flux<?>) result)
|
||||
.collectList()
|
||||
.flatMapMany(res -> {
|
||||
long duration = System.currentTimeMillis() - startTime;
|
||||
return saveLogAsync(operationLogAnnotation, username, ip, method, params, res, duration, "0", null)
|
||||
.onErrorResume(e -> Mono.empty())
|
||||
.thenMany(Flux.fromIterable(res));
|
||||
})
|
||||
.onErrorResume(error -> {
|
||||
long duration = System.currentTimeMillis() - startTime;
|
||||
return saveLogAsync(operationLogAnnotation, username, ip, method, params, null, duration, "1", error.getMessage())
|
||||
.onErrorResume(e -> Mono.empty())
|
||||
.thenMany(Flux.error(error));
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (Throwable error) {
|
||||
long duration = System.currentTimeMillis() - startTime;
|
||||
getCurrentUsername()
|
||||
.flatMap(username -> saveLogAsync(operationLogAnnotation, username, ip, method, params, null, duration, "1", error.getMessage()))
|
||||
.subscribe();
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
private ServerRequest extractServerRequest(Object[] args) {
|
||||
if (args == null || args.length == 0) return null;
|
||||
for (Object arg : args) {
|
||||
if (arg instanceof ServerRequest) return (ServerRequest) arg;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Mono<String> getCurrentUsername() {
|
||||
return ReactiveSecurityContextHolder.getContext()
|
||||
.map(ctx -> ctx.getAuthentication().getPrincipal())
|
||||
.map(principal -> principal instanceof String ? (String) principal : "system")
|
||||
.defaultIfEmpty("system")
|
||||
.onErrorReturn("system");
|
||||
}
|
||||
|
||||
private String serializeParams(Object[] args) {
|
||||
try {
|
||||
if (args == null || args.length == 0) return null;
|
||||
String json = objectMapper.writeValueAsString(args);
|
||||
if (json.length() > MAX_PARAM_LENGTH) {
|
||||
return json.substring(0, MAX_PARAM_LENGTH) + "...(truncated)";
|
||||
}
|
||||
return json;
|
||||
} catch (Exception e) {
|
||||
logger.warn("序列化参数失败: {}", e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String serializeResult(Object result) {
|
||||
try {
|
||||
if (result == null) return null;
|
||||
String json = objectMapper.writeValueAsString(result);
|
||||
if (json.length() > MAX_RESULT_LENGTH) {
|
||||
return json.substring(0, MAX_RESULT_LENGTH) + "...(truncated)";
|
||||
}
|
||||
return json;
|
||||
} catch (Exception e) {
|
||||
logger.warn("序列化结果失败: {}", e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Mono<Void> saveLogAsync(cn.novalon.gym.manage.sys.audit.OperationLog annotation,
|
||||
String username, String ip, String method,
|
||||
String params, Object result, long duration,
|
||||
String status, String errorMsg) {
|
||||
OperationLog log = new OperationLog();
|
||||
log.setUsername(username);
|
||||
log.setOperation(annotation.module() + " - " + annotation.operation());
|
||||
log.setMethod(method);
|
||||
log.setParams(params);
|
||||
log.setResult(serializeResult(result));
|
||||
log.setIp(ip);
|
||||
log.setDuration(duration);
|
||||
log.setStatus(status);
|
||||
log.setErrorMsg(errorMsg);
|
||||
|
||||
return logService.save(log)
|
||||
.doOnSuccess(saved -> logger.debug("操作日志保存成功: {} - {}",
|
||||
annotation.module(), annotation.operation()))
|
||||
.doOnError(error -> logger.error("操作日志保存失败: {}", error.getMessage()))
|
||||
.then();
|
||||
}
|
||||
}
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
package cn.novalon.gym.manage.sys.audit.controller;
|
||||
|
||||
import cn.novalon.gym.manage.sys.audit.domain.AuditLog;
|
||||
import cn.novalon.gym.manage.sys.audit.dto.AuditLogQueryRequest;
|
||||
import cn.novalon.gym.manage.sys.audit.dto.AuditLogStatistics;
|
||||
import cn.novalon.gym.manage.sys.audit.service.IAuditLogService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 审计日志控制器
|
||||
*
|
||||
* 文件定义:提供审计日志的查询和统计接口
|
||||
* 涉及业务:审计日志查询、统计分析
|
||||
* 算法:使用响应式编程处理查询请求
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-04-01
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/audit-logs")
|
||||
@Tag(name = "审计日志", description = "审计日志查询和统计接口")
|
||||
public class AuditLogController {
|
||||
|
||||
private final IAuditLogService auditLogService;
|
||||
|
||||
public AuditLogController(IAuditLogService auditLogService) {
|
||||
this.auditLogService = auditLogService;
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
@Operation(summary = "根据ID查询审计日志", description = "根据ID查询单个审计日志详情")
|
||||
public Mono<AuditLog> findById(
|
||||
@Parameter(description = "审计日志ID") @PathVariable Long id) {
|
||||
return auditLogService.findById(id);
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
@Operation(summary = "查询审计日志列表", description = "根据条件查询审计日志列表")
|
||||
public Flux<AuditLog> query(AuditLogQueryRequest request) {
|
||||
if (request.getEntityType() != null && request.getEntityId() != null) {
|
||||
return auditLogService.findByEntityTypeAndEntityId(
|
||||
request.getEntityType(),
|
||||
request.getEntityId());
|
||||
} else if (request.getEntityType() != null) {
|
||||
return auditLogService.findByEntityType(request.getEntityType());
|
||||
} else if (request.getOperator() != null) {
|
||||
return auditLogService.findByOperator(request.getOperator());
|
||||
} else if (request.getOperationType() != null) {
|
||||
return auditLogService.findByOperationType(request.getOperationType());
|
||||
} else if (request.getStartTime() != null && request.getEndTime() != null) {
|
||||
return auditLogService.findByOperationTimeBetween(
|
||||
request.getStartTime(),
|
||||
request.getEndTime());
|
||||
}
|
||||
|
||||
return Flux.empty();
|
||||
}
|
||||
|
||||
@GetMapping("/entity-type/{entityType}")
|
||||
@Operation(summary = "按实体类型查询", description = "根据实体类型查询审计日志")
|
||||
public Flux<AuditLog> findByEntityType(
|
||||
@Parameter(description = "实体类型") @PathVariable String entityType) {
|
||||
return auditLogService.findByEntityType(entityType);
|
||||
}
|
||||
|
||||
@GetMapping("/entity/{entityId}")
|
||||
@Operation(summary = "按实体ID查询", description = "根据实体ID查询审计日志")
|
||||
public Flux<AuditLog> findByEntityId(
|
||||
@Parameter(description = "实体ID") @PathVariable Long entityId) {
|
||||
return auditLogService.findByEntityId(entityId);
|
||||
}
|
||||
|
||||
@GetMapping("/operator/{operator}")
|
||||
@Operation(summary = "按操作人查询", description = "根据操作人查询审计日志")
|
||||
public Flux<AuditLog> findByOperator(
|
||||
@Parameter(description = "操作人") @PathVariable String operator) {
|
||||
return auditLogService.findByOperator(operator);
|
||||
}
|
||||
|
||||
@GetMapping("/operation-type/{operationType}")
|
||||
@Operation(summary = "按操作类型查询", description = "根据操作类型查询审计日志")
|
||||
public Flux<AuditLog> findByOperationType(
|
||||
@Parameter(description = "操作类型") @PathVariable String operationType) {
|
||||
return auditLogService.findByOperationType(operationType);
|
||||
}
|
||||
|
||||
@GetMapping("/time-range")
|
||||
@Operation(summary = "按时间范围查询", description = "根据时间范围查询审计日志")
|
||||
public Flux<AuditLog> findByTimeRange(
|
||||
@Parameter(description = "开始时间") @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime startTime,
|
||||
@Parameter(description = "结束时间") @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime endTime) {
|
||||
return auditLogService.findByOperationTimeBetween(startTime, endTime);
|
||||
}
|
||||
|
||||
@GetMapping("/statistics")
|
||||
@Operation(summary = "审计日志统计", description = "获取审计日志的统计信息")
|
||||
public Mono<AuditLogStatistics> getStatistics() {
|
||||
AuditLogStatistics statistics = new AuditLogStatistics();
|
||||
|
||||
return Mono.just(statistics);
|
||||
}
|
||||
|
||||
@GetMapping("/count/entity-type/{entityType}")
|
||||
@Operation(summary = "按实体类型统计", description = "统计指定实体类型的审计日志数量")
|
||||
public Mono<Long> countByEntityType(
|
||||
@Parameter(description = "实体类型") @PathVariable String entityType) {
|
||||
return auditLogService.countByEntityType(entityType);
|
||||
}
|
||||
|
||||
@GetMapping("/count/operator/{operator}")
|
||||
@Operation(summary = "按操作人统计", description = "统计指定操作人的审计日志数量")
|
||||
public Mono<Long> countByOperator(
|
||||
@Parameter(description = "操作人") @PathVariable String operator) {
|
||||
return auditLogService.countByOperator(operator);
|
||||
}
|
||||
|
||||
@GetMapping("/count/operation-type/{operationType}")
|
||||
@Operation(summary = "按操作类型统计", description = "统计指定操作类型的审计日志数量")
|
||||
public Mono<Long> countByOperationType(
|
||||
@Parameter(description = "操作类型") @PathVariable String operationType) {
|
||||
return auditLogService.countByOperationType(operationType);
|
||||
}
|
||||
}
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
package cn.novalon.gym.manage.sys.audit.domain;
|
||||
|
||||
import cn.novalon.gym.manage.sys.core.domain.BaseDomain;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 审计日志领域对象
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-04-01
|
||||
*/
|
||||
@Schema(description = "审计日志实体")
|
||||
public class AuditLog extends BaseDomain {
|
||||
|
||||
@Schema(description = "实体类型(如User, Role等)", example = "User")
|
||||
private String entityType;
|
||||
|
||||
@Schema(description = "实体ID", example = "1")
|
||||
private Long entityId;
|
||||
|
||||
@Schema(description = "操作类型(CREATE, UPDATE, DELETE)", example = "UPDATE")
|
||||
private String operationType;
|
||||
|
||||
@Schema(description = "操作人", example = "admin")
|
||||
private String operator;
|
||||
|
||||
@Schema(description = "操作时间")
|
||||
private LocalDateTime operationTime;
|
||||
|
||||
@Schema(description = "变更前数据(JSON格式)")
|
||||
private String beforeData;
|
||||
|
||||
@Schema(description = "变更后数据(JSON格式)")
|
||||
private String afterData;
|
||||
|
||||
@Schema(description = "变更字段列表")
|
||||
private String[] changedFields;
|
||||
|
||||
@Schema(description = "IP地址", example = "192.168.1.100")
|
||||
private String ipAddress;
|
||||
|
||||
@Schema(description = "用户代理")
|
||||
private String userAgent;
|
||||
|
||||
@Schema(description = "操作描述", example = "更新用户信息")
|
||||
private String description;
|
||||
|
||||
public AuditLog() {
|
||||
this.operationTime = LocalDateTime.now();
|
||||
}
|
||||
|
||||
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 LocalDateTime getOperationTime() {
|
||||
return operationTime;
|
||||
}
|
||||
|
||||
public void setOperationTime(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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
if (!super.equals(o)) return false;
|
||||
AuditLog auditLog = (AuditLog) o;
|
||||
return java.util.Objects.equals(entityType, auditLog.entityType) &&
|
||||
java.util.Objects.equals(entityId, auditLog.entityId) &&
|
||||
java.util.Objects.equals(operationType, auditLog.operationType) &&
|
||||
java.util.Objects.equals(operator, auditLog.operator) &&
|
||||
java.util.Objects.equals(operationTime, auditLog.operationTime) &&
|
||||
java.util.Objects.equals(beforeData, auditLog.beforeData) &&
|
||||
java.util.Objects.equals(afterData, auditLog.afterData) &&
|
||||
java.util.Arrays.equals(changedFields, auditLog.changedFields) &&
|
||||
java.util.Objects.equals(ipAddress, auditLog.ipAddress) &&
|
||||
java.util.Objects.equals(userAgent, auditLog.userAgent) &&
|
||||
java.util.Objects.equals(description, auditLog.description);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return java.util.Objects.hash(super.hashCode(), entityType, entityId, operationType, operator,
|
||||
operationTime, beforeData, afterData, java.util.Arrays.hashCode(changedFields),
|
||||
ipAddress, userAgent, description);
|
||||
}
|
||||
}
|
||||
+187
@@ -0,0 +1,187 @@
|
||||
package cn.novalon.gym.manage.sys.audit.domain;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* 审计日志归档实体
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-04-01
|
||||
*/
|
||||
@Table("audit_log_archive")
|
||||
@Schema(description = "审计日志归档实体")
|
||||
public class AuditLogArchive {
|
||||
|
||||
@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;
|
||||
|
||||
@Column("archived_at")
|
||||
@Schema(description = "归档时间")
|
||||
private LocalDateTime archivedAt;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
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 LocalDateTime getOperationTime() {
|
||||
return operationTime;
|
||||
}
|
||||
|
||||
public void setOperationTime(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;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public void setCreatedAt(LocalDateTime createdAt) {
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
|
||||
public LocalDateTime getArchivedAt() {
|
||||
return archivedAt;
|
||||
}
|
||||
|
||||
public void setArchivedAt(LocalDateTime archivedAt) {
|
||||
this.archivedAt = archivedAt;
|
||||
}
|
||||
}
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
package cn.novalon.gym.manage.sys.audit.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 审计日志查询请求
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-04-01
|
||||
*/
|
||||
@Schema(description = "审计日志查询请求")
|
||||
public class AuditLogQueryRequest {
|
||||
|
||||
@Schema(description = "实体类型", example = "User")
|
||||
private String entityType;
|
||||
|
||||
@Schema(description = "实体ID", example = "1")
|
||||
private Long entityId;
|
||||
|
||||
@Schema(description = "操作类型", example = "UPDATE")
|
||||
private String operationType;
|
||||
|
||||
@Schema(description = "操作人", example = "admin")
|
||||
private String operator;
|
||||
|
||||
@Schema(description = "开始时间")
|
||||
private LocalDateTime startTime;
|
||||
|
||||
@Schema(description = "结束时间")
|
||||
private LocalDateTime endTime;
|
||||
|
||||
@Schema(description = "页码", example = "1")
|
||||
private Integer page = 1;
|
||||
|
||||
@Schema(description = "每页大小", example = "20")
|
||||
private Integer size = 20;
|
||||
|
||||
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 LocalDateTime getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
|
||||
public void setStartTime(LocalDateTime startTime) {
|
||||
this.startTime = startTime;
|
||||
}
|
||||
|
||||
public LocalDateTime getEndTime() {
|
||||
return endTime;
|
||||
}
|
||||
|
||||
public void setEndTime(LocalDateTime endTime) {
|
||||
this.endTime = endTime;
|
||||
}
|
||||
|
||||
public Integer getPage() {
|
||||
return page;
|
||||
}
|
||||
|
||||
public void setPage(Integer page) {
|
||||
this.page = page;
|
||||
}
|
||||
|
||||
public Integer getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public void setSize(Integer size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
AuditLogQueryRequest that = (AuditLogQueryRequest) o;
|
||||
return java.util.Objects.equals(entityType, that.entityType) &&
|
||||
java.util.Objects.equals(entityId, that.entityId) &&
|
||||
java.util.Objects.equals(operationType, that.operationType) &&
|
||||
java.util.Objects.equals(operator, that.operator) &&
|
||||
java.util.Objects.equals(startTime, that.startTime) &&
|
||||
java.util.Objects.equals(endTime, that.endTime) &&
|
||||
java.util.Objects.equals(page, that.page) &&
|
||||
java.util.Objects.equals(size, that.size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return java.util.Objects.hash(entityType, entityId, operationType, operator, startTime, endTime, page, size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AuditLogQueryRequest{" +
|
||||
"entityType='" + entityType + '\'' +
|
||||
", entityId=" + entityId +
|
||||
", operationType='" + operationType + '\'' +
|
||||
", operator='" + operator + '\'' +
|
||||
", startTime=" + startTime +
|
||||
", endTime=" + endTime +
|
||||
", page=" + page +
|
||||
", size=" + size +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package cn.novalon.gym.manage.sys.audit.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 审计日志统计信息
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-04-01
|
||||
*/
|
||||
@Schema(description = "审计日志统计信息")
|
||||
public class AuditLogStatistics {
|
||||
|
||||
@Schema(description = "总记录数")
|
||||
private Long totalCount;
|
||||
|
||||
@Schema(description = "按实体类型统计")
|
||||
private Map<String, Long> countByEntityType;
|
||||
|
||||
@Schema(description = "按操作类型统计")
|
||||
private Map<String, Long> countByOperationType;
|
||||
|
||||
@Schema(description = "按操作人统计")
|
||||
private Map<String, Long> countByOperator;
|
||||
|
||||
public Long getTotalCount() {
|
||||
return totalCount;
|
||||
}
|
||||
|
||||
public void setTotalCount(Long totalCount) {
|
||||
this.totalCount = totalCount;
|
||||
}
|
||||
|
||||
public Map<String, Long> getCountByEntityType() {
|
||||
return countByEntityType;
|
||||
}
|
||||
|
||||
public void setCountByEntityType(Map<String, Long> countByEntityType) {
|
||||
this.countByEntityType = countByEntityType;
|
||||
}
|
||||
|
||||
public Map<String, Long> getCountByOperationType() {
|
||||
return countByOperationType;
|
||||
}
|
||||
|
||||
public void setCountByOperationType(Map<String, Long> countByOperationType) {
|
||||
this.countByOperationType = countByOperationType;
|
||||
}
|
||||
|
||||
public Map<String, Long> getCountByOperator() {
|
||||
return countByOperator;
|
||||
}
|
||||
|
||||
public void setCountByOperator(Map<String, Long> countByOperator) {
|
||||
this.countByOperator = countByOperator;
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package cn.novalon.gym.manage.sys.audit.repository;
|
||||
|
||||
import cn.novalon.gym.manage.sys.audit.domain.AuditLogArchive;
|
||||
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-01
|
||||
*/
|
||||
@Repository
|
||||
public interface IAuditLogArchiveRepository extends R2dbcRepository<AuditLogArchive, Long> {
|
||||
|
||||
Flux<AuditLogArchive> findByEntityType(String entityType);
|
||||
|
||||
Flux<AuditLogArchive> findByEntityId(Long entityId);
|
||||
|
||||
Flux<AuditLogArchive> findByOperator(String operator);
|
||||
|
||||
Flux<AuditLogArchive> findByOperationTimeBetween(LocalDateTime startTime, LocalDateTime endTime);
|
||||
|
||||
Flux<AuditLogArchive> findByArchivedAtBetween(LocalDateTime startTime, LocalDateTime endTime);
|
||||
|
||||
Mono<Long> countByEntityType(String entityType);
|
||||
|
||||
Mono<Long> countByOperator(String operator);
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
package cn.novalon.gym.manage.sys.audit.repository;
|
||||
|
||||
import cn.novalon.gym.manage.sys.audit.domain.AuditLog;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 审计日志仓储接口
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-04-01
|
||||
*/
|
||||
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);
|
||||
|
||||
Flux<AuditLog> findByEntityId(Long entityId);
|
||||
|
||||
Flux<AuditLog> findByEntityTypeAndEntityId(String entityType, Long entityId);
|
||||
|
||||
Flux<AuditLog> findByOperator(String operator);
|
||||
|
||||
Flux<AuditLog> findByOperationType(String operationType);
|
||||
|
||||
Flux<AuditLog> findByOperationTimeBetween(LocalDateTime startTime, LocalDateTime endTime);
|
||||
|
||||
Flux<AuditLog> findByEntityTypeAndOperationTimeBetween(
|
||||
String entityType,
|
||||
LocalDateTime startTime,
|
||||
LocalDateTime endTime
|
||||
);
|
||||
|
||||
Flux<AuditLog> findByOperatorAndOperationTimeBetween(
|
||||
String operator,
|
||||
LocalDateTime startTime,
|
||||
LocalDateTime endTime
|
||||
);
|
||||
|
||||
Mono<Long> countByEntityType(String entityType);
|
||||
|
||||
Mono<Long> countByOperationType(String operationType);
|
||||
|
||||
Mono<Long> countByOperator(String operator);
|
||||
|
||||
Mono<Long> countByOperationTimeBetween(LocalDateTime startTime, LocalDateTime endTime);
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package cn.novalon.gym.manage.sys.audit.scheduler;
|
||||
|
||||
import cn.novalon.gym.manage.sys.audit.service.IAuditLogArchiveService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 审计日志归档定时任务
|
||||
*
|
||||
* 文件定义:定时执行审计日志归档任务
|
||||
* 涉及业务:定期将历史审计日志移动到归档表
|
||||
* 算法:使用Spring Scheduler定时执行归档任务
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-04-01
|
||||
*/
|
||||
@Component
|
||||
public class AuditLogArchiveScheduler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AuditLogArchiveScheduler.class);
|
||||
|
||||
private final IAuditLogArchiveService auditLogArchiveService;
|
||||
|
||||
public AuditLogArchiveScheduler(IAuditLogArchiveService auditLogArchiveService) {
|
||||
this.auditLogArchiveService = auditLogArchiveService;
|
||||
}
|
||||
|
||||
@Scheduled(cron = "0 0 2 * * ?")
|
||||
public void archiveOldLogs() {
|
||||
logger.info("开始执行审计日志归档定时任务");
|
||||
|
||||
int daysToKeep = 30;
|
||||
|
||||
auditLogArchiveService.archiveOldLogs(daysToKeep)
|
||||
.subscribe(
|
||||
count -> logger.info("审计日志归档定时任务完成,共归档 {} 条记录", count),
|
||||
error -> logger.error("审计日志归档定时任务失败: {}", error.getMessage())
|
||||
);
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
package cn.novalon.gym.manage.sys.audit.service;
|
||||
|
||||
import cn.novalon.gym.manage.sys.audit.domain.AuditLog;
|
||||
import cn.novalon.gym.manage.sys.audit.domain.AuditLogArchive;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 审计日志归档服务接口
|
||||
*
|
||||
* 文件定义:定义审计日志归档的业务逻辑接口
|
||||
* 涉及业务:审计日志的归档、查询、清理等操作
|
||||
* 算法:定期将历史审计日志移动到归档表
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-04-14
|
||||
*/
|
||||
public interface IAuditLogArchiveService {
|
||||
|
||||
Mono<Long> archiveOldLogs(int daysToKeep);
|
||||
|
||||
Mono<AuditLogArchive> archiveLog(AuditLog auditLog);
|
||||
|
||||
Flux<AuditLogArchive> findArchivedLogsByDateRange(LocalDateTime startDate, LocalDateTime endDate);
|
||||
|
||||
Flux<AuditLogArchive> findArchivedLogsByEntityType(String entityType);
|
||||
|
||||
Mono<AuditLogArchive> findArchivedLogById(Long id);
|
||||
|
||||
Mono<Long> countArchivedLogs();
|
||||
|
||||
Mono<Long> countArchivedLogsByDateRange(LocalDateTime startDate, LocalDateTime endDate);
|
||||
|
||||
Mono<Void> deleteArchivedLogsOlderThan(LocalDateTime date);
|
||||
|
||||
Mono<Long> getArchiveStatistics();
|
||||
|
||||
Mono<Boolean> isLogArchived(Long auditLogId);
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
package cn.novalon.gym.manage.sys.audit.service;
|
||||
|
||||
import cn.novalon.gym.manage.sys.audit.domain.AuditLog;
|
||||
import cn.novalon.gym.manage.common.dto.PageRequest;
|
||||
import cn.novalon.gym.manage.common.dto.PageResponse;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 审计日志服务接口
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-04-08
|
||||
*/
|
||||
public interface IAuditLogService {
|
||||
|
||||
Mono<AuditLog> findById(Long id);
|
||||
|
||||
Flux<AuditLog> findAll();
|
||||
|
||||
Flux<AuditLog> findAll(boolean includeDeleted);
|
||||
|
||||
Mono<PageResponse<AuditLog>> findAuditLogsByPage(PageRequest pageRequest);
|
||||
|
||||
Mono<Long> count();
|
||||
|
||||
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);
|
||||
|
||||
Flux<AuditLog> findByOperationTimeBetween(LocalDateTime startTime, LocalDateTime endTime);
|
||||
|
||||
Flux<AuditLog> findByEntityTypeAndOperationTimeBetween(String entityType, LocalDateTime startTime,
|
||||
LocalDateTime endTime);
|
||||
|
||||
Flux<AuditLog> findByOperatorAndOperationTimeBetween(String operator, LocalDateTime startTime,
|
||||
LocalDateTime endTime);
|
||||
|
||||
Mono<Long> countByEntityType(String entityType);
|
||||
|
||||
Mono<Long> countByOperationType(String operationType);
|
||||
|
||||
Mono<Long> countByOperator(String operator);
|
||||
|
||||
Mono<Long> countByOperationTimeBetween(LocalDateTime startTime, LocalDateTime endTime);
|
||||
|
||||
Mono<AuditLog> save(AuditLog auditLog);
|
||||
|
||||
Mono<AuditLog> saveAsync(AuditLog auditLog);
|
||||
|
||||
Mono<Void> deleteById(Long id);
|
||||
|
||||
Mono<Void> logicalDeleteById(Long id);
|
||||
|
||||
Mono<Void> logicalDeleteByIds(List<Long> ids);
|
||||
|
||||
Mono<Void> restoreById(Long id);
|
||||
|
||||
Mono<Void> restoreByIds(List<Long> ids);
|
||||
}
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
package cn.novalon.gym.manage.sys.audit.service.impl;
|
||||
|
||||
import cn.novalon.gym.manage.sys.audit.domain.AuditLog;
|
||||
import cn.novalon.gym.manage.sys.audit.domain.AuditLogArchive;
|
||||
import cn.novalon.gym.manage.sys.audit.repository.IAuditLogArchiveRepository;
|
||||
import cn.novalon.gym.manage.sys.audit.repository.IAuditLogRepository;
|
||||
import cn.novalon.gym.manage.sys.audit.service.IAuditLogArchiveService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 审计日志归档服务实现类
|
||||
*
|
||||
* 文件定义:实现审计日志归档的业务逻辑
|
||||
* 涉及业务:审计日志的归档、查询、清理等操作
|
||||
* 算法:定期将历史审计日志移动到归档表
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-04-14
|
||||
*/
|
||||
@Service
|
||||
public class AuditLogArchiveService implements IAuditLogArchiveService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AuditLogArchiveService.class);
|
||||
|
||||
private final IAuditLogRepository auditLogRepository;
|
||||
private final IAuditLogArchiveRepository auditLogArchiveRepository;
|
||||
|
||||
public AuditLogArchiveService(IAuditLogRepository auditLogRepository,
|
||||
IAuditLogArchiveRepository auditLogArchiveRepository) {
|
||||
this.auditLogRepository = auditLogRepository;
|
||||
this.auditLogArchiveRepository = auditLogArchiveRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Mono<Long> archiveOldLogs(int daysToKeep) {
|
||||
LocalDateTime archiveBefore = LocalDateTime.now().minusDays(daysToKeep);
|
||||
|
||||
logger.info("开始归档审计日志,归档时间点: {}", archiveBefore);
|
||||
|
||||
return auditLogRepository.findByOperationTimeBetween(LocalDateTime.MIN, archiveBefore)
|
||||
.flatMap(this::archiveLog)
|
||||
.count()
|
||||
.doOnSuccess(count -> logger.info("归档完成,共归档 {} 条日志", count))
|
||||
.doOnError(error -> logger.error("归档失败: {}", error.getMessage()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Mono<AuditLogArchive> archiveLog(AuditLog auditLog) {
|
||||
AuditLogArchive archive = convertToArchive(auditLog);
|
||||
|
||||
return auditLogArchiveRepository.save(archive)
|
||||
.doOnSuccess(saved -> {
|
||||
logger.debug("审计日志归档成功: ID={}, 操作类型={}",
|
||||
saved.getId(), saved.getOperationType());
|
||||
|
||||
auditLogRepository.deleteById(auditLog.getId())
|
||||
.doOnSuccess(v -> logger.debug("原始日志删除成功: ID={}", auditLog.getId()))
|
||||
.doOnError(error -> logger.error("原始日志删除失败: ID={}, {}",
|
||||
auditLog.getId(), error.getMessage()))
|
||||
.subscribe();
|
||||
})
|
||||
.doOnError(error -> logger.error("审计日志归档失败: ID={}, {}",
|
||||
auditLog.getId(), error.getMessage()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<AuditLogArchive> findArchivedLogsByDateRange(LocalDateTime startDate, LocalDateTime endDate) {
|
||||
return auditLogArchiveRepository.findByOperationTimeBetween(startDate, endDate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<AuditLogArchive> findArchivedLogsByEntityType(String entityType) {
|
||||
return auditLogArchiveRepository.findByEntityType(entityType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<AuditLogArchive> findArchivedLogById(Long id) {
|
||||
return auditLogArchiveRepository.findById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Long> countArchivedLogs() {
|
||||
return auditLogArchiveRepository.count();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Long> countArchivedLogsByDateRange(LocalDateTime startDate, LocalDateTime endDate) {
|
||||
return auditLogArchiveRepository.findByOperationTimeBetween(startDate, endDate)
|
||||
.count();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Mono<Void> deleteArchivedLogsOlderThan(LocalDateTime date) {
|
||||
return auditLogArchiveRepository.findByOperationTimeBetween(LocalDateTime.MIN, date)
|
||||
.flatMap(archive -> auditLogArchiveRepository.deleteById(archive.getId()))
|
||||
.then()
|
||||
.doOnSuccess(v -> logger.info("删除早于 {} 的归档日志完成", date))
|
||||
.doOnError(error -> logger.error("删除归档日志失败: {}", error.getMessage()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Long> getArchiveStatistics() {
|
||||
return auditLogArchiveRepository.count()
|
||||
.doOnNext(count -> logger.info("归档日志统计: {} 条记录", count));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Boolean> isLogArchived(Long auditLogId) {
|
||||
return auditLogArchiveRepository.findAll()
|
||||
.filter(archive -> archive.getEntityId() != null && archive.getEntityId().equals(auditLogId))
|
||||
.hasElements()
|
||||
.doOnNext(archived -> logger.debug("日志 ID={} 是否已归档: {}", auditLogId, archived));
|
||||
}
|
||||
|
||||
private AuditLogArchive convertToArchive(AuditLog auditLog) {
|
||||
AuditLogArchive archive = new AuditLogArchive();
|
||||
archive.setEntityType(auditLog.getEntityType());
|
||||
archive.setEntityId(auditLog.getEntityId());
|
||||
archive.setOperationType(auditLog.getOperationType());
|
||||
archive.setOperator(auditLog.getOperator());
|
||||
archive.setOperationTime(auditLog.getOperationTime());
|
||||
archive.setIpAddress(auditLog.getIpAddress());
|
||||
archive.setUserAgent(auditLog.getUserAgent());
|
||||
archive.setArchivedAt(LocalDateTime.now());
|
||||
|
||||
if (auditLog.getDescription() != null) {
|
||||
archive.setDescription(auditLog.getDescription());
|
||||
}
|
||||
|
||||
return archive;
|
||||
}
|
||||
}
|
||||
+206
@@ -0,0 +1,206 @@
|
||||
package cn.novalon.gym.manage.sys.audit.service.impl;
|
||||
|
||||
import cn.novalon.gym.manage.sys.audit.domain.AuditLog;
|
||||
import cn.novalon.gym.manage.sys.audit.repository.IAuditLogRepository;
|
||||
import cn.novalon.gym.manage.sys.audit.service.IAuditLogService;
|
||||
import cn.novalon.gym.manage.common.dto.PageRequest;
|
||||
import cn.novalon.gym.manage.common.dto.PageResponse;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.core.scheduler.Schedulers;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* 审计日志服务实现类
|
||||
*
|
||||
* 文件定义:实现审计日志管理的核心业务逻辑
|
||||
* 涉及业务:审计日志的保存、查询、统计、删除等操作
|
||||
* 算法:使用R2DBC进行响应式数据库操作,支持分页查询、条件查询、批量操作
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-04-08
|
||||
*/
|
||||
@Service
|
||||
public class AuditLogService implements IAuditLogService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AuditLogService.class);
|
||||
|
||||
private final IAuditLogRepository auditLogRepository;
|
||||
private final Executor auditLogExecutor;
|
||||
|
||||
public AuditLogService(IAuditLogRepository auditLogRepository,
|
||||
Executor auditLogExecutor) {
|
||||
this.auditLogRepository = auditLogRepository;
|
||||
this.auditLogExecutor = auditLogExecutor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<AuditLog> findById(Long id) {
|
||||
return auditLogRepository.findById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<AuditLog> findAll() {
|
||||
return auditLogRepository.findAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<AuditLog> findAll(boolean includeDeleted) {
|
||||
if (includeDeleted) {
|
||||
return auditLogRepository.findAll();
|
||||
} else {
|
||||
return auditLogRepository.findAll();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<PageResponse<AuditLog>> findAuditLogsByPage(PageRequest pageRequest) {
|
||||
return auditLogRepository.findAll()
|
||||
.collectList()
|
||||
.map(auditLogs -> {
|
||||
int total = auditLogs.size();
|
||||
int pageSize = pageRequest.getSize();
|
||||
int pageNumber = pageRequest.getPage();
|
||||
int fromIndex = pageNumber * pageSize;
|
||||
int toIndex = Math.min(fromIndex + pageSize, total);
|
||||
|
||||
List<AuditLog> pageContent = auditLogs.subList(fromIndex, toIndex);
|
||||
int totalPages = (int) Math.ceil((double) total / pageSize);
|
||||
return new PageResponse<>(pageContent, totalPages, total, pageNumber, pageSize);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Long> count() {
|
||||
return auditLogRepository.findAll()
|
||||
.count();
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<AuditLog> findByOperationTimeBetween(LocalDateTime startTime, LocalDateTime endTime) {
|
||||
return auditLogRepository.findByOperationTimeBetween(startTime, endTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<AuditLog> findByEntityTypeAndOperationTimeBetween(String entityType, LocalDateTime startTime, LocalDateTime endTime) {
|
||||
return auditLogRepository.findByEntityTypeAndOperationTimeBetween(entityType, startTime, endTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<AuditLog> findByOperatorAndOperationTimeBetween(String operator, LocalDateTime startTime, LocalDateTime endTime) {
|
||||
return auditLogRepository.findByOperatorAndOperationTimeBetween(operator, startTime, endTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Long> countByEntityType(String entityType) {
|
||||
return auditLogRepository.countByEntityType(entityType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Long> countByOperationType(String operationType) {
|
||||
return auditLogRepository.countByOperationType(operationType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Long> countByOperator(String operator) {
|
||||
return auditLogRepository.countByOperator(operator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Long> countByOperationTimeBetween(LocalDateTime startTime, LocalDateTime endTime) {
|
||||
return auditLogRepository.countByOperationTimeBetween(startTime, endTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<AuditLog> save(AuditLog auditLog) {
|
||||
return auditLogRepository.save(auditLog);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Async("auditLogExecutor")
|
||||
public Mono<AuditLog> saveAsync(AuditLog auditLog) {
|
||||
logger.debug("异步保存审计日志: {} - {}", auditLog.getEntityType(), auditLog.getOperationType());
|
||||
|
||||
return auditLogRepository.save(auditLog)
|
||||
.doOnSuccess(saved -> logger.debug("审计日志保存成功: ID={}", saved.getId()))
|
||||
.doOnError(error -> logger.error("审计日志保存失败: {}", error.getMessage()))
|
||||
.subscribeOn(Schedulers.fromExecutor(auditLogExecutor));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Mono<Void> deleteById(Long id) {
|
||||
return auditLogRepository.deleteById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Mono<Void> logicalDeleteById(Long id) {
|
||||
return auditLogRepository.findById(id)
|
||||
.flatMap(auditLog -> {
|
||||
auditLog.setDeletedAt(LocalDateTime.now());
|
||||
return auditLogRepository.save(auditLog);
|
||||
})
|
||||
.then();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Mono<Void> logicalDeleteByIds(List<Long> ids) {
|
||||
return Flux.fromIterable(ids)
|
||||
.flatMap(this::logicalDeleteById)
|
||||
.then();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Mono<Void> restoreById(Long id) {
|
||||
return auditLogRepository.findById(id)
|
||||
.flatMap(auditLog -> {
|
||||
auditLog.setDeletedAt(null);
|
||||
return auditLogRepository.save(auditLog);
|
||||
})
|
||||
.then();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Mono<Void> restoreByIds(List<Long> ids) {
|
||||
return Flux.fromIterable(ids)
|
||||
.flatMap(this::restoreById)
|
||||
.then();
|
||||
}
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
package cn.novalon.gym.manage.sys.config;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.annotation.AsyncConfigurer;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* 异步配置类
|
||||
*
|
||||
* 文件定义:配置异步线程池,用于审计日志等异步处理
|
||||
* 涉及业务:提供统一的异步处理能力
|
||||
* 算法:使用ThreadPoolTaskExecutor管理线程池
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-04-01
|
||||
*/
|
||||
@Configuration
|
||||
@EnableAsync
|
||||
public class AsyncConfig implements AsyncConfigurer {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AsyncConfig.class);
|
||||
|
||||
@Bean(name = "auditLogExecutor")
|
||||
@Override
|
||||
public Executor getAsyncExecutor() {
|
||||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||
|
||||
executor.setCorePoolSize(5);
|
||||
executor.setMaxPoolSize(10);
|
||||
executor.setQueueCapacity(100);
|
||||
executor.setKeepAliveSeconds(60);
|
||||
executor.setThreadNamePrefix("audit-log-");
|
||||
|
||||
executor.setRejectedExecutionHandler((r, exec) -> {
|
||||
logger.warn("审计日志线程池已满,任务被拒绝,将降级为同步处理");
|
||||
if (!exec.isShutdown()) {
|
||||
r.run();
|
||||
}
|
||||
});
|
||||
|
||||
executor.setWaitForTasksToCompleteOnShutdown(true);
|
||||
executor.setAwaitTerminationSeconds(60);
|
||||
|
||||
executor.initialize();
|
||||
|
||||
logger.info("审计日志异步线程池初始化完成: corePoolSize={}, maxPoolSize={}, queueCapacity={}",
|
||||
executor.getCorePoolSize(), executor.getMaxPoolSize(), executor.getQueueCapacity());
|
||||
|
||||
return executor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
|
||||
return (throwable, method, params) -> {
|
||||
logger.error("异步任务执行异常 - 方法: {}, 参数: {}, 异常: {}",
|
||||
method.getName(), params, throwable.getMessage(), throwable);
|
||||
};
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package cn.novalon.gym.manage.sys.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.domain.ReactiveAuditorAware;
|
||||
import org.springframework.data.r2dbc.config.EnableR2dbcAuditing;
|
||||
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
|
||||
|
||||
/**
|
||||
* R2DBC审计配置类
|
||||
*
|
||||
* 文件定义:启用Spring Data R2DBC的审计功能,自动填充创建人、修改人等字段
|
||||
* 涉及业务:用户操作审计、数据变更追踪
|
||||
* 算法:使用ReactiveSecurityContextHolder获取当前认证用户
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-04-01
|
||||
*/
|
||||
@Configuration
|
||||
@EnableR2dbcAuditing(auditorAwareRef = "reactiveAuditorAware")
|
||||
public class AuditingConfig {
|
||||
|
||||
@Bean
|
||||
public ReactiveAuditorAware<String> reactiveAuditorAware() {
|
||||
return () -> ReactiveSecurityContextHolder.getContext()
|
||||
.map(securityContext -> securityContext.getAuthentication())
|
||||
.map(authentication -> {
|
||||
Object principal = authentication.getPrincipal();
|
||||
return principal instanceof String ? (String) principal : "system";
|
||||
})
|
||||
.defaultIfEmpty("system");
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
package cn.novalon.gym.manage.sys.config;
|
||||
|
||||
import cn.novalon.gym.manage.sys.core.service.impl.SysExceptionLogService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.reactive.function.server.RouterFunction;
|
||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
|
||||
import static org.springframework.web.reactive.function.server.RequestPredicates.*;
|
||||
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
|
||||
|
||||
/**
|
||||
* 异常日志配置类
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-04-15
|
||||
*/
|
||||
@Configuration
|
||||
public class ExceptionLogConfig {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ExceptionLogConfig.class);
|
||||
|
||||
/**
|
||||
* 配置异常日志的路由
|
||||
*/
|
||||
@Bean
|
||||
public RouterFunction<ServerResponse> exceptionLogRoutes(SysExceptionLogService exceptionLogService) {
|
||||
logger.info("配置异常日志路由");
|
||||
|
||||
return route()
|
||||
.GET("/api/exception-logs", request ->
|
||||
ServerResponse.ok().body(exceptionLogService.findAll(), cn.novalon.gym.manage.sys.core.domain.SysExceptionLog.class))
|
||||
.GET("/api/exception-logs/{id}", request -> {
|
||||
Long id = Long.valueOf(request.pathVariable("id"));
|
||||
return exceptionLogService.findById(id)
|
||||
.flatMap(log -> ServerResponse.ok().bodyValue(log))
|
||||
.switchIfEmpty(ServerResponse.notFound().build());
|
||||
})
|
||||
.GET("/api/exception-logs/username/{username}", request -> {
|
||||
String username = request.pathVariable("username");
|
||||
return ServerResponse.ok().body(exceptionLogService.findByUsername(username),
|
||||
cn.novalon.gym.manage.sys.core.domain.SysExceptionLog.class);
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package cn.novalon.gym.manage.sys.config;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
|
||||
/**
|
||||
* 密码编码器配置
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-26
|
||||
*/
|
||||
@Configuration
|
||||
public class PasswordEncoderConfig {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PasswordEncoderConfig.class);
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(12);
|
||||
logger.info("创建主密码编码器: BCryptPasswordEncoder(strength=12), 类型: {}", encoder.getClass().getName());
|
||||
return encoder;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
logger.info("PasswordEncoderConfig 已加载");
|
||||
}
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
package cn.novalon.gym.manage.sys.config;
|
||||
|
||||
import cn.novalon.gym.manage.sys.security.JwtAuthenticationFilter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
|
||||
import org.springframework.security.config.web.server.SecurityWebFiltersOrder;
|
||||
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
||||
import org.springframework.security.web.server.SecurityWebFilterChain;
|
||||
|
||||
/**
|
||||
* 安全配置类
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
@Configuration
|
||||
@EnableWebFluxSecurity
|
||||
public class SecurityConfig {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SecurityConfig.class);
|
||||
private final JwtAuthenticationFilter jwtAuthenticationFilter;
|
||||
private final Environment environment;
|
||||
|
||||
public SecurityConfig(JwtAuthenticationFilter jwtAuthenticationFilter, Environment environment) {
|
||||
this.jwtAuthenticationFilter = jwtAuthenticationFilter;
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
|
||||
String[] activeProfiles = environment.getActiveProfiles();
|
||||
final boolean isDevOrTest;
|
||||
|
||||
isDevOrTest = java.util.Arrays.stream(activeProfiles)
|
||||
.anyMatch(profile -> "dev".equals(profile) || "test".equals(profile) || "h2-test".equals(profile));
|
||||
|
||||
logger.info("SecurityConfig初始化: 当前环境={}, Swagger启用状态={}",
|
||||
activeProfiles.length > 0 ? String.join(",", activeProfiles) : "default", isDevOrTest);
|
||||
|
||||
http
|
||||
.csrf(ServerHttpSecurity.CsrfSpec::disable)
|
||||
.httpBasic(ServerHttpSecurity.HttpBasicSpec::disable)
|
||||
.formLogin(ServerHttpSecurity.FormLoginSpec::disable)
|
||||
.addFilterBefore(jwtAuthenticationFilter, SecurityWebFiltersOrder.AUTHENTICATION)
|
||||
.authorizeExchange(spec -> {
|
||||
spec.pathMatchers("/api/auth/**").permitAll()
|
||||
.pathMatchers("/api/public/**").permitAll()
|
||||
.pathMatchers("/ws/**").permitAll()
|
||||
.pathMatchers("/actuator/**").permitAll();
|
||||
|
||||
if (isDevOrTest) {
|
||||
spec.pathMatchers("/swagger-ui.html").permitAll()
|
||||
.pathMatchers("/swagger-ui/**").permitAll()
|
||||
.pathMatchers("/api-docs/**").permitAll()
|
||||
.pathMatchers("/v3/api-docs/**").permitAll()
|
||||
.pathMatchers("/swagger-resources/**").permitAll()
|
||||
.pathMatchers("/webjars/**").permitAll()
|
||||
.pathMatchers("/api/diagnostic/**").permitAll();
|
||||
logger.info("SecurityConfig: Swagger路径和诊断端点已放行");
|
||||
}
|
||||
|
||||
spec.anyExchange().authenticated();
|
||||
});
|
||||
|
||||
return http.build();
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package cn.novalon.gym.manage.sys.core.command;
|
||||
|
||||
/**
|
||||
* 创建菜单命令对象
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public record CreateMenuCommand(
|
||||
Long parentId,
|
||||
String menuName,
|
||||
String menuType,
|
||||
Integer orderNum,
|
||||
String component,
|
||||
String perms,
|
||||
Integer status) {
|
||||
public static CreateMenuCommand of(Long parentId, String menuName, String menuType, Integer orderNum,
|
||||
String component, String perms, Integer status) {
|
||||
return new CreateMenuCommand(parentId, menuName, menuType, orderNum, component, perms, status);
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package cn.novalon.gym.manage.sys.core.command;
|
||||
|
||||
import cn.novalon.gym.manage.common.exception.ErrorCode;
|
||||
import cn.novalon.gym.manage.common.exception.ValidationException;
|
||||
|
||||
/**
|
||||
* 创建公告命令对象
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public record CreateNoticeCommand(
|
||||
String noticeTitle,
|
||||
String noticeContent,
|
||||
String noticeType,
|
||||
String status) {
|
||||
public static CreateNoticeCommand of(String noticeTitle, String noticeContent, String noticeType, String status) {
|
||||
validateNoticeTitle(noticeTitle);
|
||||
validateNoticeContent(noticeContent);
|
||||
validateNoticeType(noticeType);
|
||||
return new CreateNoticeCommand(noticeTitle, noticeContent, noticeType, status);
|
||||
}
|
||||
|
||||
private static void validateNoticeTitle(String noticeTitle) {
|
||||
if (noticeTitle == null || noticeTitle.trim().isEmpty()) {
|
||||
throw new ValidationException(ErrorCode.VALIDATION_REQUIRED, "Notice title is required");
|
||||
}
|
||||
}
|
||||
|
||||
private static void validateNoticeContent(String noticeContent) {
|
||||
if (noticeContent == null || noticeContent.trim().isEmpty()) {
|
||||
throw new ValidationException(ErrorCode.VALIDATION_REQUIRED, "Notice content is required");
|
||||
}
|
||||
}
|
||||
|
||||
private static void validateNoticeType(String noticeType) {
|
||||
if (noticeType != null && !noticeType.equals("1") && !noticeType.equals("2")) {
|
||||
throw new ValidationException(ErrorCode.VALIDATION_INVALID_VALUE,
|
||||
"Invalid notice type. Notice type must be 1 (notification) or 2 (announcement)");
|
||||
}
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package cn.novalon.gym.manage.sys.core.command;
|
||||
|
||||
import cn.novalon.gym.manage.common.exception.ErrorCode;
|
||||
import cn.novalon.gym.manage.common.exception.ValidationException;
|
||||
import cn.novalon.gym.manage.common.util.StatusConstants;
|
||||
|
||||
/**
|
||||
* 创建角色命令对象
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public record CreateRoleCommand(
|
||||
String roleName,
|
||||
String roleKey,
|
||||
Integer roleSort,
|
||||
Integer status
|
||||
) {
|
||||
public static CreateRoleCommand of(String roleName, String roleKey, Integer roleSort, Integer status) {
|
||||
validateStatus(status);
|
||||
return new CreateRoleCommand(roleName, roleKey, roleSort, status);
|
||||
}
|
||||
|
||||
private static void validateStatus(Integer status) {
|
||||
if (status != null && status != StatusConstants.ENABLED && status != StatusConstants.DISABLED) {
|
||||
throw new ValidationException(ErrorCode.VALIDATION_INVALID_VALUE,
|
||||
"Invalid status value. Status must be 0 (disabled) or 1 (enabled)");
|
||||
}
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package cn.novalon.gym.manage.sys.core.command;
|
||||
|
||||
import cn.novalon.gym.manage.sys.primitive.Email;
|
||||
import cn.novalon.gym.manage.sys.primitive.Password;
|
||||
import cn.novalon.gym.manage.sys.primitive.Username;
|
||||
|
||||
/**
|
||||
* 创建用户命令对象
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public record CreateUserCommand(
|
||||
Username username,
|
||||
Password password,
|
||||
Email email,
|
||||
String nickname,
|
||||
String phone,
|
||||
Long roleId,
|
||||
Integer status
|
||||
) {
|
||||
public static CreateUserCommand of(String username, String password, String email, String nickname, String phone, Long roleId, Integer status) {
|
||||
return new CreateUserCommand(
|
||||
Username.of(username),
|
||||
Password.of(password),
|
||||
Email.of(email),
|
||||
nickname,
|
||||
phone,
|
||||
roleId,
|
||||
status
|
||||
);
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package cn.novalon.gym.manage.sys.core.command;
|
||||
|
||||
/**
|
||||
* 更新菜单命令对象
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public record UpdateMenuCommand(
|
||||
Long id,
|
||||
Long parentId,
|
||||
String menuName,
|
||||
String menuType,
|
||||
Integer orderNum,
|
||||
String component,
|
||||
String perms,
|
||||
Integer status
|
||||
) {
|
||||
public static UpdateMenuCommand of(Long id, Long parentId, String menuName, String menuType, Integer orderNum,
|
||||
String component, String perms, Integer status) {
|
||||
return new UpdateMenuCommand(id, parentId, menuName, menuType, orderNum, component, perms, status);
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package cn.novalon.gym.manage.sys.core.command;
|
||||
|
||||
/**
|
||||
* 更新角色命令对象
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public record UpdateRoleCommand(
|
||||
Long id,
|
||||
String roleName,
|
||||
String roleKey,
|
||||
Integer roleSort,
|
||||
Integer status
|
||||
) {
|
||||
public static UpdateRoleCommand of(Long id, String roleName, String roleKey, Integer roleSort, Integer status) {
|
||||
return new UpdateRoleCommand(id, roleName, roleKey, roleSort, status);
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package cn.novalon.gym.manage.sys.core.command;
|
||||
|
||||
/**
|
||||
* 更新用户命令对象
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public record UpdateUserCommand(
|
||||
Long id,
|
||||
String username,
|
||||
String password,
|
||||
String email,
|
||||
Long roleId,
|
||||
Integer status,
|
||||
boolean clearRole
|
||||
) {
|
||||
public static UpdateUserCommand of(Long id, String username, String password, String email, Long roleId, Integer status) {
|
||||
return new UpdateUserCommand(id, username, password, email, roleId, status, false);
|
||||
}
|
||||
|
||||
public static UpdateUserCommand of(Long id, String username, String password, String email, Long roleId, Integer status, boolean clearRole) {
|
||||
return new UpdateUserCommand(id, username, password, email, roleId, status, clearRole);
|
||||
}
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
package cn.novalon.gym.manage.sys.core.domain;
|
||||
|
||||
import cn.novalon.gym.manage.common.util.SnowflakeId;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 基础领域对象
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public abstract class BaseDomain {
|
||||
|
||||
protected Long id;
|
||||
protected String createBy;
|
||||
protected String updateBy;
|
||||
protected LocalDateTime createdAt;
|
||||
protected LocalDateTime updatedAt;
|
||||
protected LocalDateTime deletedAt;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getCreateBy() {
|
||||
return createBy;
|
||||
}
|
||||
|
||||
public void setCreateBy(String createBy) {
|
||||
this.createBy = createBy;
|
||||
}
|
||||
|
||||
public String getUpdateBy() {
|
||||
return updateBy;
|
||||
}
|
||||
|
||||
public void setUpdateBy(String updateBy) {
|
||||
this.updateBy = updateBy;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public void setCreatedAt(LocalDateTime createdAt) {
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
|
||||
public LocalDateTime getUpdatedAt() {
|
||||
return updatedAt;
|
||||
}
|
||||
|
||||
public void setUpdatedAt(LocalDateTime updatedAt) {
|
||||
this.updatedAt = updatedAt;
|
||||
}
|
||||
|
||||
public LocalDateTime getDeletedAt() {
|
||||
return deletedAt;
|
||||
}
|
||||
|
||||
public void setDeletedAt(LocalDateTime deletedAt) {
|
||||
this.deletedAt = deletedAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成主键ID
|
||||
*
|
||||
* @return 主键ID
|
||||
*/
|
||||
public Long generateId() {
|
||||
this.id = SnowflakeId.nextId();
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
BaseDomain that = (BaseDomain) o;
|
||||
return id != null && id.equals(that.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return id != null ? id.hashCode() : 0;
|
||||
}
|
||||
}
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
package cn.novalon.gym.manage.sys.core.domain;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 字典领域对象
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public class Dictionary {
|
||||
private Long id;
|
||||
private String type;
|
||||
private String code;
|
||||
private String name;
|
||||
private String value;
|
||||
private String remark;
|
||||
private Integer sort;
|
||||
private String createBy;
|
||||
private String updateBy;
|
||||
private LocalDateTime createdAt;
|
||||
private LocalDateTime updatedAt;
|
||||
private LocalDateTime deletedAt;
|
||||
|
||||
public Dictionary() {
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(String code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getRemark() {
|
||||
return remark;
|
||||
}
|
||||
|
||||
public void setRemark(String remark) {
|
||||
this.remark = remark;
|
||||
}
|
||||
|
||||
public Integer getSort() {
|
||||
return sort;
|
||||
}
|
||||
|
||||
public void setSort(Integer sort) {
|
||||
this.sort = sort;
|
||||
}
|
||||
|
||||
public String getCreateBy() {
|
||||
return createBy;
|
||||
}
|
||||
|
||||
public void setCreateBy(String createBy) {
|
||||
this.createBy = createBy;
|
||||
}
|
||||
|
||||
public String getUpdateBy() {
|
||||
return updateBy;
|
||||
}
|
||||
|
||||
public void setUpdateBy(String updateBy) {
|
||||
this.updateBy = updateBy;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public void setCreatedAt(LocalDateTime createdAt) {
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
|
||||
public LocalDateTime getUpdatedAt() {
|
||||
return updatedAt;
|
||||
}
|
||||
|
||||
public void setUpdatedAt(LocalDateTime updatedAt) {
|
||||
this.updatedAt = updatedAt;
|
||||
}
|
||||
|
||||
public LocalDateTime getDeletedAt() {
|
||||
return deletedAt;
|
||||
}
|
||||
|
||||
public void setDeletedAt(LocalDateTime deletedAt) {
|
||||
this.deletedAt = deletedAt;
|
||||
}
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
package cn.novalon.gym.manage.sys.core.domain;
|
||||
|
||||
/**
|
||||
* 操作日志领域对象
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public class OperationLog extends BaseDomain {
|
||||
|
||||
private String username;
|
||||
private String operation;
|
||||
private String method;
|
||||
private String params;
|
||||
private String result;
|
||||
private String ip;
|
||||
private Long duration;
|
||||
private String status;
|
||||
private String errorMsg;
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getOperation() {
|
||||
return operation;
|
||||
}
|
||||
|
||||
public void setOperation(String operation) {
|
||||
this.operation = operation;
|
||||
}
|
||||
|
||||
public String getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public void setMethod(String method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
public String getParams() {
|
||||
return params;
|
||||
}
|
||||
|
||||
public void setParams(String params) {
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
public String getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setResult(String result) {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
public void setIp(String ip) {
|
||||
this.ip = ip;
|
||||
}
|
||||
|
||||
public Long getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
public void setDuration(Long duration) {
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getErrorMsg() {
|
||||
return errorMsg;
|
||||
}
|
||||
|
||||
public void setErrorMsg(String errorMsg) {
|
||||
this.errorMsg = errorMsg;
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package cn.novalon.gym.manage.sys.core.domain;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 系统配置领域对象
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public class SysConfig {
|
||||
|
||||
private Long id;
|
||||
private String configName;
|
||||
private String configKey;
|
||||
private String configValue;
|
||||
private String configType;
|
||||
private String createBy;
|
||||
private String updateBy;
|
||||
private LocalDateTime createdAt;
|
||||
private LocalDateTime updatedAt;
|
||||
private LocalDateTime deletedAt;
|
||||
|
||||
public Long getId() { return id; }
|
||||
public void setId(Long id) { this.id = id; }
|
||||
public String getConfigName() { return configName; }
|
||||
public void setConfigName(String configName) { this.configName = configName; }
|
||||
public String getConfigKey() { return configKey; }
|
||||
public void setConfigKey(String configKey) { this.configKey = configKey; }
|
||||
public String getConfigValue() { return configValue; }
|
||||
public void setConfigValue(String configValue) { this.configValue = configValue; }
|
||||
public String getConfigType() { return configType; }
|
||||
public void setConfigType(String configType) { this.configType = configType; }
|
||||
public String getCreateBy() { return createBy; }
|
||||
public void setCreateBy(String createBy) { this.createBy = createBy; }
|
||||
public String getUpdateBy() { return updateBy; }
|
||||
public void setUpdateBy(String updateBy) { this.updateBy = updateBy; }
|
||||
public LocalDateTime getCreatedAt() { return createdAt; }
|
||||
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
|
||||
public LocalDateTime getUpdatedAt() { return updatedAt; }
|
||||
public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }
|
||||
public LocalDateTime getDeletedAt() { return deletedAt; }
|
||||
public void setDeletedAt(LocalDateTime deletedAt) { this.deletedAt = deletedAt; }
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package cn.novalon.gym.manage.sys.core.domain;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 字典数据领域对象
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public class SysDictData {
|
||||
|
||||
private Long id;
|
||||
private Long dictTypeId;
|
||||
private String dictLabel;
|
||||
private String dictValue;
|
||||
private Integer dictSort;
|
||||
private String dictType;
|
||||
private String cssClass;
|
||||
private String listClass;
|
||||
private String isDefault;
|
||||
private String status;
|
||||
private String createBy;
|
||||
private String updateBy;
|
||||
private LocalDateTime createdAt;
|
||||
private LocalDateTime updatedAt;
|
||||
private LocalDateTime deletedAt;
|
||||
|
||||
public Long getId() { return id; }
|
||||
public void setId(Long id) { this.id = id; }
|
||||
public Long getDictTypeId() { return dictTypeId; }
|
||||
public void setDictTypeId(Long dictTypeId) { this.dictTypeId = dictTypeId; }
|
||||
public String getDictLabel() { return dictLabel; }
|
||||
public void setDictLabel(String dictLabel) { this.dictLabel = dictLabel; }
|
||||
public String getDictValue() { return dictValue; }
|
||||
public void setDictValue(String dictValue) { this.dictValue = dictValue; }
|
||||
public Integer getDictSort() { return dictSort; }
|
||||
public void setDictSort(Integer dictSort) { this.dictSort = dictSort; }
|
||||
public String getDictType() { return dictType; }
|
||||
public void setDictType(String dictType) { this.dictType = dictType; }
|
||||
public String getCssClass() { return cssClass; }
|
||||
public void setCssClass(String cssClass) { this.cssClass = cssClass; }
|
||||
public String getListClass() { return listClass; }
|
||||
public void setListClass(String listClass) { this.listClass = listClass; }
|
||||
public String getIsDefault() { return isDefault; }
|
||||
public void setIsDefault(String isDefault) { this.isDefault = isDefault; }
|
||||
public String getStatus() { return status; }
|
||||
public void setStatus(String status) { this.status = status; }
|
||||
public String getCreateBy() { return createBy; }
|
||||
public void setCreateBy(String createBy) { this.createBy = createBy; }
|
||||
public String getUpdateBy() { return updateBy; }
|
||||
public void setUpdateBy(String updateBy) { this.updateBy = updateBy; }
|
||||
public LocalDateTime getCreatedAt() { return createdAt; }
|
||||
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
|
||||
public LocalDateTime getUpdatedAt() { return updatedAt; }
|
||||
public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }
|
||||
public LocalDateTime getDeletedAt() { return deletedAt; }
|
||||
public void setDeletedAt(LocalDateTime deletedAt) { this.deletedAt = deletedAt; }
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package cn.novalon.gym.manage.sys.core.domain;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 字典类型领域对象
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public class SysDictType {
|
||||
|
||||
private Long id;
|
||||
private String dictName;
|
||||
private String dictType;
|
||||
private String status;
|
||||
private String remark;
|
||||
private String createBy;
|
||||
private String updateBy;
|
||||
private LocalDateTime createdAt;
|
||||
private LocalDateTime updatedAt;
|
||||
private LocalDateTime deletedAt;
|
||||
|
||||
public Long getId() { return id; }
|
||||
public void setId(Long id) { this.id = id; }
|
||||
public String getDictName() { return dictName; }
|
||||
public void setDictName(String dictName) { this.dictName = dictName; }
|
||||
public String getDictType() { return dictType; }
|
||||
public void setDictType(String dictType) { this.dictType = dictType; }
|
||||
public String getStatus() { return status; }
|
||||
public void setStatus(String status) { this.status = status; }
|
||||
public String getRemark() { return remark; }
|
||||
public void setRemark(String remark) { this.remark = remark; }
|
||||
public String getCreateBy() { return createBy; }
|
||||
public void setCreateBy(String createBy) { this.createBy = createBy; }
|
||||
public String getUpdateBy() { return updateBy; }
|
||||
public void setUpdateBy(String updateBy) { this.updateBy = updateBy; }
|
||||
public LocalDateTime getCreatedAt() { return createdAt; }
|
||||
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
|
||||
public LocalDateTime getUpdatedAt() { return updatedAt; }
|
||||
public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }
|
||||
public LocalDateTime getDeletedAt() { return deletedAt; }
|
||||
public void setDeletedAt(LocalDateTime deletedAt) { this.deletedAt = deletedAt; }
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package cn.novalon.gym.manage.sys.core.domain;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 异常日志领域对象
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public class SysExceptionLog {
|
||||
|
||||
private Long id;
|
||||
private String username;
|
||||
private String title;
|
||||
private String exceptionName;
|
||||
private String methodName;
|
||||
private String methodParams;
|
||||
private String exceptionMsg;
|
||||
private String exceptionStack;
|
||||
private String ip;
|
||||
private LocalDateTime createTime;
|
||||
|
||||
public Long getId() { return id; }
|
||||
public void setId(Long id) { this.id = id; }
|
||||
public String getUsername() { return username; }
|
||||
public void setUsername(String username) { this.username = username; }
|
||||
public String getTitle() { return title; }
|
||||
public void setTitle(String title) { this.title = title; }
|
||||
public String getExceptionName() { return exceptionName; }
|
||||
public void setExceptionName(String exceptionName) { this.exceptionName = exceptionName; }
|
||||
public String getMethodName() { return methodName; }
|
||||
public void setMethodName(String methodName) { this.methodName = methodName; }
|
||||
public String getMethodParams() { return methodParams; }
|
||||
public void setMethodParams(String methodParams) { this.methodParams = methodParams; }
|
||||
public String getExceptionMsg() { return exceptionMsg; }
|
||||
public void setExceptionMsg(String exceptionMsg) { this.exceptionMsg = exceptionMsg; }
|
||||
public String getExceptionStack() { return exceptionStack; }
|
||||
public void setExceptionStack(String exceptionStack) { this.exceptionStack = exceptionStack; }
|
||||
public String getIp() { return ip; }
|
||||
public void setIp(String ip) { this.ip = ip; }
|
||||
public LocalDateTime getCreateTime() { return createTime; }
|
||||
public void setCreateTime(LocalDateTime createTime) { this.createTime = createTime; }
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
package cn.novalon.gym.manage.sys.core.domain;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 登录日志领域对象
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public class SysLoginLog {
|
||||
|
||||
private Long id;
|
||||
private String username;
|
||||
private String ip;
|
||||
private String location;
|
||||
private String browser;
|
||||
private String os;
|
||||
private String status;
|
||||
private String message;
|
||||
private LocalDateTime loginTime;
|
||||
|
||||
public Long getId() { return id; }
|
||||
public void setId(Long id) { this.id = id; }
|
||||
public String getUsername() { return username; }
|
||||
public void setUsername(String username) { this.username = username; }
|
||||
public String getIp() { return ip; }
|
||||
public void setIp(String ip) { this.ip = ip; }
|
||||
public String getLocation() { return location; }
|
||||
public void setLocation(String location) { this.location = location; }
|
||||
public String getBrowser() { return browser; }
|
||||
public void setBrowser(String browser) { this.browser = browser; }
|
||||
public String getOs() { return os; }
|
||||
public void setOs(String os) { this.os = os; }
|
||||
public String getStatus() { return status; }
|
||||
public void setStatus(String status) { this.status = status; }
|
||||
public String getMessage() { return message; }
|
||||
public void setMessage(String message) { this.message = message; }
|
||||
public LocalDateTime getLoginTime() { return loginTime; }
|
||||
public void setLoginTime(LocalDateTime loginTime) { this.loginTime = loginTime; }
|
||||
}
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
package cn.novalon.gym.manage.sys.core.domain;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 菜单领域对象
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public class SysMenu extends BaseDomain {
|
||||
|
||||
private String menuName;
|
||||
private Long parentId;
|
||||
private Integer orderNum;
|
||||
private String menuType;
|
||||
private String perms;
|
||||
private String component;
|
||||
private Integer status;
|
||||
private String createBy;
|
||||
private String updateBy;
|
||||
private List<SysMenu> children;
|
||||
|
||||
public String getMenuName() {
|
||||
return menuName;
|
||||
}
|
||||
|
||||
public void setMenuName(String menuName) {
|
||||
this.menuName = menuName;
|
||||
}
|
||||
|
||||
public Long getParentId() {
|
||||
return parentId;
|
||||
}
|
||||
|
||||
public void setParentId(Long parentId) {
|
||||
this.parentId = parentId;
|
||||
}
|
||||
|
||||
public Integer getOrderNum() {
|
||||
return orderNum;
|
||||
}
|
||||
|
||||
public void setOrderNum(Integer orderNum) {
|
||||
this.orderNum = orderNum;
|
||||
}
|
||||
|
||||
public String getMenuType() {
|
||||
return menuType;
|
||||
}
|
||||
|
||||
public void setMenuType(String menuType) {
|
||||
this.menuType = menuType;
|
||||
}
|
||||
|
||||
public String getPerms() {
|
||||
return perms;
|
||||
}
|
||||
|
||||
public void setPerms(String perms) {
|
||||
this.perms = perms;
|
||||
}
|
||||
|
||||
public String getComponent() {
|
||||
return component;
|
||||
}
|
||||
|
||||
public void setComponent(String component) {
|
||||
this.component = component;
|
||||
}
|
||||
|
||||
public Integer getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(Integer status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getCreateBy() {
|
||||
return createBy;
|
||||
}
|
||||
|
||||
public void setCreateBy(String createBy) {
|
||||
this.createBy = createBy;
|
||||
}
|
||||
|
||||
public String getUpdateBy() {
|
||||
return updateBy;
|
||||
}
|
||||
|
||||
public void setUpdateBy(String updateBy) {
|
||||
this.updateBy = updateBy;
|
||||
}
|
||||
|
||||
public List<SysMenu> getChildren() {
|
||||
return children;
|
||||
}
|
||||
|
||||
public void setChildren(List<SysMenu> children) {
|
||||
this.children = children;
|
||||
}
|
||||
}
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
package cn.novalon.gym.manage.sys.core.domain;
|
||||
|
||||
import cn.novalon.gym.manage.common.util.SnowflakeId;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
/**
|
||||
* 权限领域对象
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-25
|
||||
*/
|
||||
@Schema(description = "系统权限实体")
|
||||
public class SysPermission extends BaseDomain {
|
||||
|
||||
@Schema(description = "权限名称", example = "用户管理")
|
||||
private String permissionName;
|
||||
|
||||
@Schema(description = "权限编码", example = "system:user:view")
|
||||
private String permissionCode;
|
||||
|
||||
@Schema(description = "资源路径", example = "/api/users")
|
||||
private String resource;
|
||||
|
||||
@Schema(description = "操作类型", example = "GET")
|
||||
private String action;
|
||||
|
||||
@Schema(description = "描述", example = "查看用户列表")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "状态:0-禁用,1-正常", example = "1")
|
||||
private Integer status;
|
||||
|
||||
public String getPermissionName() {
|
||||
return permissionName;
|
||||
}
|
||||
|
||||
public void setPermissionName(String permissionName) {
|
||||
this.permissionName = permissionName;
|
||||
}
|
||||
|
||||
public String getPermissionCode() {
|
||||
return permissionCode;
|
||||
}
|
||||
|
||||
public void setPermissionCode(String permissionCode) {
|
||||
this.permissionCode = permissionCode;
|
||||
}
|
||||
|
||||
public String getResource() {
|
||||
return resource;
|
||||
}
|
||||
|
||||
public void setResource(String resource) {
|
||||
this.resource = resource;
|
||||
}
|
||||
|
||||
public String getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public void setAction(String action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public Integer getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(Integer status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除权限
|
||||
*/
|
||||
public void delete() {
|
||||
this.deletedAt = java.time.LocalDateTime.now();
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复权限
|
||||
*/
|
||||
public void restore() {
|
||||
this.deletedAt = null;
|
||||
}
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
package cn.novalon.gym.manage.sys.core.domain;
|
||||
|
||||
import cn.novalon.gym.manage.common.util.SnowflakeId;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 角色领域对象
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
@Schema(description = "系统角色实体")
|
||||
public class SysRole extends BaseDomain {
|
||||
|
||||
@Schema(description = "角色名称", example = "管理员")
|
||||
private String roleName;
|
||||
|
||||
@Schema(description = "角色权限字符串", example = "admin")
|
||||
private String roleKey;
|
||||
|
||||
@Schema(description = "显示顺序", example = "1")
|
||||
private Integer roleSort;
|
||||
|
||||
@Schema(description = "状态:0-禁用,1-正常", example = "1")
|
||||
private Integer status;
|
||||
|
||||
public String getRoleName() {
|
||||
return roleName;
|
||||
}
|
||||
|
||||
public void setRoleName(String roleName) {
|
||||
this.roleName = roleName;
|
||||
}
|
||||
|
||||
public String getRoleKey() {
|
||||
return roleKey;
|
||||
}
|
||||
|
||||
public void setRoleKey(String roleKey) {
|
||||
this.roleKey = roleKey;
|
||||
}
|
||||
|
||||
public Integer getRoleSort() {
|
||||
return roleSort;
|
||||
}
|
||||
|
||||
public void setRoleSort(Integer roleSort) {
|
||||
this.roleSort = roleSort;
|
||||
}
|
||||
|
||||
public Integer getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(Integer status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除角色
|
||||
*/
|
||||
public void delete() {
|
||||
this.deletedAt = LocalDateTime.now();
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复角色
|
||||
*/
|
||||
public void restore() {
|
||||
this.deletedAt = null;
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package cn.novalon.gym.manage.sys.core.domain;
|
||||
|
||||
import cn.novalon.gym.manage.common.util.SnowflakeId;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
/**
|
||||
* 角色权限关联领域对象
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-25
|
||||
*/
|
||||
@Schema(description = "角色权限关联实体")
|
||||
public class SysRolePermission extends BaseDomain {
|
||||
|
||||
@Schema(description = "角色ID", example = "1")
|
||||
private Long roleId;
|
||||
|
||||
@Schema(description = "权限ID", example = "1")
|
||||
private Long permissionId;
|
||||
|
||||
public Long getRoleId() {
|
||||
return roleId;
|
||||
}
|
||||
|
||||
public void setRoleId(Long roleId) {
|
||||
this.roleId = roleId;
|
||||
}
|
||||
|
||||
public Long getPermissionId() {
|
||||
return permissionId;
|
||||
}
|
||||
|
||||
public void setPermissionId(Long permissionId) {
|
||||
this.permissionId = permissionId;
|
||||
}
|
||||
}
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
package cn.novalon.gym.manage.sys.core.domain;
|
||||
|
||||
import cn.novalon.gym.manage.common.util.SnowflakeId;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 用户领域对象
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
@Schema(description = "系统用户实体")
|
||||
public class SysUser extends BaseDomain {
|
||||
|
||||
@Schema(description = "用户名", example = "admin")
|
||||
private String username;
|
||||
|
||||
@Schema(description = "密码(加密后)", example = "$2a$10$...")
|
||||
private String password;
|
||||
|
||||
@Schema(description = "昵称", example = "管理员")
|
||||
private String nickname;
|
||||
|
||||
@Schema(description = "邮箱", example = "admin@example.com")
|
||||
private String email;
|
||||
|
||||
@Schema(description = "手机号", example = "13800138000")
|
||||
private String phone;
|
||||
|
||||
@Schema(description = "头像", example = "https://example.com/avatar.jpg")
|
||||
private String avatar;
|
||||
|
||||
@Schema(description = "角色ID", example = "1")
|
||||
private Long roleId;
|
||||
|
||||
@Schema(description = "状态:0-禁用,1-正常", example = "1")
|
||||
private Integer status;
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getNickname() {
|
||||
return nickname;
|
||||
}
|
||||
|
||||
public void setNickname(String nickname) {
|
||||
this.nickname = nickname;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getPhone() {
|
||||
return phone;
|
||||
}
|
||||
|
||||
public void setPhone(String phone) {
|
||||
this.phone = phone;
|
||||
}
|
||||
|
||||
public String getAvatar() {
|
||||
return avatar;
|
||||
}
|
||||
|
||||
public void setAvatar(String avatar) {
|
||||
this.avatar = avatar;
|
||||
}
|
||||
|
||||
public Long getRoleId() {
|
||||
return roleId;
|
||||
}
|
||||
|
||||
public void setRoleId(Long roleId) {
|
||||
this.roleId = roleId;
|
||||
}
|
||||
|
||||
public Integer getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(Integer status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除用户
|
||||
*/
|
||||
public void delete() {
|
||||
this.deletedAt = LocalDateTime.now();
|
||||
}
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
package cn.novalon.gym.manage.sys.core.domain;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "用户角色关联实体")
|
||||
public class UserRole {
|
||||
|
||||
@Schema(description = "主键ID")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "用户ID")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "角色ID")
|
||||
private Long roleId;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
@Schema(description = "创建人")
|
||||
private String createdBy;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Long getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(Long userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public Long getRoleId() {
|
||||
return roleId;
|
||||
}
|
||||
|
||||
public void setRoleId(Long roleId) {
|
||||
this.roleId = roleId;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public void setCreatedAt(LocalDateTime createdAt) {
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
|
||||
public String getCreatedBy() {
|
||||
return createdBy;
|
||||
}
|
||||
|
||||
public void setCreatedBy(String createdBy) {
|
||||
this.createdBy = createdBy;
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package cn.novalon.gym.manage.sys.core.exception;
|
||||
|
||||
/**
|
||||
* 字典已存在异常
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public class DictionaryAlreadyExistsException extends RuntimeException {
|
||||
|
||||
private final String type;
|
||||
private final String code;
|
||||
|
||||
public DictionaryAlreadyExistsException(String type, String code) {
|
||||
super("Dictionary with type '" + type + "' and code '" + code + "' already exists");
|
||||
this.type = type;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
package cn.novalon.gym.manage.sys.core.query;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 操作日志查询对象
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public class OperationLogQuery {
|
||||
|
||||
private String username;
|
||||
private String operation;
|
||||
private String status;
|
||||
private String keyword;
|
||||
private LocalDateTime startTime;
|
||||
private LocalDateTime endTime;
|
||||
private String ip;
|
||||
private String method;
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getOperation() {
|
||||
return operation;
|
||||
}
|
||||
|
||||
public void setOperation(String operation) {
|
||||
this.operation = operation;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getKeyword() {
|
||||
return keyword;
|
||||
}
|
||||
|
||||
public void setKeyword(String keyword) {
|
||||
this.keyword = keyword;
|
||||
}
|
||||
|
||||
public LocalDateTime getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
|
||||
public void setStartTime(LocalDateTime startTime) {
|
||||
this.startTime = startTime;
|
||||
}
|
||||
|
||||
public LocalDateTime getEndTime() {
|
||||
return endTime;
|
||||
}
|
||||
|
||||
public void setEndTime(LocalDateTime endTime) {
|
||||
this.endTime = endTime;
|
||||
}
|
||||
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
public void setIp(String ip) {
|
||||
this.ip = ip;
|
||||
}
|
||||
|
||||
public String getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public void setMethod(String method) {
|
||||
this.method = method;
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package cn.novalon.gym.manage.sys.core.query;
|
||||
|
||||
/**
|
||||
* 异常日志查询对象
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public class SysExceptionLogQuery {
|
||||
|
||||
private String username;
|
||||
private String title;
|
||||
private String exceptionName;
|
||||
private String keyword;
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getExceptionName() {
|
||||
return exceptionName;
|
||||
}
|
||||
|
||||
public void setExceptionName(String exceptionName) {
|
||||
this.exceptionName = exceptionName;
|
||||
}
|
||||
|
||||
public String getKeyword() {
|
||||
return keyword;
|
||||
}
|
||||
|
||||
public void setKeyword(String keyword) {
|
||||
this.keyword = keyword;
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package cn.novalon.gym.manage.sys.core.query;
|
||||
|
||||
/**
|
||||
* 登录日志查询对象
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public class SysLoginLogQuery {
|
||||
|
||||
private String username;
|
||||
private String ip;
|
||||
private String status;
|
||||
private String keyword;
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
public void setIp(String ip) {
|
||||
this.ip = ip;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getKeyword() {
|
||||
return keyword;
|
||||
}
|
||||
|
||||
public void setKeyword(String keyword) {
|
||||
this.keyword = keyword;
|
||||
}
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
package cn.novalon.gym.manage.sys.core.query;
|
||||
|
||||
/**
|
||||
* 菜单查询对象
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public class SysMenuQuery {
|
||||
|
||||
private String menuName;
|
||||
private String menuType;
|
||||
private Integer status;
|
||||
private Long parentId;
|
||||
private String keyword;
|
||||
|
||||
public String getMenuName() {
|
||||
return menuName;
|
||||
}
|
||||
|
||||
public void setMenuName(String menuName) {
|
||||
this.menuName = menuName;
|
||||
}
|
||||
|
||||
public String getMenuType() {
|
||||
return menuType;
|
||||
}
|
||||
|
||||
public void setMenuType(String menuType) {
|
||||
this.menuType = menuType;
|
||||
}
|
||||
|
||||
public Integer getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(Integer status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public Long getParentId() {
|
||||
return parentId;
|
||||
}
|
||||
|
||||
public void setParentId(Long parentId) {
|
||||
this.parentId = parentId;
|
||||
}
|
||||
|
||||
public String getKeyword() {
|
||||
return keyword;
|
||||
}
|
||||
|
||||
public void setKeyword(String keyword) {
|
||||
this.keyword = keyword;
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package cn.novalon.gym.manage.sys.core.query;
|
||||
|
||||
/**
|
||||
* 角色查询对象
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public class SysRoleQuery {
|
||||
|
||||
private String roleName;
|
||||
|
||||
private String roleKey;
|
||||
|
||||
private Integer status;
|
||||
|
||||
private String keyword;
|
||||
|
||||
public String getRoleName() {
|
||||
return roleName;
|
||||
}
|
||||
|
||||
public void setRoleName(String roleName) {
|
||||
this.roleName = roleName;
|
||||
}
|
||||
|
||||
public String getRoleKey() {
|
||||
return roleKey;
|
||||
}
|
||||
|
||||
public void setRoleKey(String roleKey) {
|
||||
this.roleKey = roleKey;
|
||||
}
|
||||
|
||||
public Integer getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(Integer status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getKeyword() {
|
||||
return keyword;
|
||||
}
|
||||
|
||||
public void setKeyword(String keyword) {
|
||||
this.keyword = keyword;
|
||||
}
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
package cn.novalon.gym.manage.sys.core.query;
|
||||
|
||||
/**
|
||||
* 用户查询对象
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public class SysUserQuery {
|
||||
|
||||
private String username;
|
||||
|
||||
private String email;
|
||||
|
||||
private Long roleId;
|
||||
|
||||
private Integer status;
|
||||
|
||||
private String keyword;
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public Long getRoleId() {
|
||||
return roleId;
|
||||
}
|
||||
|
||||
public void setRoleId(Long roleId) {
|
||||
this.roleId = roleId;
|
||||
}
|
||||
|
||||
public Integer getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(Integer status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getKeyword() {
|
||||
return keyword;
|
||||
}
|
||||
|
||||
public void setKeyword(String keyword) {
|
||||
this.keyword = keyword;
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package cn.novalon.gym.manage.sys.core.repository;
|
||||
|
||||
import cn.novalon.gym.manage.sys.core.domain.Dictionary;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* 字典仓储接口
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public interface IDictionaryRepository {
|
||||
|
||||
Flux<Dictionary> findAll();
|
||||
|
||||
Flux<Dictionary> findByDeletedAtIsNullOrderBySortAsc();
|
||||
|
||||
Mono<Dictionary> findById(Long id);
|
||||
|
||||
Flux<Dictionary> findByType(String type);
|
||||
|
||||
Mono<Dictionary> findByTypeAndCode(String type, String code);
|
||||
|
||||
Mono<Boolean> existsByTypeAndCode(String type, String code);
|
||||
|
||||
Mono<Dictionary> save(Dictionary dictionary);
|
||||
|
||||
Mono<Void> deleteById(Long id);
|
||||
|
||||
Mono<Void> deleteByIdAndDeletedAtIsNull(Long id);
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package cn.novalon.gym.manage.sys.core.repository;
|
||||
|
||||
import cn.novalon.gym.manage.common.dto.PageRequest;
|
||||
import cn.novalon.gym.manage.common.dto.PageResponse;
|
||||
import cn.novalon.gym.manage.sys.core.domain.OperationLog;
|
||||
import cn.novalon.gym.manage.sys.core.query.OperationLogQuery;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 操作日志仓储接口
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public interface IOperationLogRepository {
|
||||
|
||||
Mono<OperationLog> findById(Long id);
|
||||
|
||||
Mono<OperationLog> save(OperationLog operationLog);
|
||||
|
||||
Mono<Void> deleteById(Long id);
|
||||
|
||||
Flux<OperationLog> findAll();
|
||||
|
||||
Flux<OperationLog> findByUsername(String username);
|
||||
|
||||
Mono<PageResponse<OperationLog>> findByQueryWithPagination(OperationLogQuery query, PageRequest pageRequest);
|
||||
|
||||
Mono<Long> count();
|
||||
|
||||
Mono<Long> countByCreatedAtAfter(LocalDateTime dateTime);
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package cn.novalon.gym.manage.sys.core.repository;
|
||||
|
||||
import cn.novalon.gym.manage.sys.core.domain.SysConfig;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* 系统配置仓储接口
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public interface ISysConfigRepository {
|
||||
|
||||
Mono<SysConfig> findById(Long id);
|
||||
|
||||
Mono<SysConfig> findByConfigKeyAndDeletedAtIsNull(String configKey);
|
||||
|
||||
Flux<SysConfig> findByDeletedAtIsNull();
|
||||
|
||||
Flux<SysConfig> findAll();
|
||||
|
||||
Flux<SysConfig> findAll(Sort sort);
|
||||
|
||||
Mono<SysConfig> save(SysConfig config);
|
||||
|
||||
Mono<Void> deleteByIdAndDeletedAtIsNull(Long id);
|
||||
|
||||
Mono<Long> count();
|
||||
|
||||
Mono<Boolean> existsByConfigKey(String configKey);
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package cn.novalon.gym.manage.sys.core.repository;
|
||||
|
||||
import cn.novalon.gym.manage.sys.core.domain.SysDictData;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* 字典数据仓储接口
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public interface ISysDictDataRepository {
|
||||
|
||||
Flux<SysDictData> findByDeletedAtIsNull();
|
||||
|
||||
Flux<SysDictData> findByDictTypeAndDeletedAtIsNull(String dictType);
|
||||
|
||||
Flux<SysDictData> findByDictTypeAndStatusAndDeletedAtIsNull(String dictType, String status);
|
||||
|
||||
Mono<SysDictData> findById(Long id);
|
||||
|
||||
Mono<SysDictData> save(SysDictData dictData);
|
||||
|
||||
Mono<Void> deleteByIdAndDeletedAtIsNull(Long id);
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package cn.novalon.gym.manage.sys.core.repository;
|
||||
|
||||
import cn.novalon.gym.manage.sys.core.domain.SysDictType;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* 字典类型仓储接口
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public interface ISysDictTypeRepository {
|
||||
|
||||
Flux<SysDictType> findByDeletedAtIsNull();
|
||||
|
||||
Mono<SysDictType> findById(Long id);
|
||||
|
||||
Mono<SysDictType> findByDictTypeAndDeletedAtIsNull(String dictType);
|
||||
|
||||
Mono<SysDictType> save(SysDictType dictType);
|
||||
|
||||
Mono<Void> deleteByIdAndDeletedAtIsNull(Long id);
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package cn.novalon.gym.manage.sys.core.repository;
|
||||
|
||||
import cn.novalon.gym.manage.sys.core.domain.SysExceptionLog;
|
||||
import cn.novalon.gym.manage.common.dto.PageRequest;
|
||||
import cn.novalon.gym.manage.common.dto.PageResponse;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 异常日志仓储接口
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public interface ISysExceptionLogRepository {
|
||||
|
||||
Flux<SysExceptionLog> findAllByOrderByCreateTimeDesc();
|
||||
|
||||
Flux<SysExceptionLog> findByUsernameOrderByCreateTimeDesc(String username);
|
||||
|
||||
Flux<SysExceptionLog> findByCreateTimeBetweenOrderByCreateTimeDesc(LocalDateTime startTime, LocalDateTime endTime);
|
||||
|
||||
Mono<SysExceptionLog> save(SysExceptionLog exceptionLog);
|
||||
|
||||
Mono<SysExceptionLog> findById(Long id);
|
||||
|
||||
Mono<Long> count();
|
||||
|
||||
Mono<PageResponse<SysExceptionLog>> findExceptionLogsByPage(PageRequest pageRequest);
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package cn.novalon.gym.manage.sys.core.repository;
|
||||
|
||||
import cn.novalon.gym.manage.sys.core.domain.SysLoginLog;
|
||||
import cn.novalon.gym.manage.common.dto.PageRequest;
|
||||
import cn.novalon.gym.manage.common.dto.PageResponse;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 登录日志仓储接口
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public interface ISysLoginLogRepository {
|
||||
|
||||
Flux<SysLoginLog> findAllByOrderByLoginTimeDesc();
|
||||
|
||||
Flux<SysLoginLog> findByUsernameOrderByLoginTimeDesc(String username);
|
||||
|
||||
Flux<SysLoginLog> findByLoginTimeBetweenOrderByLoginTimeDesc(LocalDateTime startTime, LocalDateTime endTime);
|
||||
|
||||
Mono<SysLoginLog> save(SysLoginLog loginLog);
|
||||
|
||||
Mono<SysLoginLog> findById(Long id);
|
||||
|
||||
Mono<Long> count();
|
||||
|
||||
Mono<Long> countToday();
|
||||
|
||||
Mono<PageResponse<SysLoginLog>> findLoginLogsByPage(PageRequest pageRequest);
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package cn.novalon.gym.manage.sys.core.repository;
|
||||
|
||||
import cn.novalon.gym.manage.sys.core.domain.SysMenu;
|
||||
import cn.novalon.gym.manage.sys.core.query.SysMenuQuery;
|
||||
import cn.novalon.gym.manage.common.dto.PageRequest;
|
||||
import cn.novalon.gym.manage.common.dto.PageResponse;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* 菜单仓储接口
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public interface ISysMenuRepository {
|
||||
|
||||
Flux<SysMenu> findByParentId(Long parentId);
|
||||
|
||||
Flux<SysMenu> findByParentIdOrderBySort(Long parentId, Sort sort);
|
||||
|
||||
Mono<SysMenu> findById(Long id);
|
||||
|
||||
Mono<SysMenu> save(SysMenu sysMenu);
|
||||
|
||||
Mono<Void> deleteById(Long id);
|
||||
|
||||
Flux<SysMenu> findAll();
|
||||
|
||||
Flux<SysMenu> findAll(Sort sort);
|
||||
|
||||
Mono<Long> count();
|
||||
|
||||
Mono<PageResponse<SysMenu>> findByQueryWithPagination(SysMenuQuery query, PageRequest pageRequest);
|
||||
|
||||
Flux<SysMenu> findByStatus(String status);
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package cn.novalon.gym.manage.sys.core.repository;
|
||||
|
||||
import cn.novalon.gym.manage.sys.core.domain.SysPermission;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* 权限仓储接口
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-25
|
||||
*/
|
||||
public interface ISysPermissionRepository {
|
||||
|
||||
Mono<SysPermission> findById(Long id);
|
||||
|
||||
Mono<SysPermission> findByIdIncludingDeleted(Long id);
|
||||
|
||||
Mono<SysPermission> save(SysPermission sysPermission);
|
||||
|
||||
Mono<Void> deleteById(Long id);
|
||||
|
||||
Flux<SysPermission> findAll();
|
||||
|
||||
Flux<SysPermission> findAll(Sort sort);
|
||||
|
||||
Mono<SysPermission> findByPermissionCode(String permissionCode);
|
||||
|
||||
Mono<Long> count();
|
||||
|
||||
Mono<Boolean> existsByPermissionCode(String permissionCode);
|
||||
|
||||
Mono<SysPermission> updatePermission(SysPermission permission);
|
||||
|
||||
Flux<SysPermission> findByRoleId(Long roleId);
|
||||
|
||||
Flux<SysPermission> findByRoleIds(java.util.List<Long> roleIds);
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package cn.novalon.gym.manage.sys.core.repository;
|
||||
|
||||
import cn.novalon.gym.manage.sys.core.domain.SysRolePermission;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* 角色权限关联仓储接口
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-25
|
||||
*/
|
||||
public interface ISysRolePermissionRepository {
|
||||
|
||||
Mono<SysRolePermission> save(SysRolePermission rolePermission);
|
||||
|
||||
Mono<Void> deleteById(Long id);
|
||||
|
||||
Mono<Void> deleteByRoleId(Long roleId);
|
||||
|
||||
Mono<Void> deleteByPermissionId(Long permissionId);
|
||||
|
||||
Flux<SysRolePermission> findByRoleId(Long roleId);
|
||||
|
||||
Flux<SysRolePermission> findByPermissionId(Long permissionId);
|
||||
|
||||
Flux<Long> findPermissionIdsByRoleId(Long roleId);
|
||||
|
||||
Flux<Long> findRoleIdsByPermissionId(Long permissionId);
|
||||
|
||||
Mono<Void> deleteByRoleIdAndPermissionIds(Long roleId, java.util.List<Long> permissionIds);
|
||||
|
||||
Mono<Void> deleteByPermissionIdAndRoleIds(Long permissionId, java.util.List<Long> roleIds);
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package cn.novalon.gym.manage.sys.core.repository;
|
||||
|
||||
import cn.novalon.gym.manage.sys.core.domain.SysRole;
|
||||
import cn.novalon.gym.manage.sys.core.query.SysRoleQuery;
|
||||
import cn.novalon.gym.manage.common.dto.PageRequest;
|
||||
import cn.novalon.gym.manage.common.dto.PageResponse;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* 角色仓储接口
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public interface ISysRoleRepository {
|
||||
|
||||
Mono<SysRole> findById(Long id);
|
||||
|
||||
Mono<SysRole> findByIdIncludingDeleted(Long id);
|
||||
|
||||
Mono<SysRole> save(SysRole sysRole);
|
||||
|
||||
Mono<Void> deleteById(Long id);
|
||||
|
||||
Flux<SysRole> findAll();
|
||||
|
||||
Flux<SysRole> findAll(Sort sort);
|
||||
|
||||
Flux<SysRole> findByRoleNameLikeOrRoleKeyLike(String roleName, String roleKey, Sort sort);
|
||||
|
||||
Mono<Long> count();
|
||||
|
||||
Mono<Long> countByRoleNameLikeOrRoleKeyLike(String roleName, String roleKey);
|
||||
|
||||
Mono<PageResponse<SysRole>> findByQueryWithPagination(SysRoleQuery query, PageRequest pageRequest);
|
||||
|
||||
Mono<SysRole> findByRoleName(String roleName);
|
||||
|
||||
Mono<Boolean> existsByRoleName(String roleName);
|
||||
|
||||
Mono<SysRole> updateRole(SysRole role);
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
package cn.novalon.gym.manage.sys.core.repository;
|
||||
|
||||
import cn.novalon.gym.manage.sys.core.domain.SysUser;
|
||||
import cn.novalon.gym.manage.sys.core.query.SysUserQuery;
|
||||
import cn.novalon.gym.manage.common.dto.PageRequest;
|
||||
import cn.novalon.gym.manage.common.dto.PageResponse;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户仓储接口
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public interface ISysUserRepository {
|
||||
|
||||
Mono<SysUser> findByUsername(String username);
|
||||
|
||||
Mono<SysUser> findByEmail(String email);
|
||||
|
||||
Mono<SysUser> findById(Long id);
|
||||
|
||||
Mono<SysUser> findByIdIncludingDeleted(Long id);
|
||||
|
||||
Mono<SysUser> save(SysUser sysUser);
|
||||
|
||||
Mono<Void> deleteById(Long id);
|
||||
|
||||
Flux<SysUser> findAll();
|
||||
|
||||
Flux<SysUser> findAll(Sort sort);
|
||||
|
||||
Flux<SysUser> findByDeletedAtIsNull();
|
||||
|
||||
Flux<SysUser> findByDeletedAtIsNull(Sort sort);
|
||||
|
||||
Mono<Long> count();
|
||||
|
||||
Mono<PageResponse<SysUser>> findByQueryWithPagination(SysUserQuery query, PageRequest pageRequest);
|
||||
|
||||
Mono<Boolean> existsByUsername(String username);
|
||||
|
||||
Mono<Boolean> existsByEmail(String email);
|
||||
|
||||
Mono<Void> logicalDeleteById(Long id);
|
||||
|
||||
Mono<Void> logicalDeleteByIds(List<Long> ids);
|
||||
|
||||
Mono<Void> restoreById(Long id);
|
||||
|
||||
Mono<Void> restoreByIds(List<Long> ids);
|
||||
|
||||
Mono<Void> updateRoleIdToNullByRoleId(Long roleId);
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package cn.novalon.gym.manage.sys.core.repository;
|
||||
|
||||
import cn.novalon.gym.manage.sys.core.domain.UserRole;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public interface IUserRoleRepository {
|
||||
|
||||
Mono<UserRole> save(UserRole userRole);
|
||||
|
||||
Mono<Void> deleteById(Long id);
|
||||
|
||||
Mono<Void> deleteByUserId(Long userId);
|
||||
|
||||
Mono<Void> deleteByRoleId(Long roleId);
|
||||
|
||||
Flux<UserRole> findByUserId(Long userId);
|
||||
|
||||
Flux<UserRole> findByRoleId(Long roleId);
|
||||
|
||||
Mono<Long> countByUserId(Long userId);
|
||||
|
||||
Mono<Long> countByRoleId(Long roleId);
|
||||
|
||||
Flux<UserRole> findAll();
|
||||
|
||||
Mono<UserRole> findById(Long id);
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package cn.novalon.gym.manage.sys.core.service;
|
||||
|
||||
import cn.novalon.gym.manage.sys.core.domain.Dictionary;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public interface IDictionaryService {
|
||||
Flux<Dictionary> findAll();
|
||||
Mono<Dictionary> findById(Long id);
|
||||
Flux<Dictionary> findByType(String type);
|
||||
Mono<Boolean> checkTypeAndCodeExists(String type, String code);
|
||||
Mono<Dictionary> save(Dictionary dictionary);
|
||||
Mono<Dictionary> update(Long id, Dictionary dictionary);
|
||||
Mono<Void> deleteById(Long id);
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package cn.novalon.gym.manage.sys.core.service;
|
||||
|
||||
import cn.novalon.gym.manage.common.dto.PageRequest;
|
||||
import cn.novalon.gym.manage.common.dto.PageResponse;
|
||||
import cn.novalon.gym.manage.sys.core.domain.OperationLog;
|
||||
import cn.novalon.gym.manage.sys.core.query.OperationLogQuery;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* 操作日志服务接口
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public interface IOperationLogService {
|
||||
Mono<OperationLog> save(OperationLog log);
|
||||
Flux<OperationLog> findAll();
|
||||
Mono<OperationLog> findById(Long id);
|
||||
Flux<OperationLog> findByUsername(String username);
|
||||
Mono<PageResponse<OperationLog>> findByQueryWithPagination(OperationLogQuery query, PageRequest pageRequest);
|
||||
Mono<Long> count();
|
||||
Mono<Long> countToday();
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package cn.novalon.gym.manage.sys.core.service;
|
||||
|
||||
import cn.novalon.gym.manage.sys.core.domain.SysConfig;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* 系统配置服务接口
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public interface ISysConfigService {
|
||||
Flux<SysConfig> findAll();
|
||||
Mono<SysConfig> findById(Long id);
|
||||
Mono<SysConfig> findByConfigKey(String configKey);
|
||||
Mono<SysConfig> save(SysConfig config);
|
||||
Mono<Void> deleteById(Long id);
|
||||
Mono<String> getConfigValue(String configKey);
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package cn.novalon.gym.manage.sys.core.service;
|
||||
|
||||
import cn.novalon.gym.manage.sys.core.domain.SysDictData;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* 字典数据服务接口
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public interface ISysDictDataService {
|
||||
Flux<SysDictData> findAll();
|
||||
Flux<SysDictData> findByDictType(String dictType);
|
||||
Flux<SysDictData> findByDictTypeAndStatus(String dictType, String status);
|
||||
Mono<SysDictData> findById(Long id);
|
||||
Mono<SysDictData> save(SysDictData dictData);
|
||||
Mono<Void> deleteById(Long id);
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package cn.novalon.gym.manage.sys.core.service;
|
||||
|
||||
import cn.novalon.gym.manage.sys.core.domain.SysDictType;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* 字典类型服务接口
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public interface ISysDictTypeService {
|
||||
Flux<SysDictType> findAll();
|
||||
Mono<SysDictType> findById(Long id);
|
||||
Mono<SysDictType> findByDictType(String dictType);
|
||||
Mono<SysDictType> save(SysDictType dictType);
|
||||
Mono<Void> deleteById(Long id);
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package cn.novalon.gym.manage.sys.core.service;
|
||||
|
||||
import cn.novalon.gym.manage.sys.core.domain.SysExceptionLog;
|
||||
import cn.novalon.gym.manage.common.dto.PageRequest;
|
||||
import cn.novalon.gym.manage.common.dto.PageResponse;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public interface ISysExceptionLogService {
|
||||
Mono<SysExceptionLog> findById(Long id);
|
||||
Flux<SysExceptionLog> findAll();
|
||||
Flux<SysExceptionLog> findByUsername(String username);
|
||||
Flux<SysExceptionLog> findByCreateTimeBetween(LocalDateTime startTime, LocalDateTime endTime);
|
||||
Mono<SysExceptionLog> save(SysExceptionLog exceptionLog);
|
||||
Mono<PageResponse<SysExceptionLog>> findExceptionLogsByPage(PageRequest pageRequest);
|
||||
Mono<Long> count();
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package cn.novalon.gym.manage.sys.core.service;
|
||||
|
||||
import cn.novalon.gym.manage.sys.core.domain.SysLoginLog;
|
||||
import cn.novalon.gym.manage.common.dto.PageRequest;
|
||||
import cn.novalon.gym.manage.common.dto.PageResponse;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 登录日志服务接口
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public interface ISysLoginLogService {
|
||||
Mono<SysLoginLog> findById(Long id);
|
||||
Flux<SysLoginLog> findAll();
|
||||
Flux<SysLoginLog> findByUsername(String username);
|
||||
Flux<SysLoginLog> findByLoginTimeBetween(LocalDateTime startTime, LocalDateTime endTime);
|
||||
Mono<SysLoginLog> save(SysLoginLog loginLog);
|
||||
Mono<PageResponse<SysLoginLog>> findLoginLogsByPage(PageRequest pageRequest);
|
||||
Mono<Long> count();
|
||||
Mono<Long> countToday();
|
||||
Flux<SysLoginLog> findRecent(int limit);
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package cn.novalon.gym.manage.sys.core.service;
|
||||
|
||||
import cn.novalon.gym.manage.sys.core.domain.SysMenu;
|
||||
import cn.novalon.gym.manage.sys.core.command.CreateMenuCommand;
|
||||
import cn.novalon.gym.manage.sys.core.command.UpdateMenuCommand;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* 菜单服务接口
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public interface ISysMenuService {
|
||||
Mono<SysMenu> findById(Long id);
|
||||
Flux<SysMenu> findAll();
|
||||
Flux<SysMenu> findByParentId(Long parentId);
|
||||
Mono<SysMenu> createMenu(SysMenu menu);
|
||||
Mono<SysMenu> createMenu(CreateMenuCommand command);
|
||||
Mono<SysMenu> updateMenu(SysMenu menu);
|
||||
Mono<SysMenu> updateMenu(UpdateMenuCommand command);
|
||||
Mono<Void> deleteMenu(Long id);
|
||||
Flux<SysMenu> buildMenuTree(Flux<SysMenu> menus);
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package cn.novalon.gym.manage.sys.core.service;
|
||||
|
||||
import cn.novalon.gym.manage.sys.core.domain.SysPermission;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* 权限服务接口
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-25
|
||||
*/
|
||||
public interface ISysPermissionService {
|
||||
Mono<SysPermission> findById(Long id);
|
||||
Flux<SysPermission> findAll();
|
||||
Flux<SysPermission> findAll(Sort sort);
|
||||
Mono<SysPermission> findByPermissionCode(String permissionCode);
|
||||
Mono<Long> count();
|
||||
Mono<SysPermission> createPermission(SysPermission permission);
|
||||
Mono<SysPermission> updatePermission(SysPermission permission);
|
||||
Mono<Void> deletePermission(Long id);
|
||||
Mono<Boolean> existsByPermissionCode(String permissionCode);
|
||||
Flux<SysPermission> findByRoleId(Long roleId);
|
||||
Flux<SysPermission> findByRoleIds(java.util.List<Long> roleIds);
|
||||
Mono<Void> assignPermissionsToRole(Long roleId, java.util.List<Long> permissionIds);
|
||||
Flux<SysPermission> getPermissionsByRoleId(Long roleId);
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package cn.novalon.gym.manage.sys.core.service;
|
||||
|
||||
import cn.novalon.gym.manage.sys.core.domain.SysRole;
|
||||
import cn.novalon.gym.manage.common.dto.PageRequest;
|
||||
import cn.novalon.gym.manage.common.dto.PageResponse;
|
||||
import cn.novalon.gym.manage.sys.core.command.CreateRoleCommand;
|
||||
import cn.novalon.gym.manage.sys.core.command.UpdateRoleCommand;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* 角色服务接口
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public interface ISysRoleService {
|
||||
Mono<SysRole> findById(Long id);
|
||||
Flux<SysRole> findAll();
|
||||
Mono<PageResponse<SysRole>> findRolesByPage(PageRequest pageRequest);
|
||||
Mono<Long> count();
|
||||
Mono<SysRole> createRole(SysRole role);
|
||||
Mono<SysRole> createRole(CreateRoleCommand command);
|
||||
Mono<SysRole> updateRole(SysRole role);
|
||||
Mono<SysRole> updateRole(UpdateRoleCommand command);
|
||||
Mono<Void> deleteRole(Long id);
|
||||
Mono<SysRole> findByRoleName(String roleName);
|
||||
Mono<Boolean> existsByRoleName(String roleName);
|
||||
Mono<SysRole> logicalDeleteRole(Long id);
|
||||
Mono<SysRole> restoreRole(Long id);
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
package cn.novalon.gym.manage.sys.core.service;
|
||||
|
||||
import cn.novalon.gym.manage.sys.core.domain.SysUser;
|
||||
import cn.novalon.gym.manage.common.dto.PageRequest;
|
||||
import cn.novalon.gym.manage.common.dto.PageResponse;
|
||||
import cn.novalon.gym.manage.sys.core.command.CreateUserCommand;
|
||||
import cn.novalon.gym.manage.sys.core.command.UpdateUserCommand;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户服务接口
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public interface ISysUserService {
|
||||
Mono<SysUser> findById(Long id);
|
||||
|
||||
Flux<SysUser> findAll();
|
||||
|
||||
Flux<SysUser> findAll(boolean includeDeleted);
|
||||
|
||||
Mono<PageResponse<SysUser>> findUsersByPage(PageRequest pageRequest);
|
||||
|
||||
Mono<Long> count();
|
||||
|
||||
Mono<SysUser> findByUsername(String username);
|
||||
|
||||
Mono<Boolean> existsByUsername(String username);
|
||||
|
||||
Mono<Boolean> existsByEmail(String email);
|
||||
|
||||
Mono<SysUser> createUser(SysUser user);
|
||||
|
||||
Mono<SysUser> createUser(CreateUserCommand command);
|
||||
|
||||
Mono<SysUser> updateUser(SysUser user);
|
||||
|
||||
Mono<SysUser> updateUser(UpdateUserCommand command);
|
||||
|
||||
Mono<Void> deleteUser(Long id);
|
||||
|
||||
Mono<Void> logicalDeleteUser(Long id);
|
||||
|
||||
Mono<Void> logicalDeleteUsers(List<Long> ids);
|
||||
|
||||
Mono<Void> restoreUser(Long id);
|
||||
|
||||
Mono<Void> restoreUsers(List<Long> ids);
|
||||
|
||||
Mono<SysUser> changePassword(Long userId, String oldPassword, String newPassword);
|
||||
|
||||
Mono<Void> updateRoleIdToNullByRoleId(Long roleId);
|
||||
|
||||
Mono<Void> assignRolesToUser(Long userId, java.util.List<Long> roleIds);
|
||||
|
||||
Flux<cn.novalon.gym.manage.sys.core.domain.SysRole> getUserRoles(Long userId);
|
||||
|
||||
Flux<Long> getUserRoleIds(Long userId);
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package cn.novalon.gym.manage.sys.core.service;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public interface IWebSocketService {
|
||||
Mono<Void> sendToUser(Long userId, Object message);
|
||||
Mono<Void> broadcast(Object message);
|
||||
Mono<Void> notifyNewNotice(String noticeTitle, String noticeContent);
|
||||
Mono<Void> notifyNewMessage(Long userId, String title, String content);
|
||||
}
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
package cn.novalon.gym.manage.sys.core.service.impl;
|
||||
|
||||
import cn.novalon.gym.manage.sys.core.domain.Dictionary;
|
||||
import cn.novalon.gym.manage.sys.core.exception.DictionaryAlreadyExistsException;
|
||||
import cn.novalon.gym.manage.sys.core.repository.IDictionaryRepository;
|
||||
import cn.novalon.gym.manage.sys.core.service.IDictionaryService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 字典服务实现类
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-14
|
||||
*/
|
||||
@Service
|
||||
public class DictionaryService implements IDictionaryService {
|
||||
|
||||
private final IDictionaryRepository repository;
|
||||
|
||||
public DictionaryService(IDictionaryRepository repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<Dictionary> findAll() {
|
||||
return repository.findAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Dictionary> findById(Long id) {
|
||||
return repository.findById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<Dictionary> findByType(String type) {
|
||||
return repository.findByType(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Boolean> checkTypeAndCodeExists(String type, String code) {
|
||||
return repository.existsByTypeAndCode(type, code);
|
||||
}
|
||||
|
||||
@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);
|
||||
});
|
||||
}
|
||||
dictionary.setUpdatedAt(LocalDateTime.now());
|
||||
return repository.save(dictionary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Dictionary> update(Long id, Dictionary dictionary) {
|
||||
return repository.findById(id)
|
||||
.flatMap(existing -> {
|
||||
if (dictionary.getName() != null) {
|
||||
existing.setName(dictionary.getName());
|
||||
}
|
||||
if (dictionary.getValue() != null) {
|
||||
existing.setValue(dictionary.getValue());
|
||||
}
|
||||
if (dictionary.getRemark() != null) {
|
||||
existing.setRemark(dictionary.getRemark());
|
||||
}
|
||||
if (dictionary.getSort() != null) {
|
||||
existing.setSort(dictionary.getSort());
|
||||
}
|
||||
existing.setUpdatedAt(LocalDateTime.now());
|
||||
return repository.save(existing);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> deleteById(Long id) {
|
||||
return repository.deleteById(id);
|
||||
}
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
package cn.novalon.gym.manage.sys.core.service.impl;
|
||||
|
||||
import cn.novalon.gym.manage.common.dto.PageRequest;
|
||||
import cn.novalon.gym.manage.common.dto.PageResponse;
|
||||
import cn.novalon.gym.manage.sys.core.domain.OperationLog;
|
||||
import cn.novalon.gym.manage.sys.core.query.OperationLogQuery;
|
||||
import cn.novalon.gym.manage.sys.core.repository.IOperationLogRepository;
|
||||
import cn.novalon.gym.manage.sys.core.service.IOperationLogService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 操作日志服务实现类
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-14
|
||||
*/
|
||||
@Service
|
||||
public class OperationLogService implements IOperationLogService {
|
||||
|
||||
private final IOperationLogRepository logRepository;
|
||||
|
||||
public OperationLogService(IOperationLogRepository logRepository) {
|
||||
this.logRepository = logRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<OperationLog> save(OperationLog log) {
|
||||
log.setCreatedAt(LocalDateTime.now());
|
||||
return logRepository.save(log);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<OperationLog> findAll() {
|
||||
return logRepository.findAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<OperationLog> findById(Long id) {
|
||||
return logRepository.findById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<OperationLog> findByUsername(String username) {
|
||||
return logRepository.findByUsername(username);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<PageResponse<OperationLog>> findByQueryWithPagination(OperationLogQuery query, PageRequest pageRequest) {
|
||||
return logRepository.findByQueryWithPagination(query, pageRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Long> count() {
|
||||
return logRepository.count();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Long> countToday() {
|
||||
LocalDateTime startOfDay = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0);
|
||||
return logRepository.countByCreatedAtAfter(startOfDay);
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
package cn.novalon.gym.manage.sys.core.service.impl;
|
||||
|
||||
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;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
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;
|
||||
|
||||
public SysConfigService(ISysConfigRepository repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<SysConfig> findAll() {
|
||||
return repository.findByDeletedAtIsNull();
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
@Override
|
||||
@CacheEvict(value = "sysConfig", key = "#id")
|
||||
public Mono<Void> deleteById(Long id) {
|
||||
return repository.deleteByIdAndDeletedAtIsNull(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<String> getConfigValue(String configKey) {
|
||||
return findByConfigKey(configKey)
|
||||
.map(SysConfig::getConfigValue);
|
||||
}
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
package cn.novalon.gym.manage.sys.core.service.impl;
|
||||
|
||||
import cn.novalon.gym.manage.sys.core.domain.SysDictData;
|
||||
import cn.novalon.gym.manage.sys.core.repository.ISysDictDataRepository;
|
||||
import cn.novalon.gym.manage.sys.core.service.ISysDictDataService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* 字典数据服务实现类
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-14
|
||||
*/
|
||||
@Service
|
||||
public class SysDictDataService implements ISysDictDataService {
|
||||
|
||||
private final ISysDictDataRepository repository;
|
||||
|
||||
public SysDictDataService(ISysDictDataRepository repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<SysDictData> findAll() {
|
||||
return repository.findByDeletedAtIsNull();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<SysDictData> findByDictType(String dictType) {
|
||||
return repository.findByDictTypeAndDeletedAtIsNull(dictType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<SysDictData> findByDictTypeAndStatus(String dictType, String status) {
|
||||
return repository.findByDictTypeAndStatusAndDeletedAtIsNull(dictType, status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SysDictData> findById(Long id) {
|
||||
return repository.findById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SysDictData> save(SysDictData dictData) {
|
||||
return repository.save(dictData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> deleteById(Long id) {
|
||||
return repository.deleteByIdAndDeletedAtIsNull(id);
|
||||
}
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
package cn.novalon.gym.manage.sys.core.service.impl;
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
public SysDictTypeService(ISysDictTypeRepository repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<SysDictType> findAll() {
|
||||
return repository.findByDeletedAtIsNull();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SysDictType> findById(Long id) {
|
||||
return repository.findById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SysDictType> findByDictType(String dictType) {
|
||||
return repository.findByDictTypeAndDeletedAtIsNull(dictType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SysDictType> save(SysDictType dictType) {
|
||||
return repository.save(dictType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> deleteById(Long id) {
|
||||
return repository.deleteByIdAndDeletedAtIsNull(id);
|
||||
}
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
package cn.novalon.gym.manage.sys.core.service.impl;
|
||||
|
||||
import cn.novalon.gym.manage.sys.core.domain.SysExceptionLog;
|
||||
import cn.novalon.gym.manage.sys.core.repository.ISysExceptionLogRepository;
|
||||
import cn.novalon.gym.manage.sys.core.service.ISysExceptionLogService;
|
||||
import cn.novalon.gym.manage.common.dto.PageRequest;
|
||||
import cn.novalon.gym.manage.common.dto.PageResponse;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 异常日志服务实现类
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-14
|
||||
*/
|
||||
@Service
|
||||
public class SysExceptionLogService implements ISysExceptionLogService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SysExceptionLogService.class);
|
||||
private final ISysExceptionLogRepository repository;
|
||||
|
||||
public SysExceptionLogService(ISysExceptionLogRepository repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<SysExceptionLog> findAll() {
|
||||
return repository.findAllByOrderByCreateTimeDesc();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<SysExceptionLog> findByUsername(String username) {
|
||||
return repository.findByUsernameOrderByCreateTimeDesc(username);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<SysExceptionLog> findByCreateTimeBetween(LocalDateTime startTime, LocalDateTime endTime) {
|
||||
return repository.findByCreateTimeBetweenOrderByCreateTimeDesc(startTime, endTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SysExceptionLog> save(SysExceptionLog exceptionLog) {
|
||||
return repository.save(exceptionLog);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SysExceptionLog> findById(Long id) {
|
||||
return repository.findById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<PageResponse<SysExceptionLog>> findExceptionLogsByPage(PageRequest pageRequest) {
|
||||
logger.info("分页查询异常日志: page={}, size={}", pageRequest.getPage(), pageRequest.getSize());
|
||||
return repository.findExceptionLogsByPage(pageRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Long> count() {
|
||||
return repository.count();
|
||||
}
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
package cn.novalon.gym.manage.sys.core.service.impl;
|
||||
|
||||
import cn.novalon.gym.manage.sys.core.domain.SysLoginLog;
|
||||
import cn.novalon.gym.manage.sys.core.repository.ISysLoginLogRepository;
|
||||
import cn.novalon.gym.manage.sys.core.service.ISysLoginLogService;
|
||||
import cn.novalon.gym.manage.common.dto.PageRequest;
|
||||
import cn.novalon.gym.manage.common.dto.PageResponse;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 登录日志服务实现类
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-14
|
||||
*/
|
||||
@Service
|
||||
public class SysLoginLogService implements ISysLoginLogService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SysLoginLogService.class);
|
||||
private final ISysLoginLogRepository repository;
|
||||
|
||||
public SysLoginLogService(ISysLoginLogRepository repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<SysLoginLog> findAll() {
|
||||
return repository.findAllByOrderByLoginTimeDesc();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<SysLoginLog> findByUsername(String username) {
|
||||
return repository.findByUsernameOrderByLoginTimeDesc(username);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<SysLoginLog> findByLoginTimeBetween(LocalDateTime startTime, LocalDateTime endTime) {
|
||||
return repository.findByLoginTimeBetweenOrderByLoginTimeDesc(startTime, endTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SysLoginLog> save(SysLoginLog loginLog) {
|
||||
return repository.save(loginLog);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SysLoginLog> findById(Long id) {
|
||||
return repository.findById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<PageResponse<SysLoginLog>> findLoginLogsByPage(PageRequest pageRequest) {
|
||||
logger.info("分页查询登录日志: page={}, size={}", pageRequest.getPage(), pageRequest.getSize());
|
||||
return repository.findLoginLogsByPage(pageRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Long> count() {
|
||||
return repository.count();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Long> countToday() {
|
||||
return repository.countToday();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<SysLoginLog> findRecent(int limit) {
|
||||
logger.info("获取最近{}条登录日志", limit);
|
||||
return repository.findAllByOrderByLoginTimeDesc()
|
||||
.take(limit);
|
||||
}
|
||||
}
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
package cn.novalon.gym.manage.sys.core.service.impl;
|
||||
|
||||
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.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 org.springframework.stereotype.Service;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 系统菜单服务实现类
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-14
|
||||
*/
|
||||
@Service
|
||||
public class SysMenuService implements ISysMenuService {
|
||||
|
||||
private final ISysMenuRepository menuRepository;
|
||||
|
||||
public SysMenuService(ISysMenuRepository menuRepository) {
|
||||
this.menuRepository = menuRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SysMenu> findById(Long id) {
|
||||
return menuRepository.findById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<SysMenu> findAll() {
|
||||
return menuRepository.findAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<SysMenu> findByParentId(Long parentId) {
|
||||
return menuRepository.findByParentId(parentId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SysMenu> createMenu(SysMenu menu) {
|
||||
menu.setCreatedAt(LocalDateTime.now());
|
||||
return menuRepository.save(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SysMenu> createMenu(CreateMenuCommand command) {
|
||||
SysMenu menu = new SysMenu();
|
||||
menu.setParentId(command.parentId());
|
||||
menu.setMenuName(command.menuName());
|
||||
menu.setMenuType(command.menuType());
|
||||
menu.setOrderNum(command.orderNum());
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SysMenu> updateMenu(SysMenu menu) {
|
||||
menu.setUpdatedAt(LocalDateTime.now());
|
||||
return menuRepository.save(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SysMenu> updateMenu(UpdateMenuCommand command) {
|
||||
return menuRepository.findById(command.id())
|
||||
.switchIfEmpty(Mono.error(new RuntimeException("Menu not found")))
|
||||
.flatMap(menu -> {
|
||||
if (command.parentId() != null) {
|
||||
menu.setParentId(command.parentId());
|
||||
}
|
||||
if (command.menuName() != null) {
|
||||
menu.setMenuName(command.menuName());
|
||||
}
|
||||
if (command.menuType() != null) {
|
||||
menu.setMenuType(command.menuType());
|
||||
}
|
||||
if (command.orderNum() != null) {
|
||||
menu.setOrderNum(command.orderNum());
|
||||
}
|
||||
if (command.component() != null) {
|
||||
menu.setComponent(command.component());
|
||||
}
|
||||
if (command.perms() != null) {
|
||||
menu.setPerms(command.perms());
|
||||
}
|
||||
if (command.status() != null) {
|
||||
menu.setStatus(command.status());
|
||||
}
|
||||
menu.setUpdatedAt(LocalDateTime.now());
|
||||
return menuRepository.save(menu);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> deleteMenu(Long id) {
|
||||
return menuRepository.deleteById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<SysMenu> buildMenuTree(Flux<SysMenu> menus) {
|
||||
return menus.collectList()
|
||||
.map(list -> buildTree(list, 0L))
|
||||
.flatMapMany(Flux::fromIterable);
|
||||
}
|
||||
|
||||
private List<SysMenu> buildTree(List<SysMenu> menus, Long parentId) {
|
||||
return menus.stream()
|
||||
.filter(m -> m.getParentId().equals(parentId))
|
||||
.peek(m -> m.setChildren(buildTree(menus, m.getId())))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
package cn.novalon.gym.manage.sys.core.service.impl;
|
||||
|
||||
import cn.novalon.gym.manage.common.util.StatusConstants;
|
||||
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.springframework.data.domain.Sort;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 系统权限服务实现类
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-25
|
||||
*/
|
||||
@Service
|
||||
public class SysPermissionService implements ISysPermissionService {
|
||||
|
||||
private final ISysPermissionRepository permissionRepository;
|
||||
private final ISysRolePermissionRepository rolePermissionRepository;
|
||||
|
||||
public SysPermissionService(ISysPermissionRepository permissionRepository,
|
||||
ISysRolePermissionRepository rolePermissionRepository) {
|
||||
this.permissionRepository = permissionRepository;
|
||||
this.rolePermissionRepository = rolePermissionRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SysPermission> findById(Long id) {
|
||||
return permissionRepository.findById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<SysPermission> findAll() {
|
||||
return permissionRepository.findAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<SysPermission> findAll(Sort sort) {
|
||||
return permissionRepository.findAll(sort);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SysPermission> findByPermissionCode(String permissionCode) {
|
||||
return permissionRepository.findByPermissionCode(permissionCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Long> count() {
|
||||
return permissionRepository.count();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SysPermission> createPermission(SysPermission permission) {
|
||||
permission.setCreatedAt(LocalDateTime.now());
|
||||
if (permission.getStatus() == null) {
|
||||
permission.setStatus(StatusConstants.ENABLED);
|
||||
}
|
||||
return permissionRepository.save(permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SysPermission> updatePermission(SysPermission permission) {
|
||||
permission.setUpdatedAt(LocalDateTime.now());
|
||||
return permissionRepository.updatePermission(permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> deletePermission(Long id) {
|
||||
return permissionRepository.findById(id)
|
||||
.flatMap(permission -> {
|
||||
permission.delete();
|
||||
return permissionRepository.updatePermission(permission)
|
||||
.then(rolePermissionRepository.deleteByPermissionId(id));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Boolean> existsByPermissionCode(String permissionCode) {
|
||||
return permissionRepository.existsByPermissionCode(permissionCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<SysPermission> findByRoleId(Long roleId) {
|
||||
return permissionRepository.findByRoleId(roleId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<SysPermission> findByRoleIds(List<Long> roleIds) {
|
||||
return permissionRepository.findByRoleIds(roleIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Mono<Void> assignPermissionsToRole(Long roleId, List<Long> permissionIds) {
|
||||
return rolePermissionRepository.deleteByRoleId(roleId)
|
||||
.then(Flux.fromIterable(permissionIds)
|
||||
.flatMap(permissionId -> {
|
||||
SysRolePermission rolePermission = new SysRolePermission();
|
||||
rolePermission.setRoleId(roleId);
|
||||
rolePermission.setPermissionId(permissionId);
|
||||
rolePermission.setCreatedAt(LocalDateTime.now());
|
||||
return rolePermissionRepository.save(rolePermission);
|
||||
})
|
||||
.then());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<SysPermission> getPermissionsByRoleId(Long roleId) {
|
||||
return permissionRepository.findByRoleId(roleId);
|
||||
}
|
||||
}
|
||||
+172
@@ -0,0 +1,172 @@
|
||||
package cn.novalon.gym.manage.sys.core.service.impl;
|
||||
|
||||
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;
|
||||
import cn.novalon.gym.manage.sys.core.repository.ISysRoleRepository;
|
||||
import cn.novalon.gym.manage.sys.core.repository.IUserRoleRepository;
|
||||
import cn.novalon.gym.manage.sys.core.repository.ISysRolePermissionRepository;
|
||||
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.command.CreateRoleCommand;
|
||||
import cn.novalon.gym.manage.sys.core.command.UpdateRoleCommand;
|
||||
import cn.novalon.gym.manage.common.dto.PageRequest;
|
||||
import cn.novalon.gym.manage.common.dto.PageResponse;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 系统角色服务实现类
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-14
|
||||
*/
|
||||
@Service
|
||||
public class SysRoleService implements ISysRoleService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SysRoleService.class);
|
||||
private final ISysRoleRepository roleRepository;
|
||||
private final ISysUserService userService;
|
||||
private final IUserRoleRepository userRoleRepository;
|
||||
private final ISysRolePermissionRepository rolePermissionRepository;
|
||||
|
||||
public SysRoleService(ISysRoleRepository roleRepository, ISysUserService userService,
|
||||
IUserRoleRepository userRoleRepository, ISysRolePermissionRepository rolePermissionRepository) {
|
||||
this.roleRepository = roleRepository;
|
||||
this.userService = userService;
|
||||
this.userRoleRepository = userRoleRepository;
|
||||
this.rolePermissionRepository = rolePermissionRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SysRole> findById(Long id) {
|
||||
return roleRepository.findById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<SysRole> findAll() {
|
||||
return roleRepository.findAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<PageResponse<SysRole>> findRolesByPage(PageRequest pageRequest) {
|
||||
SysRoleQuery query = new SysRoleQuery();
|
||||
|
||||
if (pageRequest.getKeyword() != null && !pageRequest.getKeyword().isEmpty()) {
|
||||
query.setKeyword(pageRequest.getKeyword());
|
||||
}
|
||||
|
||||
return roleRepository.findByQueryWithPagination(query, pageRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Long> count() {
|
||||
return roleRepository.count();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SysRole> createRole(SysRole role) {
|
||||
role.setCreatedAt(LocalDateTime.now());
|
||||
if (role.getStatus() == null) {
|
||||
role.setStatus(StatusConstants.ENABLED);
|
||||
}
|
||||
return roleRepository.save(role);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SysRole> createRole(CreateRoleCommand command) {
|
||||
SysRole role = new SysRole();
|
||||
role.generateId();
|
||||
role.setRoleName(command.roleName());
|
||||
role.setRoleKey(command.roleKey());
|
||||
role.setRoleSort(command.roleSort());
|
||||
role.setStatus(command.status() != null ? command.status() : StatusConstants.ENABLED);
|
||||
role.setCreatedAt(LocalDateTime.now());
|
||||
return roleRepository.save(role);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SysRole> updateRole(SysRole role) {
|
||||
role.setUpdatedAt(LocalDateTime.now());
|
||||
return roleRepository.save(role);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SysRole> updateRole(UpdateRoleCommand command) {
|
||||
return roleRepository.findById(command.id())
|
||||
.switchIfEmpty(Mono.error(new RuntimeException("Role not found")))
|
||||
.flatMap(role -> {
|
||||
if (command.roleName() != null) {
|
||||
role.setRoleName(command.roleName());
|
||||
}
|
||||
if (command.roleKey() != null) {
|
||||
role.setRoleKey(command.roleKey());
|
||||
}
|
||||
if (command.roleSort() != null) {
|
||||
role.setRoleSort(command.roleSort());
|
||||
}
|
||||
if (command.status() != null) {
|
||||
role.setStatus(command.status());
|
||||
}
|
||||
role.setUpdatedAt(LocalDateTime.now());
|
||||
return roleRepository.save(role);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Mono<Void> deleteRole(Long id) {
|
||||
logger.debug("开始删除角色,ID: {}", id);
|
||||
|
||||
return roleRepository.findById(id)
|
||||
.flatMap(role -> {
|
||||
logger.debug("找到角色,开始删除关联记录");
|
||||
return userRoleRepository.deleteByRoleId(id)
|
||||
.doOnSuccess(v -> logger.debug("成功删除用户角色关联记录"))
|
||||
.doOnError(e -> logger.error("删除用户角色关联记录失败", e))
|
||||
.then(rolePermissionRepository.deleteByRoleId(id))
|
||||
.doOnSuccess(v -> logger.debug("成功删除角色权限关联记录"))
|
||||
.doOnError(e -> logger.error("删除角色权限关联记录失败", e))
|
||||
.then(userService.updateRoleIdToNullByRoleId(id))
|
||||
.doOnSuccess(v -> logger.debug("成功更新用户角色ID为null"))
|
||||
.doOnError(e -> logger.error("更新用户角色ID失败", e))
|
||||
.then(roleRepository.deleteById(id))
|
||||
.doOnSuccess(v -> logger.debug("成功删除角色"))
|
||||
.doOnError(e -> logger.error("删除角色失败", e));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SysRole> findByRoleName(String roleName) {
|
||||
return roleRepository.findByRoleName(roleName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Boolean> existsByRoleName(String roleName) {
|
||||
return roleRepository.existsByRoleName(roleName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SysRole> logicalDeleteRole(Long id) {
|
||||
return roleRepository.findByIdIncludingDeleted(id)
|
||||
.flatMap(role -> {
|
||||
role.delete();
|
||||
return roleRepository.updateRole(role);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SysRole> restoreRole(Long id) {
|
||||
return roleRepository.findByIdIncludingDeleted(id)
|
||||
.flatMap(role -> {
|
||||
role.restore();
|
||||
return roleRepository.updateRole(role);
|
||||
});
|
||||
}
|
||||
}
|
||||
+284
@@ -0,0 +1,284 @@
|
||||
package cn.novalon.gym.manage.sys.core.service.impl;
|
||||
|
||||
import cn.novalon.gym.manage.common.util.StatusConstants;
|
||||
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;
|
||||
import cn.novalon.gym.manage.common.dto.PageRequest;
|
||||
import cn.novalon.gym.manage.common.dto.PageResponse;
|
||||
import cn.novalon.gym.manage.sys.core.repository.ISysUserRepository;
|
||||
import cn.novalon.gym.manage.sys.core.repository.ISysRoleRepository;
|
||||
import cn.novalon.gym.manage.sys.core.repository.IUserRoleRepository;
|
||||
import cn.novalon.gym.manage.sys.core.service.ISysUserService;
|
||||
import cn.novalon.gym.manage.sys.core.command.CreateUserCommand;
|
||||
import cn.novalon.gym.manage.sys.core.command.UpdateUserCommand;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import reactor.core.publisher.Flux;
|
||||
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 {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SysUserService.class);
|
||||
private final ISysUserRepository userRepository;
|
||||
private final ISysRoleRepository roleRepository;
|
||||
private final IUserRoleRepository userRoleRepository;
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
|
||||
public SysUserService(ISysUserRepository userRepository,
|
||||
ISysRoleRepository roleRepository,
|
||||
IUserRoleRepository userRoleRepository,
|
||||
@Qualifier("passwordEncoder") PasswordEncoder passwordEncoder) {
|
||||
this.userRepository = userRepository;
|
||||
this.roleRepository = roleRepository;
|
||||
this.userRoleRepository = userRoleRepository;
|
||||
this.passwordEncoder = passwordEncoder;
|
||||
|
||||
logger.info("使用的密码编码器类型: {}", passwordEncoder.getClass().getName());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final BCryptPasswordEncoder directEncoder = new BCryptPasswordEncoder(12);
|
||||
|
||||
@Override
|
||||
public Mono<SysUser> findById(Long id) {
|
||||
return userRepository.findById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<SysUser> findAll() {
|
||||
return userRepository.findAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<SysUser> findAll(boolean includeDeleted) {
|
||||
if (includeDeleted) {
|
||||
return userRepository.findAll();
|
||||
} else {
|
||||
return userRepository.findByDeletedAtIsNull();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<PageResponse<SysUser>> findUsersByPage(PageRequest pageRequest) {
|
||||
return userRepository.findByQueryWithPagination(null, pageRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Long> count() {
|
||||
return userRepository.count();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SysUser> findByUsername(String username) {
|
||||
return userRepository.findByUsername(username);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SysUser> createUser(SysUser user) {
|
||||
logger.info("SysUserService.createUser - 用户名: {}, 密码前缀: {}",
|
||||
user.getUsername(),
|
||||
user.getPassword() != null ? user.getPassword().substring(0, 7) : "null");
|
||||
user.generateId();
|
||||
if (user.getPassword() != null && !user.getPassword().startsWith("$2a$")
|
||||
&& !user.getPassword().startsWith("$2b$")) {
|
||||
logger.info("密码不以$2a$或$2b$开头,重新编码");
|
||||
user.setPassword(passwordEncoder.encode(user.getPassword()));
|
||||
logger.info("重新编码后的密码前缀: {}", user.getPassword().substring(0, 7));
|
||||
} else {
|
||||
logger.info("密码已编码,跳过重新编码");
|
||||
}
|
||||
if (user.getStatus() == null) {
|
||||
user.setStatus(StatusConstants.ENABLED);
|
||||
}
|
||||
return userRepository.save(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SysUser> createUser(CreateUserCommand command) {
|
||||
SysUser user = new SysUser();
|
||||
user.generateId();
|
||||
user.setUsername(command.username().getValue());
|
||||
user.setPassword(passwordEncoder.encode(command.password().getValue()));
|
||||
user.setEmail(command.email().getValue());
|
||||
user.setNickname(command.nickname());
|
||||
user.setPhone(command.phone());
|
||||
user.setRoleId(command.roleId());
|
||||
user.setStatus(command.status() != null ? command.status() : StatusConstants.ENABLED);
|
||||
return userRepository.save(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SysUser> updateUser(SysUser user) {
|
||||
user.setUpdatedAt(LocalDateTime.now());
|
||||
return userRepository.save(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SysUser> updateUser(UpdateUserCommand command) {
|
||||
return userRepository.findById(command.id())
|
||||
.switchIfEmpty(Mono.error(new RuntimeException("User not found")))
|
||||
.flatMap(user -> {
|
||||
if (command.username() != null) {
|
||||
user.setUsername(command.username());
|
||||
}
|
||||
if (command.password() != null) {
|
||||
user.setPassword(passwordEncoder.encode(command.password()));
|
||||
}
|
||||
if (command.email() != null) {
|
||||
user.setEmail(command.email());
|
||||
}
|
||||
if (command.clearRole()) {
|
||||
user.setRoleId(null);
|
||||
} else if (command.roleId() != null) {
|
||||
user.setRoleId(command.roleId());
|
||||
}
|
||||
if (command.status() != null) {
|
||||
user.setStatus(command.status());
|
||||
}
|
||||
user.setUpdatedAt(LocalDateTime.now());
|
||||
return userRepository.save(user);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Mono<Void> deleteUser(Long id) {
|
||||
logger.debug("开始删除用户,ID: {}", id);
|
||||
|
||||
return userRepository.findById(id)
|
||||
.switchIfEmpty(Mono.error(new RuntimeException("User not found")))
|
||||
.flatMap(user -> {
|
||||
logger.debug("找到用户,开始删除关联记录");
|
||||
return userRoleRepository.deleteByUserId(id)
|
||||
.doOnSuccess(v -> logger.debug("成功删除用户角色关联记录"))
|
||||
.doOnError(e -> logger.error("删除用户角色关联记录失败", e))
|
||||
.then(userRepository.deleteById(id))
|
||||
.doOnSuccess(v -> logger.debug("成功删除用户"))
|
||||
.doOnError(e -> logger.error("删除用户失败", e));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> updateRoleIdToNullByRoleId(Long roleId) {
|
||||
return userRepository.updateRoleIdToNullByRoleId(roleId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SysUser> changePassword(Long userId, String oldPassword, String newPassword) {
|
||||
return userRepository.findById(userId)
|
||||
.flatMap(user -> {
|
||||
if (!passwordEncoder.matches(oldPassword, user.getPassword())) {
|
||||
return Mono.error(new RuntimeException("旧密码不正确"));
|
||||
}
|
||||
user.setPassword(passwordEncoder.encode(newPassword));
|
||||
user.setUpdatedAt(LocalDateTime.now());
|
||||
return userRepository.save(user);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Boolean> existsByUsername(String username) {
|
||||
return userRepository.findByUsername(username)
|
||||
.map(user -> user != null)
|
||||
.defaultIfEmpty(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Boolean> existsByEmail(String email) {
|
||||
return userRepository.findByEmail(email)
|
||||
.map(user -> user != null)
|
||||
.defaultIfEmpty(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> logicalDeleteUser(Long id) {
|
||||
return userRepository.findByIdIncludingDeleted(id)
|
||||
.flatMap(user -> {
|
||||
user.setDeletedAt(LocalDateTime.now());
|
||||
return userRepository.save(user);
|
||||
})
|
||||
.then();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> logicalDeleteUsers(List<Long> ids) {
|
||||
return userRepository.logicalDeleteByIds(ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> restoreUser(Long id) {
|
||||
return userRepository.findByIdIncludingDeleted(id)
|
||||
.flatMap(user -> {
|
||||
user.setDeletedAt(null);
|
||||
return userRepository.save(user);
|
||||
})
|
||||
.then();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> restoreUsers(List<Long> ids) {
|
||||
return userRepository.restoreByIds(ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Mono<Void> assignRolesToUser(Long userId, List<Long> roleIds) {
|
||||
logger.debug("开始为用户分配角色,用户ID: {}, 角色IDs: {}", userId, roleIds);
|
||||
|
||||
if (roleIds == null || roleIds.isEmpty()) {
|
||||
logger.debug("角色列表为空,删除用户的所有角色关联");
|
||||
return userRoleRepository.deleteByUserId(userId)
|
||||
.doOnSuccess(v -> logger.debug("成功删除用户的所有角色关联"))
|
||||
.doOnError(e -> logger.error("删除用户角色关联失败", e));
|
||||
}
|
||||
|
||||
return userRoleRepository.deleteByUserId(userId)
|
||||
.doOnSuccess(v -> logger.debug("成功删除用户的旧角色关联"))
|
||||
.doOnError(e -> logger.error("删除用户旧角色关联失败", e))
|
||||
.then(
|
||||
Flux.fromIterable(roleIds)
|
||||
.concatMap(roleId -> {
|
||||
logger.debug("为用户分配角色ID: {}", roleId);
|
||||
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());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<SysRole> getUserRoles(Long userId) {
|
||||
return userRoleRepository.findByUserId(userId)
|
||||
.flatMap(userRole -> roleRepository.findById(userRole.getRoleId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<Long> getUserRoleIds(Long userId) {
|
||||
return userRoleRepository.findByUserId(userId)
|
||||
.map(UserRole::getRoleId);
|
||||
}
|
||||
}
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
package cn.novalon.gym.manage.sys.core.util;
|
||||
|
||||
import cn.novalon.gym.manage.sys.core.domain.OperationLog;
|
||||
import org.apache.poi.ss.usermodel.*;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Excel导出工具类
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-04-03
|
||||
*/
|
||||
public class ExcelExportUtil {
|
||||
|
||||
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
/**
|
||||
* 导出操作日志到Excel
|
||||
*
|
||||
* @param logs 操作日志列表
|
||||
* @return Excel文件字节数组
|
||||
* @throws IOException IO异常
|
||||
*/
|
||||
public static byte[] exportOperationLogs(List<OperationLog> logs) throws IOException {
|
||||
try (Workbook workbook = new XSSFWorkbook();
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
|
||||
|
||||
Sheet sheet = workbook.createSheet("操作日志");
|
||||
|
||||
CellStyle headerStyle = createHeaderStyle(workbook);
|
||||
CellStyle dateStyle = createDateStyle(workbook);
|
||||
|
||||
Row headerRow = sheet.createRow(0);
|
||||
String[] headers = {"ID", "操作人", "操作模块", "请求方法", "请求参数", "执行结果",
|
||||
"IP地址", "耗时(ms)", "状态", "错误信息", "操作时间"};
|
||||
|
||||
for (int i = 0; i < headers.length; i++) {
|
||||
Cell cell = headerRow.createCell(i);
|
||||
cell.setCellValue(headers[i]);
|
||||
cell.setCellStyle(headerStyle);
|
||||
sheet.setColumnWidth(i, 20 * 256);
|
||||
}
|
||||
|
||||
int rowNum = 1;
|
||||
for (OperationLog log : logs) {
|
||||
Row row = sheet.createRow(rowNum++);
|
||||
|
||||
row.createCell(0).setCellValue(log.getId() != null ? log.getId() : 0);
|
||||
row.createCell(1).setCellValue(log.getUsername() != null ? log.getUsername() : "");
|
||||
row.createCell(2).setCellValue(log.getOperation() != null ? log.getOperation() : "");
|
||||
row.createCell(3).setCellValue(log.getMethod() != null ? log.getMethod() : "");
|
||||
row.createCell(4).setCellValue(truncateText(log.getParams(), 1000));
|
||||
row.createCell(5).setCellValue(truncateText(log.getResult(), 1000));
|
||||
row.createCell(6).setCellValue(log.getIp() != null ? log.getIp() : "");
|
||||
row.createCell(7).setCellValue(log.getDuration() != null ? log.getDuration() : 0);
|
||||
row.createCell(8).setCellValue("0".equals(log.getStatus()) ? "成功" : "失败");
|
||||
row.createCell(9).setCellValue(log.getErrorMsg() != null ? log.getErrorMsg() : "");
|
||||
|
||||
Cell dateCell = row.createCell(10);
|
||||
if (log.getCreatedAt() != null) {
|
||||
dateCell.setCellValue(log.getCreatedAt().format(DATE_TIME_FORMATTER));
|
||||
dateCell.setCellStyle(dateStyle);
|
||||
}
|
||||
}
|
||||
|
||||
workbook.write(outputStream);
|
||||
return outputStream.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
private static CellStyle createHeaderStyle(Workbook workbook) {
|
||||
CellStyle style = workbook.createCellStyle();
|
||||
style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
|
||||
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
|
||||
style.setBorderBottom(BorderStyle.THIN);
|
||||
style.setBorderTop(BorderStyle.THIN);
|
||||
style.setBorderLeft(BorderStyle.THIN);
|
||||
style.setBorderRight(BorderStyle.THIN);
|
||||
style.setAlignment(HorizontalAlignment.CENTER);
|
||||
style.setVerticalAlignment(VerticalAlignment.CENTER);
|
||||
|
||||
Font font = workbook.createFont();
|
||||
font.setBold(true);
|
||||
font.setFontHeightInPoints((short) 12);
|
||||
style.setFont(font);
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
private static CellStyle createDateStyle(Workbook workbook) {
|
||||
CellStyle style = workbook.createCellStyle();
|
||||
style.setAlignment(HorizontalAlignment.CENTER);
|
||||
style.setVerticalAlignment(VerticalAlignment.CENTER);
|
||||
return style;
|
||||
}
|
||||
|
||||
private static String truncateText(String text, int maxLength) {
|
||||
if (text == null) {
|
||||
return "";
|
||||
}
|
||||
if (text.length() <= maxLength) {
|
||||
return text;
|
||||
}
|
||||
return text.substring(0, maxLength) + "...";
|
||||
}
|
||||
}
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
package cn.novalon.gym.manage.sys.core.util;
|
||||
|
||||
import cn.novalon.gym.manage.sys.core.domain.SysConfig;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 系统配置验证工具类
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-31
|
||||
*/
|
||||
public class ValidationUtil {
|
||||
|
||||
// 配置键正则表达式:只允许字母、数字、下划线、点号,长度1-100
|
||||
private static final Pattern CONFIG_KEY_PATTERN = Pattern.compile("^[a-zA-Z0-9_.-]{1,100}$");
|
||||
|
||||
// 配置名称正则表达式:允许中文、字母、数字、下划线、空格,长度1-50
|
||||
private static final Pattern CONFIG_NAME_PATTERN = Pattern.compile("^[\\u4e00-\\u9fa5a-zA-Z0-9_\\\\.\\s]{1,50}$");
|
||||
|
||||
// 配置类型正则表达式:只允许字母、数字、下划线,长度1-20
|
||||
private static final Pattern CONFIG_TYPE_PATTERN = Pattern.compile("^[a-zA-Z0-9_]{1,20}$");
|
||||
|
||||
/**
|
||||
* 验证配置对象
|
||||
*/
|
||||
public static Mono<SysConfig> validateConfig(SysConfig config) {
|
||||
if (config == null) {
|
||||
return Mono.error(new IllegalArgumentException("配置对象不能为空"));
|
||||
}
|
||||
|
||||
// 验证配置键
|
||||
if (!isValidConfigKey(config.getConfigKey())) {
|
||||
return Mono.error(new IllegalArgumentException("配置键格式无效,只允许字母、数字、下划线、点号,长度1-100"));
|
||||
}
|
||||
|
||||
// 验证配置名称
|
||||
if (!isValidConfigName(config.getConfigName())) {
|
||||
return Mono.error(new IllegalArgumentException("配置名称格式无效,允许中文、字母、数字、下划线、空格,长度1-50"));
|
||||
}
|
||||
|
||||
// 验证配置类型
|
||||
if (config.getConfigType() != null && !isValidConfigType(config.getConfigType())) {
|
||||
return Mono.error(new IllegalArgumentException("配置类型格式无效,只允许字母、数字、下划线,长度1-20"));
|
||||
}
|
||||
|
||||
// 验证配置值长度
|
||||
if (config.getConfigValue() != null && config.getConfigValue().length() > 5000) {
|
||||
return Mono.error(new IllegalArgumentException("配置值长度不能超过5000个字符"));
|
||||
}
|
||||
|
||||
return Mono.just(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证配置键
|
||||
*/
|
||||
public static boolean isValidConfigKey(String configKey) {
|
||||
return configKey != null && CONFIG_KEY_PATTERN.matcher(configKey).matches();
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证配置名称
|
||||
*/
|
||||
public static boolean isValidConfigName(String configName) {
|
||||
return configName != null && CONFIG_NAME_PATTERN.matcher(configName).matches();
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证配置类型
|
||||
*/
|
||||
public static boolean isValidConfigType(String configType) {
|
||||
return configType == null || CONFIG_TYPE_PATTERN.matcher(configType).matches();
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证ID参数
|
||||
*/
|
||||
public static Mono<Long> validateId(String idStr) {
|
||||
try {
|
||||
Long id = Long.valueOf(idStr);
|
||||
if (id <= 0) {
|
||||
return Mono.error(new IllegalArgumentException("ID必须大于0"));
|
||||
}
|
||||
return Mono.just(id);
|
||||
} catch (NumberFormatException e) {
|
||||
return Mono.error(new IllegalArgumentException("ID格式无效"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建错误响应
|
||||
*/
|
||||
public static Mono<ServerResponse> createErrorResponse(String message) {
|
||||
return ServerResponse.status(HttpStatus.BAD_REQUEST)
|
||||
.bodyValue(new ErrorResponse(message));
|
||||
}
|
||||
|
||||
/**
|
||||
* 错误响应对象
|
||||
*/
|
||||
public static class ErrorResponse {
|
||||
private final String message;
|
||||
private final long timestamp;
|
||||
|
||||
public ErrorResponse(String message) {
|
||||
this.message = message;
|
||||
this.timestamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package cn.novalon.gym.manage.sys.dto.request;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class AssignRolesRequest {
|
||||
private List<Long> roleIds;
|
||||
|
||||
public List<Long> getRoleIds() {
|
||||
return roleIds;
|
||||
}
|
||||
|
||||
public void setRoleIds(List<Long> roleIds) {
|
||||
this.roleIds = roleIds;
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package cn.novalon.gym.manage.sys.dto.request;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* 登录请求DTO
|
||||
*
|
||||
* 文件定义:封装用户登录请求的参数
|
||||
* 涉及业务:用户登录认证
|
||||
* 算法:使用Jakarta Validation进行参数验证
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
@Schema(description = "用户登录请求")
|
||||
public class LoginRequest {
|
||||
|
||||
@Schema(description = "用户名", example = "admin")
|
||||
@NotBlank(message = "用户名不能为空")
|
||||
private String username;
|
||||
|
||||
@Schema(description = "密码", example = "123456")
|
||||
@NotBlank(message = "密码不能为空")
|
||||
private String password;
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
package cn.novalon.gym.manage.sys.dto.request;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* 菜单创建请求DTO
|
||||
*
|
||||
* 文件定义:用于创建菜单的请求DTO对象,封装HTTP请求参数
|
||||
* 涉及业务:菜单管理、权限分配等场景
|
||||
* 算法:通过验证注解确保请求参数的有效性
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public class MenuCreateRequest {
|
||||
|
||||
private Long parentId;
|
||||
|
||||
@NotBlank(message = "菜单名称不能为空")
|
||||
private String menuName;
|
||||
|
||||
@NotBlank(message = "菜单类型不能为空")
|
||||
private String menuType;
|
||||
|
||||
private Integer orderNum;
|
||||
|
||||
private String component;
|
||||
|
||||
private String perms;
|
||||
|
||||
private Integer status;
|
||||
|
||||
public Long getParentId() {
|
||||
return parentId;
|
||||
}
|
||||
|
||||
public void setParentId(Long parentId) {
|
||||
this.parentId = parentId;
|
||||
}
|
||||
|
||||
public String getMenuName() {
|
||||
return menuName;
|
||||
}
|
||||
|
||||
public void setMenuName(String menuName) {
|
||||
this.menuName = menuName;
|
||||
}
|
||||
|
||||
public String getMenuType() {
|
||||
return menuType;
|
||||
}
|
||||
|
||||
public void setMenuType(String menuType) {
|
||||
this.menuType = menuType;
|
||||
}
|
||||
|
||||
public Integer getOrderNum() {
|
||||
return orderNum;
|
||||
}
|
||||
|
||||
public void setOrderNum(Integer orderNum) {
|
||||
this.orderNum = orderNum;
|
||||
}
|
||||
|
||||
public String getComponent() {
|
||||
return component;
|
||||
}
|
||||
|
||||
public void setComponent(String component) {
|
||||
this.component = component;
|
||||
}
|
||||
|
||||
public String getPerms() {
|
||||
return perms;
|
||||
}
|
||||
|
||||
public void setPerms(String perms) {
|
||||
this.perms = perms;
|
||||
}
|
||||
|
||||
public Integer getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(Integer status) {
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
package cn.novalon.gym.manage.sys.dto.request;
|
||||
|
||||
/**
|
||||
* 菜单更新请求DTO
|
||||
*
|
||||
* 文件定义:用于更新菜单的请求DTO对象,封装HTTP请求参数
|
||||
* 涉及业务:菜单管理、权限分配等场景
|
||||
* 算法:支持部分字段更新,通过验证注解确保请求参数的有效性
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public class MenuUpdateRequest {
|
||||
|
||||
private Long parentId;
|
||||
|
||||
private String menuName;
|
||||
|
||||
private String menuType;
|
||||
|
||||
private Integer orderNum;
|
||||
|
||||
private String component;
|
||||
|
||||
private String perms;
|
||||
|
||||
private Integer status;
|
||||
|
||||
public Long getParentId() {
|
||||
return parentId;
|
||||
}
|
||||
|
||||
public void setParentId(Long parentId) {
|
||||
this.parentId = parentId;
|
||||
}
|
||||
|
||||
public String getMenuName() {
|
||||
return menuName;
|
||||
}
|
||||
|
||||
public void setMenuName(String menuName) {
|
||||
this.menuName = menuName;
|
||||
}
|
||||
|
||||
public String getMenuType() {
|
||||
return menuType;
|
||||
}
|
||||
|
||||
public void setMenuType(String menuType) {
|
||||
this.menuType = menuType;
|
||||
}
|
||||
|
||||
public Integer getOrderNum() {
|
||||
return orderNum;
|
||||
}
|
||||
|
||||
public void setOrderNum(Integer orderNum) {
|
||||
this.orderNum = orderNum;
|
||||
}
|
||||
|
||||
public String getComponent() {
|
||||
return component;
|
||||
}
|
||||
|
||||
public void setComponent(String component) {
|
||||
this.component = component;
|
||||
}
|
||||
|
||||
public String getPerms() {
|
||||
return perms;
|
||||
}
|
||||
|
||||
public void setPerms(String perms) {
|
||||
this.perms = perms;
|
||||
}
|
||||
|
||||
public Integer getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(Integer status) {
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package cn.novalon.gym.manage.sys.dto.request;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* 密码修改请求DTO
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-14
|
||||
*/
|
||||
public class PasswordChangeRequest {
|
||||
|
||||
@NotBlank(message = "旧密码不能为空")
|
||||
private String oldPassword;
|
||||
|
||||
@NotBlank(message = "新密码不能为空")
|
||||
private String newPassword;
|
||||
|
||||
public String getOldPassword() {
|
||||
return oldPassword;
|
||||
}
|
||||
|
||||
public void setOldPassword(String oldPassword) {
|
||||
this.oldPassword = oldPassword;
|
||||
}
|
||||
|
||||
public String getNewPassword() {
|
||||
return newPassword;
|
||||
}
|
||||
|
||||
public void setNewPassword(String newPassword) {
|
||||
this.newPassword = newPassword;
|
||||
}
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
package cn.novalon.gym.manage.sys.dto.request;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
/**
|
||||
* 角色创建请求DTO
|
||||
*
|
||||
* 文件定义:用于创建角色的请求DTO对象,封装HTTP请求参数
|
||||
* 涉及业务:角色管理、权限分配等场景
|
||||
* 算法:通过验证注解确保请求参数的有效性
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
@Schema(description = "角色创建请求")
|
||||
public class RoleCreateRequest {
|
||||
|
||||
@Schema(description = "角色名称", example = "管理员")
|
||||
@NotBlank(message = "角色名称不能为空")
|
||||
@Size(min = 2, max = 50, message = "角色名称长度必须在2-50之间")
|
||||
private String roleName;
|
||||
|
||||
@Schema(description = "角色权限字符串", example = "admin")
|
||||
@NotBlank(message = "角色权限字符串不能为空")
|
||||
@Size(min = 2, max = 50, message = "角色权限字符串长度必须在2-50之间")
|
||||
@Pattern(regexp = "^[a-zA-Z0-9_-]+$", message = "角色权限字符串只能包含字母、数字、下划线和横线")
|
||||
private String roleKey;
|
||||
|
||||
@Schema(description = "显示顺序", example = "1")
|
||||
@NotNull(message = "显示顺序不能为空")
|
||||
@Min(value = 1, message = "显示顺序必须大于0")
|
||||
private Integer roleSort;
|
||||
|
||||
@Schema(description = "状态", example = "1")
|
||||
private Integer status;
|
||||
|
||||
public String getRoleName() {
|
||||
return roleName;
|
||||
}
|
||||
|
||||
public void setRoleName(String roleName) {
|
||||
this.roleName = roleName;
|
||||
}
|
||||
|
||||
public String getRoleKey() {
|
||||
return roleKey;
|
||||
}
|
||||
|
||||
public void setRoleKey(String roleKey) {
|
||||
this.roleKey = roleKey;
|
||||
}
|
||||
|
||||
public Integer getRoleSort() {
|
||||
return roleSort;
|
||||
}
|
||||
|
||||
public void setRoleSort(Integer roleSort) {
|
||||
this.roleSort = roleSort;
|
||||
}
|
||||
|
||||
public Integer getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(Integer status) {
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
package cn.novalon.gym.manage.sys.dto.request;
|
||||
|
||||
/**
|
||||
* 角色更新请求DTO
|
||||
*
|
||||
* 文件定义:用于更新角色的请求DTO对象,封装HTTP请求参数
|
||||
* 涉及业务:角色管理、权限分配等场景
|
||||
* 算法:支持部分字段更新,通过验证注解确保请求参数的有效性
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-13
|
||||
*/
|
||||
public class RoleUpdateRequest {
|
||||
|
||||
private String roleName;
|
||||
|
||||
private String roleKey;
|
||||
|
||||
private Integer roleSort;
|
||||
|
||||
private Integer status;
|
||||
|
||||
public String getRoleName() {
|
||||
return roleName;
|
||||
}
|
||||
|
||||
public void setRoleName(String roleName) {
|
||||
this.roleName = roleName;
|
||||
}
|
||||
|
||||
public String getRoleKey() {
|
||||
return roleKey;
|
||||
}
|
||||
|
||||
public void setRoleKey(String roleKey) {
|
||||
this.roleKey = roleKey;
|
||||
}
|
||||
|
||||
public Integer getRoleSort() {
|
||||
return roleSort;
|
||||
}
|
||||
|
||||
public void setRoleSort(Integer roleSort) {
|
||||
this.roleSort = roleSort;
|
||||
}
|
||||
|
||||
public Integer getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(Integer status) {
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
package cn.novalon.gym.manage.sys.dto.request;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.Email;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户注册请求DTO
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-14
|
||||
*/
|
||||
@Schema(description = "用户注册请求")
|
||||
public class UserRegisterRequest {
|
||||
|
||||
@Schema(description = "用户名", example = "testuser")
|
||||
@NotBlank(message = "用户名不能为空")
|
||||
@Size(min = 3, max = 50, message = "用户名长度必须在3-50之间")
|
||||
@Pattern(regexp = "^[a-zA-Z0-9_-]+$", message = "用户名只能包含字母、数字、下划线和横线")
|
||||
private String username;
|
||||
|
||||
@Schema(description = "昵称", example = "测试用户")
|
||||
@Size(max = 100, message = "昵称长度不能超过100")
|
||||
private String nickname;
|
||||
|
||||
@Schema(description = "密码", example = "Admin123")
|
||||
@NotBlank(message = "密码不能为空")
|
||||
@Size(min = 8, max = 20, message = "密码长度必须在8-20之间")
|
||||
@Pattern(regexp = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).+$", message = "密码必须包含大小写字母和数字")
|
||||
private String password;
|
||||
|
||||
@Schema(description = "邮箱", example = "test@example.com")
|
||||
@NotBlank(message = "邮箱不能为空")
|
||||
@Email(message = "邮箱格式不正确")
|
||||
@Size(max = 100, message = "邮箱长度不能超过100")
|
||||
private String email;
|
||||
|
||||
@Schema(description = "手机号", example = "13800138000")
|
||||
@NotBlank(message = "手机号不能为空")
|
||||
@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
|
||||
private String phone;
|
||||
|
||||
@Schema(description = "角色ID列表", example = "[1, 2]")
|
||||
private List<Long> roles;
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getNickname() {
|
||||
return nickname;
|
||||
}
|
||||
|
||||
public void setNickname(String nickname) {
|
||||
this.nickname = nickname;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getPhone() {
|
||||
return phone;
|
||||
}
|
||||
|
||||
public void setPhone(String phone) {
|
||||
this.phone = phone;
|
||||
}
|
||||
|
||||
public List<Long> getRoles() {
|
||||
return roles;
|
||||
}
|
||||
|
||||
public void setRoles(List<Long> roles) {
|
||||
this.roles = roles;
|
||||
}
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package cn.novalon.gym.manage.sys.dto.request;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.Email;
|
||||
|
||||
/**
|
||||
* 用户更新请求DTO
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-14
|
||||
*/
|
||||
@Schema(description = "用户更新请求")
|
||||
public class UserUpdateRequest {
|
||||
|
||||
@Schema(description = "邮箱", example = "newemail@example.com")
|
||||
private String email;
|
||||
|
||||
@Schema(description = "状态:0-禁用,1-正常", example = "1")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "角色ID", example = "1")
|
||||
private Long roleId;
|
||||
|
||||
@Schema(description = "是否清除角色关联", example = "false")
|
||||
private Boolean clearRole;
|
||||
|
||||
@Email(message = "邮箱格式不正确")
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public Integer getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(Integer status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public Long getRoleId() {
|
||||
return roleId;
|
||||
}
|
||||
|
||||
public void setRoleId(Long roleId) {
|
||||
this.roleId = roleId;
|
||||
}
|
||||
|
||||
public Boolean getClearRole() {
|
||||
return clearRole;
|
||||
}
|
||||
|
||||
public void setClearRole(Boolean clearRole) {
|
||||
this.clearRole = clearRole;
|
||||
}
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
package cn.novalon.gym.manage.sys.dto.response;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
/**
|
||||
* 认证响应DTO
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-14
|
||||
*/
|
||||
@Schema(description = "用户认证响应")
|
||||
public class AuthResponse {
|
||||
|
||||
@Schema(description = "JWT访问令牌", example = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...")
|
||||
private String token;
|
||||
|
||||
@Schema(description = "用户ID", example = "1")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "用户名", example = "admin")
|
||||
private String username;
|
||||
|
||||
public AuthResponse() {
|
||||
}
|
||||
|
||||
public AuthResponse(String token, Long userId, String username) {
|
||||
this.token = token;
|
||||
this.userId = userId;
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public void setToken(String token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public Long getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(Long userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
package cn.novalon.gym.manage.sys.dto.response;
|
||||
|
||||
/**
|
||||
* 文件预览响应DTO
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-03-14
|
||||
*/
|
||||
public class FilePreviewResponse {
|
||||
private String fileName;
|
||||
private String fileType;
|
||||
private Long fileSize;
|
||||
private String previewType;
|
||||
private String previewData;
|
||||
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public void setFileName(String fileName) {
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
public String getFileType() {
|
||||
return fileType;
|
||||
}
|
||||
|
||||
public void setFileType(String fileType) {
|
||||
this.fileType = fileType;
|
||||
}
|
||||
|
||||
public Long getFileSize() {
|
||||
return fileSize;
|
||||
}
|
||||
|
||||
public void setFileSize(Long fileSize) {
|
||||
this.fileSize = fileSize;
|
||||
}
|
||||
|
||||
public String getPreviewType() {
|
||||
return previewType;
|
||||
}
|
||||
|
||||
public void setPreviewType(String previewType) {
|
||||
this.previewType = previewType;
|
||||
}
|
||||
|
||||
public String getPreviewData() {
|
||||
return previewData;
|
||||
}
|
||||
|
||||
public void setPreviewData(String previewData) {
|
||||
this.previewData = previewData;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user