feat: 更新端口配置并添加监控支持

fix: 修复测试配置和依赖检查

perf: 优化雪花算法性能

refactor: 清理冗余代码和未使用的导入

style: 统一代码格式和注释

test: 添加单元测试和集成测试

ci: 更新CI配置和构建脚本

chore: 更新依赖和配置文件
This commit is contained in:
张翔
2026-03-13 08:50:19 +08:00
parent fe2e4110dd
commit 9f8bf041c3
169 changed files with 3565 additions and 132 deletions
@@ -1,9 +1,12 @@
package cn.novalon.manage.sys;
import cn.novalon.manage.sys.config.JwtProperties;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@SpringBootApplication
@EnableConfigurationProperties(JwtProperties.class)
public class ManageSysApplication {
public static void main(String[] args) {
SpringApplication.run(ManageSysApplication.class, args);
@@ -0,0 +1,30 @@
package cn.novalon.manage.sys.config;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.TimeUnit;
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
cacheManager.setCaffeine(caffeineCacheBuilder());
return cacheManager;
}
private Caffeine<Object, Object> caffeineCacheBuilder() {
return Caffeine.newBuilder()
.initialCapacity(100)
.maximumSize(500)
.expireAfterWrite(30, TimeUnit.MINUTES)
.recordStats();
}
}
@@ -0,0 +1,30 @@
package cn.novalon.manage.sys.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
@Component
@ConfigurationProperties(prefix = "jwt")
@Validated
public class JwtProperties {
private String secret = "default-secret-key-change-in-production";
private long expiration = 86400000;
public String getSecret() {
return secret;
}
public void setSecret(String secret) {
this.secret = secret;
}
public long getExpiration() {
return expiration;
}
public void setExpiration(long expiration) {
this.expiration = expiration;
}
}
@@ -4,8 +4,6 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.codec.multipart.DefaultPartHttpMessageReader;
import org.springframework.http.codec.multipart.MultipartHttpMessageReader;
import org.springframework.web.reactive.function.client.ExchangeStrategies;
import org.springframework.web.reactive.function.client.WebClient;
@Configuration
public class MultipartConfig {
@@ -0,0 +1,45 @@
package cn.novalon.manage.sys.config;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import io.swagger.v3.oas.models.servers.Server;
import io.swagger.v3.oas.models.tags.Tag;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Arrays;
import java.util.List;
@Configuration
public class OpenApiConfig {
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(new Info()
.title("Novalon Manage System API")
.version("1.0.0")
.description("Novalon 管理系统 RESTful API 文档")
.contact(new Contact()
.name("Novalon Team")
.email("support@novalon.cn"))
.license(new License()
.name("Apache 2.0")
.url("https://www.apache.org/licenses/LICENSE-2.0")))
.servers(List.of(
new Server().url("http://localhost:8080").description("开发环境"),
new Server().url("https://api.novalon.cn").description("生产环境")))
.tags(Arrays.asList(
new Tag().name("用户管理").description("用户相关操作"),
new Tag().name("角色管理").description("角色相关操作"),
new Tag().name("配置管理").description("系统配置相关操作"),
new Tag().name("字典管理").description("字典数据相关操作"),
new Tag().name("通知管理").description("系统通知相关操作"),
new Tag().name("文件管理").description("文件上传下载相关操作"),
new Tag().name("日志管理").description("操作日志相关操作"),
new Tag().name("认证管理").description("登录认证相关操作"),
new Tag().name("统计信息").description("系统统计相关操作")));
}
}
@@ -16,7 +16,6 @@ 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;
@Configuration
@@ -114,15 +113,15 @@ public class SystemRouter {
public RouterFunction<ServerResponse> logRoutes(SysLogHandler logHandler) {
return route()
.GET("/api/logs/login", logHandler::getAllLoginLogs)
.GET("/api/logs/login/{id}", logHandler::getLoginLogById)
.POST("/api/logs/login", logHandler::createLoginLog)
.GET("/api/logs/login/page", logHandler::getLoginLogsByPage)
.GET("/api/logs/login/count", logHandler::getLoginLogCount)
.GET("/api/logs/login/{id}", logHandler::getLoginLogById)
.POST("/api/logs/login", logHandler::createLoginLog)
.GET("/api/logs/exception", logHandler::getAllExceptionLogs)
.GET("/api/logs/exception/{id}", logHandler::getExceptionLogById)
.POST("/api/logs/exception", logHandler::createExceptionLog)
.GET("/api/logs/exception/page", logHandler::getExceptionLogsByPage)
.GET("/api/logs/exception/count", logHandler::getExceptionLogCount)
.GET("/api/logs/exception/{id}", logHandler::getExceptionLogById)
.POST("/api/logs/exception", logHandler::createExceptionLog)
.build();
}
@@ -164,8 +163,8 @@ public class SystemRouter {
.PUT("/api/dict/types/{id}", dictHandler::updateDictType)
.DELETE("/api/dict/types/{id}", dictHandler::deleteDictType)
.GET("/api/dict/data", dictHandler::getAllDictData)
.GET("/api/dict/data/{id}", dictHandler::getDictDataById)
.GET("/api/dict/data/type/{dictType}", dictHandler::getDictDataByType)
.GET("/api/dict/data/{id}", dictHandler::getDictDataById)
.POST("/api/dict/data", dictHandler::createDictData)
.PUT("/api/dict/data/{id}", dictHandler::updateDictData)
.DELETE("/api/dict/data/{id}", dictHandler::deleteDictData)
@@ -11,6 +11,8 @@ import java.time.LocalDateTime;
public abstract class BaseDomain {
protected Long id;
protected String createBy;
protected String updateBy;
protected LocalDateTime createdAt;
protected LocalDateTime updatedAt;
protected LocalDateTime deletedAt;
@@ -23,6 +25,22 @@ public abstract class BaseDomain {
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;
}
@@ -11,8 +11,10 @@ public class Dictionary {
private String remark;
private Integer sort;
private String createBy;
private String updateBy;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
private LocalDateTime deletedAt;
public Dictionary() {
}
@@ -81,6 +83,14 @@ public class Dictionary {
this.createBy = createBy;
}
public String getUpdateBy() {
return updateBy;
}
public void setUpdateBy(String updateBy) {
this.updateBy = updateBy;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
@@ -96,4 +106,12 @@ public class Dictionary {
public void setUpdatedAt(LocalDateTime updatedAt) {
this.updatedAt = updatedAt;
}
public LocalDateTime getDeletedAt() {
return deletedAt;
}
public void setDeletedAt(LocalDateTime deletedAt) {
this.deletedAt = deletedAt;
}
}
@@ -13,6 +13,7 @@ public class SysConfig {
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; }
@@ -32,4 +33,6 @@ public class SysConfig {
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; }
}
@@ -18,6 +18,7 @@ public class SysDictData {
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; }
@@ -47,4 +48,6 @@ public class SysDictData {
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; }
}
@@ -13,6 +13,7 @@ public class SysDictType {
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; }
@@ -32,4 +33,6 @@ public class SysDictType {
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; }
}
@@ -11,7 +11,9 @@ public class SysFile {
private String fileType;
private String storageType;
private String createBy;
private String updateBy;
private LocalDateTime createdAt;
private LocalDateTime deletedAt;
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
@@ -27,6 +29,10 @@ public class SysFile {
public void setStorageType(String storageType) { this.storageType = storageType; }
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 getDeletedAt() { return deletedAt; }
public void setDeletedAt(LocalDateTime deletedAt) { this.deletedAt = deletedAt; }
}
@@ -11,6 +11,8 @@ public class SysMenu extends BaseDomain {
private String perms;
private String component;
private String status;
private String createBy;
private String updateBy;
private List<SysMenu> children;
public String getMenuName() {
@@ -69,6 +71,22 @@ public class SysMenu extends BaseDomain {
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;
}
@@ -13,6 +13,7 @@ public class SysNotice {
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; }
@@ -32,4 +33,6 @@ public class SysNotice {
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; }
}
@@ -5,7 +5,6 @@ import cn.novalon.manage.sys.core.exception.DictionaryAlreadyExistsException;
import cn.novalon.manage.sys.core.service.IDictionaryService;
import cn.novalon.manage.sys.infrastructure.db.converter.DictionaryConverter;
import cn.novalon.manage.sys.infrastructure.db.dao.DictionaryDao;
import cn.novalon.manage.sys.infrastructure.db.entity.DictionaryEntity;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@@ -11,6 +11,7 @@ import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@Service
@@ -70,9 +71,11 @@ public class SysLoginLogService implements ISysLoginLogService {
return allLogs
.collectList()
.map(list -> {
.flatMap(list -> {
List<SysLoginLog> sortedList = new ArrayList<>(list);
if (pageRequest.getSort() != null && !pageRequest.getSort().isEmpty()) {
list.sort((a, b) -> {
sortedList.sort((a, b) -> {
int comparison = 0;
if ("username".equals(pageRequest.getSort())) {
comparison = compareStrings(a.getUsername(), b.getUsername());
@@ -84,7 +87,8 @@ public class SysLoginLogService implements ISysLoginLogService {
return "desc".equalsIgnoreCase(pageRequest.getOrder()) ? -comparison : comparison;
});
}
return list;
return Mono.just(sortedList);
})
.zipWith(dao.count())
.map(tuple -> {
@@ -126,4 +130,4 @@ public class SysLoginLogService implements ISysLoginLogService {
public Mono<Long> count() {
return dao.count();
}
}
}
@@ -9,7 +9,6 @@ import cn.novalon.manage.sys.dto.request.PageRequest;
import cn.novalon.manage.sys.dto.response.PageResponse;
import cn.novalon.manage.sys.infrastructure.db.entity.query.SysRoleQueryCriteria;
import cn.novalon.manage.sys.infrastructure.db.utils.QueryUtil;
import org.springframework.data.domain.Sort;
import org.springframework.data.relational.core.query.Query;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
@@ -25,7 +25,7 @@ public final class SnowflakeId {
private static final long DEFAULT_EPOCH = 1582136402000L;
private static final int MAX_RETRIES = 10;
private static final long MAX_BACKWARD_MS = 50;
private static final int SPIN_THRESHOLD = 100;
private static final int SPIN_THRESHOLD = 5;
private static final long TIME_CACHE_DURATION_MS = 16;
private static final AtomicLong lastTimestamp = new AtomicLong(-1L);
@@ -9,10 +9,16 @@ import cn.novalon.manage.sys.core.service.ISysUserService;
import org.springframework.http.HttpStatus;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.support.WebExchangeBindException;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.stream.Collectors;
@Component
public class SysAuthHandler {
@@ -20,7 +26,8 @@ public class SysAuthHandler {
private final PasswordEncoder passwordEncoder;
private final JwtTokenProvider jwtTokenProvider;
public SysAuthHandler(ISysUserService userService, PasswordEncoder passwordEncoder, JwtTokenProvider jwtTokenProvider) {
public SysAuthHandler(ISysUserService userService, PasswordEncoder passwordEncoder,
JwtTokenProvider jwtTokenProvider) {
this.userService = userService;
this.passwordEncoder = passwordEncoder;
this.jwtTokenProvider = jwtTokenProvider;
@@ -28,6 +35,12 @@ public class SysAuthHandler {
public Mono<ServerResponse> login(ServerRequest request) {
return request.bodyToMono(LoginRequest.class)
.filter(loginRequest -> loginRequest.getUsername() != null
&& !loginRequest.getUsername().trim().isEmpty())
.switchIfEmpty(Mono.error(new IllegalArgumentException("用户名不能为空")))
.filter(loginRequest -> loginRequest.getPassword() != null
&& !loginRequest.getPassword().trim().isEmpty())
.switchIfEmpty(Mono.error(new IllegalArgumentException("密码不能为空")))
.flatMap(loginRequest -> userService.findByUsername(loginRequest.getUsername())
.filter(user -> passwordEncoder.matches(loginRequest.getPassword(), user.getPassword()))
.filter(user -> 1 == user.getStatus())
@@ -36,7 +49,22 @@ public class SysAuthHandler {
AuthResponse response = new AuthResponse(token, user.getId(), user.getUsername());
return ServerResponse.ok().bodyValue(response);
})
.switchIfEmpty(ServerResponse.status(HttpStatus.UNAUTHORIZED).build()));
.switchIfEmpty(ServerResponse.status(HttpStatus.UNAUTHORIZED).build()))
.onErrorResume(WebExchangeBindException.class, ex -> {
String errorMessage = ex.getBindingResult().getFieldErrors().stream()
.map(FieldError::getDefaultMessage)
.collect(Collectors.joining(", "));
return ServerResponse.badRequest().bodyValue(Map.of(
"code", HttpStatus.BAD_REQUEST.value(),
"message", errorMessage,
"timestamp", LocalDateTime.now()));
})
.onErrorResume(IllegalArgumentException.class, ex -> {
return ServerResponse.badRequest().bodyValue(Map.of(
"code", HttpStatus.BAD_REQUEST.value(),
"message", ex.getMessage(),
"timestamp", LocalDateTime.now()));
});
}
public Mono<ServerResponse> register(ServerRequest request) {
@@ -44,7 +72,7 @@ public class SysAuthHandler {
.flatMap(registerRequest -> {
SysUser user = new SysUser();
user.setUsername(registerRequest.getUsername());
user.setPassword(registerRequest.getPassword());
user.setPassword(passwordEncoder.encode(registerRequest.getPassword()));
user.setEmail(registerRequest.getEmail());
return userService.findByUsername(registerRequest.getUsername())
.flatMap(existing -> Mono.<ServerResponse>error(new RuntimeException("用户名已存在")))
@@ -7,9 +7,7 @@ import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.codec.multipart.FilePart;
import org.springframework.http.codec.multipart.Part;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
@@ -70,7 +68,7 @@ public class SysFileHandler {
if (resource.exists() && resource.isReadable()) {
return ServerResponse.ok()
.header(HttpHeaders.CONTENT_DISPOSITION,
.header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"" + file.getFileName() + "\"")
.bodyValue(resource);
} else {
@@ -93,7 +91,7 @@ public class SysFileHandler {
if (resource.exists() && resource.isReadable()) {
return ServerResponse.ok()
.header(HttpHeaders.CONTENT_DISPOSITION,
.header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"" + file.getFileName() + "\"")
.bodyValue(resource);
} else {
@@ -128,7 +126,7 @@ public class SysFileHandler {
response.setPreviewData(Base64.getEncoder().encodeToString(fileBytes));
} else if (fileType.startsWith("text/")) {
response.setPreviewType("text");
response.setPreviewData(new String(fileBytes));
response.setPreviewData(new String(fileBytes, java.nio.charset.StandardCharsets.UTF_8));
} else {
response.setPreviewType("unsupported");
response.setPreviewData(null);
@@ -164,7 +162,7 @@ public class SysFileHandler {
response.setPreviewData(Base64.getEncoder().encodeToString(fileBytes));
} else if (fileType.startsWith("text/")) {
response.setPreviewType("text");
response.setPreviewData(new String(fileBytes));
response.setPreviewData(new String(fileBytes, java.nio.charset.StandardCharsets.UTF_8));
} else {
response.setPreviewType("unsupported");
response.setPreviewData(null);
@@ -5,7 +5,6 @@ import cn.novalon.manage.sys.core.domain.SysExceptionLog;
import cn.novalon.manage.sys.core.service.ISysLoginLogService;
import cn.novalon.manage.sys.core.service.ISysExceptionLogService;
import cn.novalon.manage.sys.dto.request.PageRequest;
import cn.novalon.manage.sys.dto.response.PageResponse;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
@@ -3,6 +3,8 @@ package cn.novalon.manage.sys.handler.role;
import cn.novalon.manage.sys.core.domain.SysRole;
import cn.novalon.manage.sys.core.service.ISysRoleService;
import cn.novalon.manage.sys.dto.request.PageRequest;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
@@ -10,6 +12,7 @@ import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
@Component
@Tag(name = "角色管理", description = "角色相关操作")
public class SysRoleHandler {
private final ISysRoleService roleService;
@@ -18,11 +21,13 @@ public class SysRoleHandler {
this.roleService = roleService;
}
@Operation(summary = "获取所有角色", description = "获取系统中所有角色列表")
public Mono<ServerResponse> getAllRoles(ServerRequest request) {
return ServerResponse.ok()
.body(roleService.findAll(), SysRole.class);
}
@Operation(summary = "分页获取角色", description = "根据分页参数获取角色列表")
public Mono<ServerResponse> getRolesByPage(ServerRequest request) {
int page = Integer.parseInt(request.queryParam("page").orElse("0"));
int size = Integer.parseInt(request.queryParam("size").orElse("10"));
@@ -41,11 +46,13 @@ public class SysRoleHandler {
.flatMap(response -> ServerResponse.ok().bodyValue(response));
}
@Operation(summary = "获取角色总数", description = "获取系统中角色总数")
public Mono<ServerResponse> getRoleCount(ServerRequest request) {
return roleService.count()
.flatMap(count -> ServerResponse.ok().bodyValue(count));
}
@Operation(summary = "根据角色名获取角色", description = "根据角色名称获取角色详细信息")
public Mono<ServerResponse> getRoleByName(ServerRequest request) {
String roleName = request.pathVariable("roleName");
return roleService.findByRoleName(roleName)
@@ -53,12 +60,14 @@ public class SysRoleHandler {
.switchIfEmpty(ServerResponse.notFound().build());
}
@Operation(summary = "检查角色名是否存在", description = "检查指定角色名是否已存在")
public Mono<ServerResponse> checkNameExists(ServerRequest request) {
String name = request.queryParam("name").orElse(null);
return roleService.existsByRoleName(name)
.flatMap(exists -> ServerResponse.ok().bodyValue(exists));
}
@Operation(summary = "根据ID获取角色", description = "根据角色ID获取角色详细信息")
public Mono<ServerResponse> getRoleById(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return roleService.findById(id)
@@ -66,12 +75,14 @@ public class SysRoleHandler {
.switchIfEmpty(ServerResponse.notFound().build());
}
@Operation(summary = "创建角色", description = "创建新角色")
public Mono<ServerResponse> createRole(ServerRequest request) {
return request.bodyToMono(SysRole.class)
.flatMap(roleService::createRole)
.flatMap(role -> ServerResponse.status(HttpStatus.CREATED).bodyValue(role));
}
@Operation(summary = "更新角色", description = "更新角色信息")
public Mono<ServerResponse> updateRole(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return request.bodyToMono(SysRole.class)
@@ -87,6 +98,7 @@ public class SysRoleHandler {
.switchIfEmpty(ServerResponse.notFound().build());
}
@Operation(summary = "删除角色", description = "逻辑删除角色")
public Mono<ServerResponse> deleteRole(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return roleService.logicalDeleteRole(id)
@@ -94,6 +106,7 @@ public class SysRoleHandler {
.switchIfEmpty(ServerResponse.notFound().build());
}
@Operation(summary = "恢复角色", description = "恢复被逻辑删除的角色")
public Mono<ServerResponse> restoreRole(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return roleService.restoreRole(id)
@@ -5,6 +5,8 @@ import cn.novalon.manage.sys.core.service.ISysUserService;
import cn.novalon.manage.sys.dto.request.PageRequest;
import cn.novalon.manage.sys.dto.request.PasswordChangeRequest;
import cn.novalon.manage.sys.dto.request.UserUpdateRequest;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
@@ -14,6 +16,7 @@ import reactor.core.publisher.Mono;
import java.util.List;
@Component
@Tag(name = "用户管理", description = "用户相关操作")
public class SysUserHandler {
private final ISysUserService userService;
@@ -22,12 +25,14 @@ public class SysUserHandler {
this.userService = userService;
}
@Operation(summary = "获取所有用户", description = "获取系统中所有用户列表")
public Mono<ServerResponse> getAllUsers(ServerRequest request) {
boolean includeDeleted = Boolean.valueOf(request.queryParam("includeDeleted").orElse("false"));
return ServerResponse.ok()
.body(userService.findAll(includeDeleted), SysUser.class);
}
@Operation(summary = "分页获取用户", description = "根据分页参数获取用户列表")
public Mono<ServerResponse> getUsersByPage(ServerRequest request) {
int page = Integer.parseInt(request.queryParam("page").orElse("0"));
int size = Integer.parseInt(request.queryParam("size").orElse("10"));
@@ -46,11 +51,13 @@ public class SysUserHandler {
.flatMap(response -> ServerResponse.ok().bodyValue(response));
}
@Operation(summary = "获取用户总数", description = "获取系统中用户总数")
public Mono<ServerResponse> getUserCount(ServerRequest request) {
return userService.count()
.flatMap(count -> ServerResponse.ok().bodyValue(count));
}
@Operation(summary = "根据ID获取用户", description = "根据用户ID获取用户详细信息")
public Mono<ServerResponse> getUserById(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return userService.findById(id)
@@ -58,6 +65,7 @@ public class SysUserHandler {
.switchIfEmpty(ServerResponse.notFound().build());
}
@Operation(summary = "根据用户名获取用户", description = "根据用户名获取用户详细信息")
public Mono<ServerResponse> getUserByUsername(ServerRequest request) {
String username = request.pathVariable("username");
return userService.findByUsername(username)
@@ -65,12 +73,14 @@ public class SysUserHandler {
.switchIfEmpty(ServerResponse.notFound().build());
}
@Operation(summary = "创建用户", description = "创建新用户")
public Mono<ServerResponse> createUser(ServerRequest request) {
return request.bodyToMono(SysUser.class)
.flatMap(userService::createUser)
.flatMap(user -> ServerResponse.status(HttpStatus.CREATED).bodyValue(user));
}
@Operation(summary = "更新用户", description = "更新用户信息")
public Mono<ServerResponse> updateUser(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return request.bodyToMono(UserUpdateRequest.class)
@@ -88,12 +98,14 @@ public class SysUserHandler {
.switchIfEmpty(ServerResponse.notFound().build());
}
@Operation(summary = "删除用户", description = "物理删除用户")
public Mono<ServerResponse> deleteUser(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return userService.deleteUser(id)
.then(ServerResponse.noContent().build());
}
@Operation(summary = "修改密码", description = "修改用户密码")
public Mono<ServerResponse> changePassword(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return request.bodyToMono(PasswordChangeRequest.class)
@@ -101,12 +113,14 @@ public class SysUserHandler {
.flatMap(user -> ServerResponse.ok().bodyValue(user));
}
@Operation(summary = "逻辑删除用户", description = "逻辑删除单个用户")
public Mono<ServerResponse> logicalDeleteUser(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return userService.logicalDeleteUser(id)
.then(ServerResponse.noContent().build());
}
@Operation(summary = "批量逻辑删除用户", description = "批量逻辑删除多个用户")
public Mono<ServerResponse> logicalDeleteUsers(ServerRequest request) {
return request.bodyToMono(new org.springframework.core.ParameterizedTypeReference<List<Long>>() {
})
@@ -114,12 +128,14 @@ public class SysUserHandler {
.then(ServerResponse.noContent().build());
}
@Operation(summary = "恢复用户", description = "恢复单个被逻辑删除的用户")
public Mono<ServerResponse> restoreUser(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return userService.restoreUser(id)
.then(ServerResponse.noContent().build());
}
@Operation(summary = "批量恢复用户", description = "批量恢复被逻辑删除的用户")
public Mono<ServerResponse> restoreUsers(ServerRequest request) {
return request.bodyToMono(new org.springframework.core.ParameterizedTypeReference<List<Long>>() {
})
@@ -127,12 +143,14 @@ public class SysUserHandler {
.then(ServerResponse.noContent().build());
}
@Operation(summary = "检查用户名是否存在", description = "检查指定用户名是否已存在")
public Mono<ServerResponse> checkUsernameExists(ServerRequest request) {
String username = request.queryParam("username").orElse(null);
return userService.existsByUsername(username)
.flatMap(exists -> ServerResponse.ok().bodyValue(exists));
}
@Operation(summary = "检查邮箱是否存在", description = "检查指定邮箱是否已存在")
public Mono<ServerResponse> checkEmailExists(ServerRequest request) {
String email = request.queryParam("email").orElse(null);
return userService.existsByEmail(email)
@@ -12,6 +12,12 @@ public abstract class BaseEntity {
@Id
private Long id;
@Column("create_by")
private String createBy;
@Column("update_by")
private String updateBy;
@CreatedDate
@Column("created_at")
private LocalDateTime createdAt;
@@ -31,6 +37,22 @@ public abstract class BaseEntity {
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;
}
@@ -1,8 +1,7 @@
package cn.novalon.manage.sys.infrastructure.db.entity;
import cn.novalon.manage.sys.core.domain.Dictionary;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Transient;
import org.springframework.data.relational.core.mapping.Column;
import org.springframework.data.relational.core.mapping.Table;
import java.time.LocalDateTime;
@@ -17,9 +16,15 @@ public class DictionaryEntity {
private String value;
private String remark;
private Integer sort;
@Column("create_by")
private String createBy;
@Column("update_by")
private String updateBy;
@Column("created_at")
private LocalDateTime createdAt;
@Column("updated_at")
private LocalDateTime updatedAt;
@Column("deleted_at")
private LocalDateTime deletedAt;
public DictionaryEntity() {
@@ -89,6 +94,14 @@ public class DictionaryEntity {
this.createBy = createBy;
}
public String getUpdateBy() {
return updateBy;
}
public void setUpdateBy(String updateBy) {
this.updateBy = updateBy;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
@@ -24,6 +24,12 @@ public class SysConfigEntity {
@Column("config_type")
private String configType;
@Column("create_by")
private String createBy;
@Column("update_by")
private String updateBy;
@Column("created_at")
private LocalDateTime createdAt;
@@ -73,6 +79,22 @@ public class SysConfigEntity {
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;
}
@@ -36,6 +36,12 @@ public class SysDictDataEntity {
@Column("status")
private String status;
@Column("create_by")
private String createBy;
@Column("update_by")
private String updateBy;
@Column("created_at")
private LocalDateTime createdAt;
@@ -117,6 +123,22 @@ public class SysDictDataEntity {
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;
}
@@ -24,6 +24,12 @@ public class SysDictTypeEntity {
@Column("remark")
private String remark;
@Column("create_by")
private String createBy;
@Column("update_by")
private String updateBy;
@Column("created_at")
private LocalDateTime createdAt;
@@ -73,6 +79,22 @@ public class SysDictTypeEntity {
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;
}
@@ -30,6 +30,9 @@ public class SysFileEntity {
@Column("create_by")
private String createBy;
@Column("update_by")
private String updateBy;
@Column("created_at")
private LocalDateTime createdAt;
@@ -92,6 +95,14 @@ public class SysFileEntity {
this.createBy = createBy;
}
public String getUpdateBy() {
return updateBy;
}
public void setUpdateBy(String updateBy) {
this.updateBy = updateBy;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
@@ -24,6 +24,12 @@ public class SysNoticeEntity {
@Column("status")
private String status;
@Column("create_by")
private String createBy;
@Column("update_by")
private String updateBy;
@Column("created_at")
private LocalDateTime createdAt;
@@ -73,6 +79,22 @@ public class SysNoticeEntity {
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;
}
@@ -3,16 +3,12 @@ package cn.novalon.manage.sys.infrastructure.db.mapper;
import cn.novalon.manage.sys.core.domain.Dictionary;
import cn.novalon.manage.sys.infrastructure.db.entity.DictionaryEntity;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper(componentModel = "spring")
public interface DictionaryMapper {
DictionaryMapper INSTANCE = Mappers.getMapper(DictionaryMapper.class);
Dictionary toDomain(DictionaryEntity entity);
DictionaryEntity toEntity(Dictionary domain);
@@ -3,15 +3,12 @@ package cn.novalon.manage.sys.infrastructure.db.mapper;
import cn.novalon.manage.sys.core.domain.OperationLog;
import cn.novalon.manage.sys.infrastructure.db.entity.OperationLogEntity;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper(componentModel = "spring")
public interface OperationLogMapper {
OperationLogMapper INSTANCE = Mappers.getMapper(OperationLogMapper.class);
OperationLog toDomain(OperationLogEntity entity);
OperationLogEntity toEntity(OperationLog domain);
@@ -3,15 +3,12 @@ package cn.novalon.manage.sys.infrastructure.db.mapper;
import cn.novalon.manage.sys.core.domain.SysConfig;
import cn.novalon.manage.sys.infrastructure.db.entity.SysConfigEntity;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper(componentModel = "spring")
public interface SysConfigMapper {
SysConfigMapper INSTANCE = Mappers.getMapper(SysConfigMapper.class);
SysConfig toDomain(SysConfigEntity entity);
SysConfigEntity toEntity(SysConfig domain);
@@ -3,15 +3,12 @@ package cn.novalon.manage.sys.infrastructure.db.mapper;
import cn.novalon.manage.sys.core.domain.SysDictData;
import cn.novalon.manage.sys.infrastructure.db.entity.SysDictDataEntity;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper(componentModel = "spring")
public interface SysDictDataMapper {
SysDictDataMapper INSTANCE = Mappers.getMapper(SysDictDataMapper.class);
SysDictData toDomain(SysDictDataEntity entity);
SysDictDataEntity toEntity(SysDictData domain);
@@ -3,15 +3,12 @@ package cn.novalon.manage.sys.infrastructure.db.mapper;
import cn.novalon.manage.sys.core.domain.SysDictType;
import cn.novalon.manage.sys.infrastructure.db.entity.SysDictTypeEntity;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper(componentModel = "spring")
public interface SysDictTypeMapper {
SysDictTypeMapper INSTANCE = Mappers.getMapper(SysDictTypeMapper.class);
SysDictType toDomain(SysDictTypeEntity entity);
SysDictTypeEntity toEntity(SysDictType domain);
@@ -3,15 +3,12 @@ package cn.novalon.manage.sys.infrastructure.db.mapper;
import cn.novalon.manage.sys.core.domain.SysExceptionLog;
import cn.novalon.manage.sys.infrastructure.db.entity.SysExceptionLogEntity;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper(componentModel = "spring")
public interface SysExceptionLogMapper {
SysExceptionLogMapper INSTANCE = Mappers.getMapper(SysExceptionLogMapper.class);
SysExceptionLog toDomain(SysExceptionLogEntity entity);
SysExceptionLogEntity toEntity(SysExceptionLog domain);
@@ -3,15 +3,12 @@ package cn.novalon.manage.sys.infrastructure.db.mapper;
import cn.novalon.manage.sys.core.domain.SysFile;
import cn.novalon.manage.sys.infrastructure.db.entity.SysFileEntity;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper(componentModel = "spring")
public interface SysFileMapper {
SysFileMapper INSTANCE = Mappers.getMapper(SysFileMapper.class);
SysFile toDomain(SysFileEntity entity);
SysFileEntity toEntity(SysFile domain);
@@ -3,15 +3,12 @@ package cn.novalon.manage.sys.infrastructure.db.mapper;
import cn.novalon.manage.sys.core.domain.SysLoginLog;
import cn.novalon.manage.sys.infrastructure.db.entity.SysLoginLogEntity;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper(componentModel = "spring")
public interface SysLoginLogMapper {
SysLoginLogMapper INSTANCE = Mappers.getMapper(SysLoginLogMapper.class);
SysLoginLog toDomain(SysLoginLogEntity entity);
SysLoginLogEntity toEntity(SysLoginLog domain);
@@ -2,21 +2,66 @@ package cn.novalon.manage.sys.infrastructure.db.mapper;
import cn.novalon.manage.sys.core.domain.SysMenu;
import cn.novalon.manage.sys.infrastructure.db.entity.SysMenuEntity;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import org.springframework.stereotype.Component;
import java.util.List;
@Mapper(componentModel = "spring")
public interface SysMenuMapper {
@Component
public class SysMenuMapper {
SysMenuMapper INSTANCE = Mappers.getMapper(SysMenuMapper.class);
private static final SysMenuMapper INSTANCE = new SysMenuMapper();
SysMenu toDomain(SysMenuEntity entity);
public static SysMenuMapper getInstance() {
return INSTANCE;
}
SysMenuEntity toEntity(SysMenu domain);
public SysMenu toDomain(SysMenuEntity entity) {
if (entity == null) {
return null;
}
SysMenu domain = new SysMenu();
domain.setId(entity.getId());
domain.setMenuName(entity.getMenuName());
domain.setParentId(entity.getParentId());
domain.setOrderNum(entity.getOrderNum());
domain.setMenuType(entity.getMenuType());
domain.setPerms(entity.getPerms());
domain.setComponent(entity.getComponent());
domain.setStatus(entity.getStatus());
domain.setCreateBy(entity.getCreateBy());
domain.setUpdateBy(entity.getUpdateBy());
domain.setCreatedAt(entity.getCreatedAt());
domain.setUpdatedAt(entity.getUpdatedAt());
domain.setDeletedAt(entity.getDeletedAt());
return domain;
}
List<SysMenu> toDomainList(List<SysMenuEntity> entities);
public SysMenuEntity toEntity(SysMenu domain) {
if (domain == null) {
return null;
}
SysMenuEntity entity = new SysMenuEntity();
entity.setId(domain.getId());
entity.setMenuName(domain.getMenuName());
entity.setParentId(domain.getParentId());
entity.setOrderNum(domain.getOrderNum());
entity.setMenuType(domain.getMenuType());
entity.setPerms(domain.getPerms());
entity.setComponent(domain.getComponent());
entity.setStatus(domain.getStatus());
entity.setCreateBy(domain.getCreateBy());
entity.setUpdateBy(domain.getUpdateBy());
entity.setCreatedAt(domain.getCreatedAt());
entity.setUpdatedAt(domain.getUpdatedAt());
entity.setDeletedAt(domain.getDeletedAt());
return entity;
}
List<SysMenuEntity> toEntityList(List<SysMenu> domains);
public List<SysMenu> toDomainList(List<SysMenuEntity> entities) {
return entities.stream().map(this::toDomain).toList();
}
public List<SysMenuEntity> toEntityList(List<SysMenu> domains) {
return domains.stream().map(this::toEntity).toList();
}
}
@@ -3,15 +3,12 @@ package cn.novalon.manage.sys.infrastructure.db.mapper;
import cn.novalon.manage.sys.core.domain.SysNotice;
import cn.novalon.manage.sys.infrastructure.db.entity.SysNoticeEntity;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper(componentModel = "spring")
public interface SysNoticeMapper {
SysNoticeMapper INSTANCE = Mappers.getMapper(SysNoticeMapper.class);
SysNotice toDomain(SysNoticeEntity entity);
SysNoticeEntity toEntity(SysNotice domain);
@@ -3,15 +3,12 @@ package cn.novalon.manage.sys.infrastructure.db.mapper;
import cn.novalon.manage.sys.core.domain.SysRole;
import cn.novalon.manage.sys.infrastructure.db.entity.SysRoleEntity;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper(componentModel = "spring")
public interface SysRoleMapper {
SysRoleMapper INSTANCE = Mappers.getMapper(SysRoleMapper.class);
SysRole toDomain(SysRoleEntity entity);
SysRoleEntity toEntity(SysRole domain);
@@ -3,15 +3,12 @@ package cn.novalon.manage.sys.infrastructure.db.mapper;
import cn.novalon.manage.sys.core.domain.SysUser;
import cn.novalon.manage.sys.infrastructure.db.entity.SysUserEntity;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper(componentModel = "spring")
public interface SysUserMapper {
SysUserMapper INSTANCE = Mappers.getMapper(SysUserMapper.class);
SysUser toDomain(SysUserEntity entity);
SysUserEntity toEntity(SysUser domain);
@@ -3,15 +3,12 @@ package cn.novalon.manage.sys.infrastructure.db.mapper;
import cn.novalon.manage.sys.core.domain.SysUserMessage;
import cn.novalon.manage.sys.infrastructure.db.entity.SysUserMessageEntity;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper(componentModel = "spring")
public interface SysUserMessageMapper {
SysUserMessageMapper INSTANCE = Mappers.getMapper(SysUserMessageMapper.class);
SysUserMessage toDomain(SysUserMessageEntity entity);
SysUserMessageEntity toEntity(SysUserMessage domain);
@@ -3,7 +3,6 @@ package cn.novalon.manage.sys.infrastructure.db.repository;
import cn.novalon.manage.sys.core.domain.SysConfig;
import cn.novalon.manage.sys.infrastructure.db.mapper.SysConfigMapper;
import cn.novalon.manage.sys.infrastructure.db.dao.SysConfigDao;
import cn.novalon.manage.sys.infrastructure.db.entity.SysConfigEntity;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Flux;
@@ -3,7 +3,6 @@ package cn.novalon.manage.sys.infrastructure.db.repository;
import cn.novalon.manage.sys.core.domain.SysDictData;
import cn.novalon.manage.sys.infrastructure.db.converter.SysDictDataConverter;
import cn.novalon.manage.sys.infrastructure.db.dao.SysDictDataDao;
import cn.novalon.manage.sys.infrastructure.db.entity.SysDictDataEntity;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Flux;
@@ -3,7 +3,6 @@ package cn.novalon.manage.sys.infrastructure.db.repository;
import cn.novalon.manage.sys.core.domain.SysDictType;
import cn.novalon.manage.sys.infrastructure.db.converter.SysDictTypeConverter;
import cn.novalon.manage.sys.infrastructure.db.dao.SysDictTypeDao;
import cn.novalon.manage.sys.infrastructure.db.entity.SysDictTypeEntity;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Flux;
@@ -3,7 +3,6 @@ package cn.novalon.manage.sys.infrastructure.db.repository;
import cn.novalon.manage.sys.core.domain.SysExceptionLog;
import cn.novalon.manage.sys.infrastructure.db.converter.SysExceptionLogConverter;
import cn.novalon.manage.sys.infrastructure.db.dao.SysExceptionLogDao;
import cn.novalon.manage.sys.infrastructure.db.entity.SysExceptionLogEntity;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@@ -3,7 +3,6 @@ package cn.novalon.manage.sys.infrastructure.db.repository;
import cn.novalon.manage.sys.core.domain.SysFile;
import cn.novalon.manage.sys.infrastructure.db.mapper.SysFileMapper;
import cn.novalon.manage.sys.infrastructure.db.dao.SysFileDao;
import cn.novalon.manage.sys.infrastructure.db.entity.SysFileEntity;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Flux;
@@ -3,7 +3,6 @@ package cn.novalon.manage.sys.infrastructure.db.repository;
import cn.novalon.manage.sys.core.domain.SysLoginLog;
import cn.novalon.manage.sys.infrastructure.db.converter.SysLoginLogConverter;
import cn.novalon.manage.sys.infrastructure.db.dao.SysLoginLogDao;
import cn.novalon.manage.sys.infrastructure.db.entity.SysLoginLogEntity;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@@ -3,7 +3,6 @@ package cn.novalon.manage.sys.infrastructure.db.repository;
import cn.novalon.manage.sys.core.domain.SysNotice;
import cn.novalon.manage.sys.infrastructure.db.mapper.SysNoticeMapper;
import cn.novalon.manage.sys.infrastructure.db.dao.SysNoticeDao;
import cn.novalon.manage.sys.infrastructure.db.entity.SysNoticeEntity;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Flux;
@@ -3,7 +3,6 @@ package cn.novalon.manage.sys.infrastructure.db.repository;
import cn.novalon.manage.sys.core.domain.SysUserMessage;
import cn.novalon.manage.sys.infrastructure.db.converter.SysUserMessageConverter;
import cn.novalon.manage.sys.infrastructure.db.dao.SysUserMessageDao;
import cn.novalon.manage.sys.infrastructure.db.entity.SysUserMessageEntity;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@@ -27,7 +27,6 @@ public class JwtAuthenticationFilter implements WebFilter {
String token = extractToken(exchange.getRequest());
if (token != null && jwtTokenProvider.validateToken(token)) {
String username = jwtTokenProvider.getUsernameFromToken(token);
Long userId = jwtTokenProvider.getUserIdFromToken(token);
UsernamePasswordAuthenticationToken authentication =
@@ -1,9 +1,9 @@
package cn.novalon.manage.sys.security;
import cn.novalon.manage.sys.config.JwtProperties;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.crypto.SecretKey;
@@ -15,14 +15,14 @@ import java.util.Map;
@Component
public class JwtTokenProvider {
@Value("${jwt.secret}")
private String jwtSecret;
private final JwtProperties jwtProperties;
@Value("${jwt.expiration}")
private long jwtExpiration;
public JwtTokenProvider(JwtProperties jwtProperties) {
this.jwtProperties = jwtProperties;
}
private SecretKey getSigningKey() {
return Keys.hmacShaKeyFor(jwtSecret.getBytes(StandardCharsets.UTF_8));
return Keys.hmacShaKeyFor(jwtProperties.getSecret().getBytes(StandardCharsets.UTF_8));
}
public String generateToken(String username, Long userId) {
@@ -34,7 +34,7 @@ public class JwtTokenProvider {
.setClaims(claims)
.setSubject(username)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + jwtExpiration))
.setExpiration(new Date(System.currentTimeMillis() + jwtProperties.getExpiration()))
.signWith(getSigningKey())
.compact();
}
@@ -1,9 +1,9 @@
package cn.novalon.manage.sys.websocket;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.socket.WebSocketHandler;
import org.springframework.web.reactive.socket.WebSocketMessage;
import org.springframework.web.reactive.socket.WebSocketSession;
import reactor.core.publisher.Mono;
@@ -46,7 +46,8 @@ public class SysWebSocketHandler implements WebSocketHandler {
private void handleIncomingMessage(WebSocketSession session, String userId, String payload) {
try {
Map<String, Object> message = objectMapper.readValue(payload, Map.class);
Map<String, Object> message = objectMapper.readValue(payload, new TypeReference<Map<String, Object>>() {
});
String type = (String) message.get("type");
switch (type) {
@@ -4,11 +4,11 @@ server:
spring:
application:
name: novalon-manage-api
servlet:
multipart:
enabled: true
max-file-size: 10MB
max-request-size: 10MB
servlet:
multipart:
enabled: true
max-file-size: 10MB
max-request-size: 10MB
datasource:
url: jdbc:postgresql://localhost:55432/manage_system
username: postgres
@@ -33,3 +33,18 @@ jwt:
logging:
level:
cn.novalon.manage: DEBUG
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
endpoint:
health:
show-details: always
metrics:
access: read-only
prometheus:
metrics:
export:
enabled: true
@@ -0,0 +1,209 @@
-- Novalon管理系统数据库初始化脚本
-- 版本: V1
-- 描述: 创建所有核心表
-- 用户表
CREATE TABLE IF NOT EXISTS users (
id BIGSERIAL PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
email VARCHAR(100),
phone VARCHAR(20),
role_id BIGINT,
status INTEGER DEFAULT 1,
create_by VARCHAR(50),
update_by VARCHAR(50),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP
);
-- 角色表
CREATE TABLE IF NOT EXISTS roles (
id BIGSERIAL PRIMARY KEY,
role_name VARCHAR(100) NOT NULL,
role_key VARCHAR(100) NOT NULL UNIQUE,
role_sort INTEGER DEFAULT 0,
status INTEGER DEFAULT 1,
create_by VARCHAR(50),
update_by VARCHAR(50),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP
);
-- 菜单表
CREATE TABLE IF NOT EXISTS menus (
id BIGSERIAL PRIMARY KEY,
menu_name VARCHAR(50) NOT NULL,
parent_id BIGINT DEFAULT 0,
order_num INTEGER DEFAULT 0,
menu_type VARCHAR(1) DEFAULT 'C',
perms VARCHAR(100),
component VARCHAR(200),
status INTEGER DEFAULT 1,
create_by VARCHAR(50),
update_by VARCHAR(50),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP
);
-- 字典类型表
CREATE TABLE IF NOT EXISTS sys_dict_type (
id BIGSERIAL PRIMARY KEY,
dict_name VARCHAR(100) NOT NULL,
dict_type VARCHAR(100) NOT NULL UNIQUE,
status VARCHAR(1) DEFAULT '0',
remark VARCHAR(500),
create_by VARCHAR(50),
update_by VARCHAR(50),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP
);
-- 字典数据表
CREATE TABLE IF NOT EXISTS sys_dict_data (
id BIGSERIAL PRIMARY KEY,
dict_sort INTEGER DEFAULT 0,
dict_label VARCHAR(100) NOT NULL,
dict_value VARCHAR(100) NOT NULL,
dict_type VARCHAR(100) NOT NULL,
css_class VARCHAR(100),
list_class VARCHAR(100),
is_default VARCHAR(1) DEFAULT 'N',
status VARCHAR(1) DEFAULT '0',
create_by VARCHAR(50),
update_by VARCHAR(50),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP
);
-- 系统配置表
CREATE TABLE IF NOT EXISTS sys_config (
id BIGSERIAL PRIMARY KEY,
config_name VARCHAR(100) NOT NULL,
config_key VARCHAR(100) NOT NULL UNIQUE,
config_value VARCHAR(500) NOT NULL,
config_type VARCHAR(1) DEFAULT 'N',
create_by VARCHAR(50),
update_by VARCHAR(50),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP
);
-- 登录日志表
CREATE TABLE IF NOT EXISTS sys_login_log (
id BIGSERIAL PRIMARY KEY,
username VARCHAR(50),
ip VARCHAR(50),
location VARCHAR(255),
browser VARCHAR(50),
os VARCHAR(50),
status VARCHAR(1),
message VARCHAR(255),
login_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 异常日志表
CREATE TABLE IF NOT EXISTS sys_exception_log (
id BIGSERIAL PRIMARY KEY,
username VARCHAR(50),
ip VARCHAR(50),
location VARCHAR(255),
browser VARCHAR(50),
os VARCHAR(50),
status VARCHAR(1),
message VARCHAR(255),
exception_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 系统公告表
CREATE TABLE IF NOT EXISTS sys_notice (
id BIGSERIAL PRIMARY KEY,
notice_title VARCHAR(50) NOT NULL,
notice_type VARCHAR(1) NOT NULL,
notice_content TEXT,
status VARCHAR(1) DEFAULT '0',
create_by VARCHAR(50),
update_by VARCHAR(50),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP
);
-- 用户消息表
CREATE TABLE IF NOT EXISTS sys_user_message (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL,
notice_id BIGINT,
message_title VARCHAR(255),
message_content TEXT,
is_read VARCHAR(1) DEFAULT '0',
read_time TIMESTAMP,
create_by VARCHAR(50),
update_by VARCHAR(50),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP
);
-- 文件管理表
CREATE TABLE IF NOT EXISTS sys_file (
id BIGSERIAL PRIMARY KEY,
file_name VARCHAR(255) NOT NULL,
file_path VARCHAR(500) NOT NULL,
file_size BIGINT,
file_type VARCHAR(100),
file_extension VARCHAR(10),
create_by VARCHAR(50),
update_by VARCHAR(50),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP
);
-- OAuth2客户端表
CREATE TABLE IF NOT EXISTS oauth2_client (
id BIGSERIAL PRIMARY KEY,
client_id VARCHAR(100) NOT NULL UNIQUE,
client_secret VARCHAR(255) NOT NULL,
client_name VARCHAR(100),
web_server_redirect_uri VARCHAR(500),
scope VARCHAR(500),
authorized_grant_types VARCHAR(500),
access_token_validity_seconds INTEGER,
refresh_token_validity_seconds INTEGER,
auto_approve VARCHAR(1) DEFAULT 'false',
enabled VARCHAR(1) DEFAULT 'true',
create_by VARCHAR(50),
update_by VARCHAR(50),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP
);
-- 插入初始管理员用户
INSERT INTO users (username, password, email, role_id, status, create_by, update_by)
VALUES ('admin', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHsM8lE9lBOsl7iKTVKIUi', 'admin@novalon.com', 1, 1, 'system', 'system')
ON CONFLICT (username) DO NOTHING;
-- 插入初始角色
INSERT INTO roles (role_name, role_key, role_sort, status, create_by, update_by)
VALUES ('超级管理员', 'admin', 1, 1, 'system', 'system')
ON CONFLICT (role_key) DO NOTHING;
-- 插入初始字典类型
INSERT INTO sys_dict_type (dict_name, dict_type, status, remark, create_by, update_by)
VALUES ('用户状态', 'user_status', '0', '用户状态列表', 'system', 'system')
ON CONFLICT (dict_type) DO NOTHING;
-- 插入初始字典数据
INSERT INTO sys_dict_data (dict_sort, dict_label, dict_value, dict_type, status, create_by, update_by)
VALUES
(1, '正常', '1', 'user_status', '0', 'system', 'system'),
(2, '停用', '0', 'user_status', '0', 'system', 'system')
ON CONFLICT DO NOTHING;