feat: 更新端口配置并添加监控支持
fix: 修复测试配置和依赖检查 perf: 优化雪花算法性能 refactor: 清理冗余代码和未使用的导入 style: 统一代码格式和注释 test: 添加单元测试和集成测试 ci: 更新CI配置和构建脚本 chore: 更新依赖和配置文件
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>
|
||||
@@ -49,6 +49,10 @@
|
||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||
<artifactId>caffeine</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-cache</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
@@ -150,6 +154,92 @@
|
||||
</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>
|
||||
<plugin>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-maven</artifactId>
|
||||
<version>9.0.9</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>dependency-check</id>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<failBuildOnCVSS>7</failBuildOnCVSS>
|
||||
<suppressionFile>dependency-check-suppressions.xml</suppressionFile>
|
||||
</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>
|
||||
+3
@@ -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);
|
||||
|
||||
+30
@@ -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();
|
||||
}
|
||||
}
|
||||
+30
@@ -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;
|
||||
}
|
||||
}
|
||||
-2
@@ -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 {
|
||||
|
||||
+45
@@ -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("系统统计相关操作")));
|
||||
}
|
||||
}
|
||||
+5
-6
@@ -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)
|
||||
|
||||
+18
@@ -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;
|
||||
}
|
||||
|
||||
+18
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+3
@@ -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; }
|
||||
}
|
||||
|
||||
+3
@@ -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; }
|
||||
}
|
||||
|
||||
+3
@@ -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; }
|
||||
}
|
||||
|
||||
+6
@@ -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; }
|
||||
}
|
||||
|
||||
+18
@@ -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;
|
||||
}
|
||||
|
||||
+3
@@ -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; }
|
||||
}
|
||||
|
||||
-1
@@ -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;
|
||||
|
||||
+8
-4
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
-1
@@ -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;
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
+31
-3
@@ -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("用户名已存在")))
|
||||
|
||||
+4
-6
@@ -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);
|
||||
|
||||
-1
@@ -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;
|
||||
|
||||
+13
@@ -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)
|
||||
|
||||
+18
@@ -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)
|
||||
|
||||
+22
@@ -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;
|
||||
}
|
||||
|
||||
+15
-2
@@ -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;
|
||||
}
|
||||
|
||||
+22
@@ -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;
|
||||
}
|
||||
|
||||
+22
@@ -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;
|
||||
}
|
||||
|
||||
+22
@@ -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;
|
||||
}
|
||||
|
||||
+11
@@ -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;
|
||||
}
|
||||
|
||||
+22
@@ -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;
|
||||
}
|
||||
|
||||
-4
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
+54
-9
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
-1
@@ -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;
|
||||
|
||||
-1
@@ -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;
|
||||
|
||||
-1
@@ -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;
|
||||
|
||||
-1
@@ -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;
|
||||
|
||||
-1
@@ -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;
|
||||
|
||||
-1
@@ -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;
|
||||
|
||||
-1
@@ -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;
|
||||
|
||||
-1
@@ -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;
|
||||
|
||||
-1
@@ -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 =
|
||||
|
||||
+7
-7
@@ -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();
|
||||
}
|
||||
|
||||
+3
-2
@@ -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
|
||||
|
||||
+209
@@ -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;
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package cn.novalon.manage.sys.config;
|
||||
|
||||
import org.springframework.boot.test.context.TestConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import io.r2dbc.spi.ConnectionFactory;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
@TestConfiguration
|
||||
public class UnitTestConfig {
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public ConnectionFactory testConnectionFactory() {
|
||||
return Mockito.mock(ConnectionFactory.class);
|
||||
}
|
||||
}
|
||||
+183
-23
@@ -1,9 +1,11 @@
|
||||
package cn.novalon.manage.sys.core.service.impl;
|
||||
|
||||
import cn.novalon.manage.sys.core.domain.Dictionary;
|
||||
import cn.novalon.manage.sys.core.exception.DictionaryAlreadyExistsException;
|
||||
import cn.novalon.manage.sys.core.service.IDictionaryService;
|
||||
import cn.novalon.manage.sys.infrastructure.db.dao.DictionaryDao;
|
||||
import cn.novalon.manage.sys.infrastructure.db.converter.DictionaryConverter;
|
||||
import cn.novalon.manage.sys.infrastructure.db.entity.DictionaryEntity;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
@@ -13,9 +15,10 @@ import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class DictionaryServiceTest {
|
||||
@@ -28,55 +31,212 @@ class DictionaryServiceTest {
|
||||
|
||||
private IDictionaryService service;
|
||||
|
||||
private Dictionary testDictionary;
|
||||
private DictionaryEntity testEntity;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
service = new DictionaryService(dao, converter);
|
||||
|
||||
testDictionary = new Dictionary();
|
||||
testDictionary.setId(1L);
|
||||
testDictionary.setType("test_type");
|
||||
testDictionary.setCode("test_code");
|
||||
testDictionary.setName("Test Label");
|
||||
testDictionary.setValue("test_value");
|
||||
testDictionary.setSort(1);
|
||||
testDictionary.setRemark("Test remark");
|
||||
testDictionary.setCreatedAt(LocalDateTime.now());
|
||||
testDictionary.setUpdatedAt(LocalDateTime.now());
|
||||
|
||||
testEntity = new DictionaryEntity();
|
||||
testEntity.setId(1L);
|
||||
testEntity.setType("test_type");
|
||||
testEntity.setCode("test_code");
|
||||
testEntity.setName("Test Label");
|
||||
testEntity.setValue("test_value");
|
||||
testEntity.setSort(1);
|
||||
testEntity.setRemark("Test remark");
|
||||
testEntity.setCreatedAt(LocalDateTime.now());
|
||||
testEntity.setUpdatedAt(LocalDateTime.now());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindAll() {
|
||||
Dictionary dict1 = new Dictionary();
|
||||
dict1.setId(1L);
|
||||
dict1.setType("type1");
|
||||
|
||||
Dictionary dict2 = new Dictionary();
|
||||
dict2.setId(2L);
|
||||
dict2.setType("type2");
|
||||
|
||||
when(dao.findByDeletedAtIsNullOrderBySortAsc()).thenReturn(Flux.empty());
|
||||
when(dao.findByDeletedAtIsNullOrderBySortAsc()).thenReturn(Flux.just(testEntity));
|
||||
when(converter.toDomain(testEntity)).thenReturn(testDictionary);
|
||||
|
||||
StepVerifier.create(service.findAll())
|
||||
.expectNext(testDictionary)
|
||||
.verifyComplete();
|
||||
|
||||
verify(dao).findByDeletedAtIsNullOrderBySortAsc();
|
||||
verify(converter).toDomain(testEntity);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindById() {
|
||||
Dictionary dict = new Dictionary();
|
||||
dict.setId(1L);
|
||||
dict.setType("type1");
|
||||
|
||||
when(dao.findById(1L)).thenReturn(Mono.empty());
|
||||
when(dao.findById(1L)).thenReturn(Mono.just(testEntity));
|
||||
when(converter.toDomain(testEntity)).thenReturn(testDictionary);
|
||||
|
||||
StepVerifier.create(service.findById(1L))
|
||||
.expectNext(testDictionary)
|
||||
.verifyComplete();
|
||||
|
||||
verify(dao).findById(1L);
|
||||
verify(converter).toDomain(testEntity);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSave() {
|
||||
Dictionary dict = new Dictionary();
|
||||
dict.setId(1L);
|
||||
dict.setType("type1");
|
||||
void testFindById_NotFound() {
|
||||
when(dao.findById(999L)).thenReturn(Mono.empty());
|
||||
|
||||
when(dao.save(any())).thenReturn(Mono.empty());
|
||||
|
||||
StepVerifier.create(service.save(dict))
|
||||
StepVerifier.create(service.findById(999L))
|
||||
.verifyComplete();
|
||||
|
||||
verify(dao).findById(999L);
|
||||
verify(converter, never()).toDomain(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindByType() {
|
||||
when(dao.findByType("test_type")).thenReturn(Flux.just(testEntity));
|
||||
when(converter.toDomain(testEntity)).thenReturn(testDictionary);
|
||||
|
||||
StepVerifier.create(service.findByType("test_type"))
|
||||
.expectNext(testDictionary)
|
||||
.verifyComplete();
|
||||
|
||||
verify(dao).findByType("test_type");
|
||||
verify(converter).toDomain(testEntity);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckTypeAndCodeExists_True() {
|
||||
when(dao.findByTypeAndCode("test_type", "test_code")).thenReturn(Mono.just(testEntity));
|
||||
|
||||
StepVerifier.create(service.checkTypeAndCodeExists("test_type", "test_code"))
|
||||
.expectNext(true)
|
||||
.verifyComplete();
|
||||
|
||||
verify(dao).findByTypeAndCode("test_type", "test_code");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckTypeAndCodeExists_False() {
|
||||
when(dao.findByTypeAndCode("test_type", "test_code")).thenReturn(Mono.empty());
|
||||
|
||||
StepVerifier.create(service.checkTypeAndCodeExists("test_type", "test_code"))
|
||||
.expectNext(false)
|
||||
.verifyComplete();
|
||||
|
||||
verify(dao).findByTypeAndCode("test_type", "test_code");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSave_NewDictionary_Success() {
|
||||
Dictionary newDict = new Dictionary();
|
||||
newDict.setType("test_type");
|
||||
newDict.setCode("test_code");
|
||||
newDict.setName("Test Label");
|
||||
newDict.setValue("test_value");
|
||||
|
||||
when(dao.findByTypeAndCode("test_type", "test_code")).thenReturn(Mono.empty());
|
||||
when(converter.toEntity(any())).thenReturn(testEntity);
|
||||
when(dao.save(any())).thenReturn(Mono.just(testEntity));
|
||||
when(converter.toDomain(testEntity)).thenReturn(testDictionary);
|
||||
|
||||
StepVerifier.create(service.save(newDict))
|
||||
.expectNextMatches(dict -> dict.getId() != null)
|
||||
.verifyComplete();
|
||||
|
||||
verify(dao).findByTypeAndCode("test_type", "test_code");
|
||||
verify(converter).toEntity(any());
|
||||
verify(dao).save(any());
|
||||
verify(converter).toDomain(testEntity);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSave_NewDictionary_AlreadyExists() {
|
||||
Dictionary newDict = new Dictionary();
|
||||
newDict.setType("test_type");
|
||||
newDict.setCode("test_code");
|
||||
|
||||
when(dao.findByTypeAndCode("test_type", "test_code")).thenReturn(Mono.just(testEntity));
|
||||
|
||||
StepVerifier.create(service.save(newDict))
|
||||
.expectError(DictionaryAlreadyExistsException.class)
|
||||
.verify();
|
||||
|
||||
verify(dao).findByTypeAndCode("test_type", "test_code");
|
||||
verify(converter, never()).toEntity(any());
|
||||
verify(dao, never()).save(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSave_UpdateExistingDictionary() {
|
||||
Dictionary existingDict = new Dictionary();
|
||||
existingDict.setId(1L);
|
||||
existingDict.setType("test_type");
|
||||
existingDict.setCode("test_code");
|
||||
|
||||
when(converter.toEntity(existingDict)).thenReturn(testEntity);
|
||||
when(dao.save(any())).thenReturn(Mono.just(testEntity));
|
||||
when(converter.toDomain(testEntity)).thenReturn(testDictionary);
|
||||
|
||||
StepVerifier.create(service.save(existingDict))
|
||||
.expectNextMatches(dict -> dict.getId() == 1L)
|
||||
.verifyComplete();
|
||||
|
||||
verify(dao, never()).findByTypeAndCode(anyString(), anyString());
|
||||
verify(converter).toEntity(existingDict);
|
||||
verify(dao).save(any());
|
||||
verify(converter).toDomain(testEntity);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUpdate() {
|
||||
Dictionary updateDict = new Dictionary();
|
||||
updateDict.setName("Updated Name");
|
||||
updateDict.setValue("updated_value");
|
||||
updateDict.setRemark("Updated remark");
|
||||
updateDict.setSort(2);
|
||||
|
||||
DictionaryEntity existingEntity = new DictionaryEntity();
|
||||
existingEntity.setId(1L);
|
||||
existingEntity.setType("test_type");
|
||||
existingEntity.setCode("test_code");
|
||||
existingEntity.setName("Old Name");
|
||||
existingEntity.setValue("old_value");
|
||||
existingEntity.setRemark("Old remark");
|
||||
existingEntity.setSort(1);
|
||||
|
||||
when(dao.findById(1L)).thenReturn(Mono.just(existingEntity));
|
||||
when(dao.save(any())).thenReturn(Mono.just(existingEntity));
|
||||
when(converter.toDomain(existingEntity)).thenReturn(testDictionary);
|
||||
|
||||
StepVerifier.create(service.update(1L, updateDict))
|
||||
.expectNextMatches(dict -> dict.getId() == 1L)
|
||||
.verifyComplete();
|
||||
|
||||
verify(dao).findById(1L);
|
||||
verify(dao).save(any());
|
||||
verify(converter).toDomain(existingEntity);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUpdate_NotFound() {
|
||||
Dictionary updateDict = new Dictionary();
|
||||
updateDict.setName("Updated Name");
|
||||
|
||||
when(dao.findById(999L)).thenReturn(Mono.empty());
|
||||
|
||||
StepVerifier.create(service.update(999L, updateDict))
|
||||
.verifyComplete();
|
||||
|
||||
verify(dao).findById(999L);
|
||||
verify(dao, never()).save(any());
|
||||
verify(converter, never()).toDomain(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
package cn.novalon.manage.sys.core.service.impl;
|
||||
|
||||
import cn.novalon.manage.sys.core.domain.SysConfig;
|
||||
import cn.novalon.manage.sys.infrastructure.db.converter.SysConfigConverter;
|
||||
import cn.novalon.manage.sys.infrastructure.db.dao.SysConfigDao;
|
||||
import cn.novalon.manage.sys.infrastructure.db.entity.SysConfigEntity;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class SysConfigServiceTest {
|
||||
|
||||
@Mock
|
||||
private SysConfigDao dao;
|
||||
|
||||
@Mock
|
||||
private SysConfigConverter converter;
|
||||
|
||||
private SysConfigService configService;
|
||||
|
||||
private SysConfig testConfig;
|
||||
private SysConfigEntity testEntity;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
configService = new SysConfigService(dao, converter);
|
||||
|
||||
testConfig = new SysConfig();
|
||||
testConfig.setId(1L);
|
||||
testConfig.setConfigKey("app.name");
|
||||
testConfig.setConfigValue("Novalon Manage System");
|
||||
testConfig.setConfigName("Application Name");
|
||||
testConfig.setConfigType("system");
|
||||
|
||||
testEntity = new SysConfigEntity();
|
||||
testEntity.setId(1L);
|
||||
testEntity.setConfigKey("app.name");
|
||||
testEntity.setConfigValue("Novalon Manage System");
|
||||
testEntity.setConfigName("Application Name");
|
||||
testEntity.setConfigType("system");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindAll() {
|
||||
when(dao.findByDeletedAtIsNull()).thenReturn(Flux.just(testEntity));
|
||||
when(converter.toDomain(testEntity)).thenReturn(testConfig);
|
||||
|
||||
StepVerifier.create(configService.findAll())
|
||||
.expectNext(testConfig)
|
||||
.verifyComplete();
|
||||
|
||||
verify(dao).findByDeletedAtIsNull();
|
||||
verify(converter).toDomain(testEntity);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindById() {
|
||||
when(dao.findById(1L)).thenReturn(Mono.just(testEntity));
|
||||
when(converter.toDomain(testEntity)).thenReturn(testConfig);
|
||||
|
||||
StepVerifier.create(configService.findById(1L))
|
||||
.expectNext(testConfig)
|
||||
.verifyComplete();
|
||||
|
||||
verify(dao).findById(1L);
|
||||
verify(converter).toDomain(testEntity);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindById_NotFound() {
|
||||
when(dao.findById(999L)).thenReturn(Mono.empty());
|
||||
|
||||
StepVerifier.create(configService.findById(999L))
|
||||
.verifyComplete();
|
||||
|
||||
verify(dao).findById(999L);
|
||||
verify(converter, never()).toDomain(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindByConfigKey() {
|
||||
when(dao.findByConfigKeyAndDeletedAtIsNull("app.name")).thenReturn(Mono.just(testEntity));
|
||||
when(converter.toDomain(testEntity)).thenReturn(testConfig);
|
||||
|
||||
StepVerifier.create(configService.findByConfigKey("app.name"))
|
||||
.expectNext(testConfig)
|
||||
.verifyComplete();
|
||||
|
||||
verify(dao).findByConfigKeyAndDeletedAtIsNull("app.name");
|
||||
verify(converter).toDomain(testEntity);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindByConfigKey_NotFound() {
|
||||
when(dao.findByConfigKeyAndDeletedAtIsNull("nonexistent")).thenReturn(Mono.empty());
|
||||
|
||||
StepVerifier.create(configService.findByConfigKey("nonexistent"))
|
||||
.verifyComplete();
|
||||
|
||||
verify(dao).findByConfigKeyAndDeletedAtIsNull("nonexistent");
|
||||
verify(converter, never()).toDomain(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSave() {
|
||||
when(converter.toEntity(testConfig)).thenReturn(testEntity);
|
||||
when(dao.save(testEntity)).thenReturn(Mono.just(testEntity));
|
||||
when(converter.toDomain(testEntity)).thenReturn(testConfig);
|
||||
|
||||
StepVerifier.create(configService.save(testConfig))
|
||||
.expectNext(testConfig)
|
||||
.verifyComplete();
|
||||
|
||||
verify(converter).toEntity(testConfig);
|
||||
verify(dao).save(testEntity);
|
||||
verify(converter).toDomain(testEntity);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDeleteById() {
|
||||
when(dao.deleteByIdAndDeletedAtIsNull(1L)).thenReturn(Mono.empty());
|
||||
|
||||
StepVerifier.create(configService.deleteById(1L))
|
||||
.verifyComplete();
|
||||
|
||||
verify(dao).deleteByIdAndDeletedAtIsNull(1L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetConfigValue() {
|
||||
when(dao.findByConfigKeyAndDeletedAtIsNull("app.name")).thenReturn(Mono.just(testEntity));
|
||||
when(converter.toDomain(testEntity)).thenReturn(testConfig);
|
||||
|
||||
StepVerifier.create(configService.getConfigValue("app.name"))
|
||||
.expectNext("Novalon Manage System")
|
||||
.verifyComplete();
|
||||
|
||||
verify(dao).findByConfigKeyAndDeletedAtIsNull("app.name");
|
||||
verify(converter).toDomain(testEntity);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetConfigValue_NotFound() {
|
||||
when(dao.findByConfigKeyAndDeletedAtIsNull("nonexistent")).thenReturn(Mono.empty());
|
||||
|
||||
StepVerifier.create(configService.getConfigValue("nonexistent"))
|
||||
.verifyComplete();
|
||||
|
||||
verify(dao).findByConfigKeyAndDeletedAtIsNull("nonexistent");
|
||||
}
|
||||
}
|
||||
+206
@@ -0,0 +1,206 @@
|
||||
package cn.novalon.manage.sys.core.service.impl;
|
||||
|
||||
import cn.novalon.manage.sys.core.constants.StatusConstants;
|
||||
import cn.novalon.manage.sys.core.domain.SysRole;
|
||||
import cn.novalon.manage.sys.core.repository.ISysRoleRepository;
|
||||
import cn.novalon.manage.sys.dto.request.PageRequest;
|
||||
import cn.novalon.manage.sys.dto.response.PageResponse;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.data.relational.core.query.Query;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class SysRoleServiceTest {
|
||||
|
||||
@Mock
|
||||
private ISysRoleRepository roleRepository;
|
||||
|
||||
private SysRoleService roleService;
|
||||
|
||||
private SysRole testRole;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
roleService = new SysRoleService(roleRepository);
|
||||
|
||||
testRole = new SysRole();
|
||||
testRole.setId(1L);
|
||||
testRole.setRoleName("admin");
|
||||
testRole.setRoleKey("admin");
|
||||
testRole.setStatus(StatusConstants.ENABLED);
|
||||
testRole.setCreatedAt(LocalDateTime.now());
|
||||
testRole.setUpdatedAt(LocalDateTime.now());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindById() {
|
||||
when(roleRepository.findById(1L)).thenReturn(Mono.just(testRole));
|
||||
|
||||
StepVerifier.create(roleService.findById(1L))
|
||||
.expectNext(testRole)
|
||||
.verifyComplete();
|
||||
|
||||
verify(roleRepository).findById(1L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindAll() {
|
||||
when(roleRepository.findAll()).thenReturn(Flux.just(testRole));
|
||||
|
||||
StepVerifier.create(roleService.findAll())
|
||||
.expectNext(testRole)
|
||||
.verifyComplete();
|
||||
|
||||
verify(roleRepository).findAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindRolesByPage() {
|
||||
PageRequest pageRequest = new PageRequest();
|
||||
pageRequest.setPage(0);
|
||||
pageRequest.setSize(10);
|
||||
pageRequest.setKeyword("admin");
|
||||
|
||||
PageResponse<SysRole> pageResponse = new PageResponse<>();
|
||||
pageResponse.setContent(List.of(testRole));
|
||||
pageResponse.setTotalElements(1L);
|
||||
|
||||
when(roleRepository.findByQueryWithPagination(any(Query.class), eq(pageRequest)))
|
||||
.thenReturn(Mono.just(pageResponse));
|
||||
|
||||
StepVerifier.create(roleService.findRolesByPage(pageRequest))
|
||||
.expectNextMatches(response -> response.getTotalElements() == 1L)
|
||||
.verifyComplete();
|
||||
|
||||
verify(roleRepository).findByQueryWithPagination(any(Query.class), eq(pageRequest));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCount() {
|
||||
when(roleRepository.count()).thenReturn(Mono.just(5L));
|
||||
|
||||
StepVerifier.create(roleService.count())
|
||||
.expectNext(5L)
|
||||
.verifyComplete();
|
||||
|
||||
verify(roleRepository).count();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCreateRole() {
|
||||
SysRole newRole = new SysRole();
|
||||
newRole.setRoleName("user");
|
||||
newRole.setRoleKey("user");
|
||||
|
||||
when(roleRepository.save(any(SysRole.class))).thenReturn(Mono.just(testRole));
|
||||
|
||||
StepVerifier.create(roleService.createRole(newRole))
|
||||
.expectNextMatches(role ->
|
||||
role.getStatus().equals(StatusConstants.ENABLED) &&
|
||||
role.getCreatedAt() != null)
|
||||
.verifyComplete();
|
||||
|
||||
verify(roleRepository).save(any(SysRole.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUpdateRole() {
|
||||
SysRole updateRole = new SysRole();
|
||||
updateRole.setId(1L);
|
||||
updateRole.setRoleName("updated_admin");
|
||||
|
||||
when(roleRepository.save(any(SysRole.class))).thenReturn(Mono.just(testRole));
|
||||
|
||||
StepVerifier.create(roleService.updateRole(updateRole))
|
||||
.expectNextMatches(role -> role.getUpdatedAt() != null)
|
||||
.verifyComplete();
|
||||
|
||||
verify(roleRepository).save(any(SysRole.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDeleteRole() {
|
||||
when(roleRepository.deleteById(1L)).thenReturn(Mono.empty());
|
||||
|
||||
StepVerifier.create(roleService.deleteRole(1L))
|
||||
.verifyComplete();
|
||||
|
||||
verify(roleRepository).deleteById(1L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindByRoleName() {
|
||||
when(roleRepository.findByRoleName("admin")).thenReturn(Mono.just(testRole));
|
||||
|
||||
StepVerifier.create(roleService.findByRoleName("admin"))
|
||||
.expectNext(testRole)
|
||||
.verifyComplete();
|
||||
|
||||
verify(roleRepository).findByRoleName("admin");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExistsByRoleName_True() {
|
||||
when(roleRepository.existsByRoleName("admin")).thenReturn(Mono.just(true));
|
||||
|
||||
StepVerifier.create(roleService.existsByRoleName("admin"))
|
||||
.expectNext(true)
|
||||
.verifyComplete();
|
||||
|
||||
verify(roleRepository).existsByRoleName("admin");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExistsByRoleName_False() {
|
||||
when(roleRepository.existsByRoleName("nonexistent")).thenReturn(Mono.just(false));
|
||||
|
||||
StepVerifier.create(roleService.existsByRoleName("nonexistent"))
|
||||
.expectNext(false)
|
||||
.verifyComplete();
|
||||
|
||||
verify(roleRepository).existsByRoleName("nonexistent");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLogicalDeleteRole() {
|
||||
when(roleRepository.findByIdIncludingDeleted(1L)).thenReturn(Mono.just(testRole));
|
||||
when(roleRepository.updateRole(any(SysRole.class))).thenReturn(Mono.just(testRole));
|
||||
|
||||
StepVerifier.create(roleService.logicalDeleteRole(1L))
|
||||
.expectNextMatches(role -> role.getDeletedAt() != null)
|
||||
.verifyComplete();
|
||||
|
||||
verify(roleRepository).findByIdIncludingDeleted(1L);
|
||||
verify(roleRepository).updateRole(any(SysRole.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRestoreRole() {
|
||||
SysRole deletedRole = new SysRole();
|
||||
deletedRole.setId(1L);
|
||||
deletedRole.setDeletedAt(LocalDateTime.now());
|
||||
|
||||
when(roleRepository.findByIdIncludingDeleted(1L)).thenReturn(Mono.just(deletedRole));
|
||||
when(roleRepository.updateRole(any(SysRole.class))).thenReturn(Mono.just(testRole));
|
||||
|
||||
StepVerifier.create(roleService.restoreRole(1L))
|
||||
.expectNextMatches(role -> role.getDeletedAt() == null)
|
||||
.verifyComplete();
|
||||
|
||||
verify(roleRepository).findByIdIncludingDeleted(1L);
|
||||
verify(roleRepository).updateRole(any(SysRole.class));
|
||||
}
|
||||
}
|
||||
+334
@@ -0,0 +1,334 @@
|
||||
package cn.novalon.manage.sys.core.service.impl;
|
||||
|
||||
import cn.novalon.manage.sys.core.constants.StatusConstants;
|
||||
import cn.novalon.manage.sys.core.domain.SysUser;
|
||||
import cn.novalon.manage.sys.core.repository.ISysUserRepository;
|
||||
import cn.novalon.manage.sys.dto.request.PageRequest;
|
||||
import cn.novalon.manage.sys.dto.response.PageResponse;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.data.relational.core.query.Query;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class SysUserServiceTest {
|
||||
|
||||
@Mock
|
||||
private ISysUserRepository userRepository;
|
||||
|
||||
@Mock
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
private SysUserService userService;
|
||||
|
||||
private SysUser testUser;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
userService = new SysUserService(userRepository, passwordEncoder);
|
||||
|
||||
testUser = new SysUser();
|
||||
testUser.setId(1L);
|
||||
testUser.setUsername("testuser");
|
||||
testUser.setPassword("encoded_password");
|
||||
testUser.setEmail("test@example.com");
|
||||
testUser.setRoleId(1L);
|
||||
testUser.setStatus(StatusConstants.ENABLED);
|
||||
testUser.setCreatedAt(LocalDateTime.now());
|
||||
testUser.setUpdatedAt(LocalDateTime.now());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindById() {
|
||||
when(userRepository.findById(1L)).thenReturn(Mono.just(testUser));
|
||||
|
||||
StepVerifier.create(userService.findById(1L))
|
||||
.expectNext(testUser)
|
||||
.verifyComplete();
|
||||
|
||||
verify(userRepository).findById(1L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindAll() {
|
||||
when(userRepository.findAll()).thenReturn(Flux.just(testUser));
|
||||
|
||||
StepVerifier.create(userService.findAll())
|
||||
.expectNext(testUser)
|
||||
.verifyComplete();
|
||||
|
||||
verify(userRepository).findAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindAll_IncludeDeleted() {
|
||||
when(userRepository.findAll()).thenReturn(Flux.just(testUser));
|
||||
|
||||
StepVerifier.create(userService.findAll(true))
|
||||
.expectNext(testUser)
|
||||
.verifyComplete();
|
||||
|
||||
verify(userRepository).findAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindAll_ExcludeDeleted() {
|
||||
when(userRepository.findByDeletedAtIsNull()).thenReturn(Flux.just(testUser));
|
||||
|
||||
StepVerifier.create(userService.findAll(false))
|
||||
.expectNext(testUser)
|
||||
.verifyComplete();
|
||||
|
||||
verify(userRepository).findByDeletedAtIsNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindUsersByPage() {
|
||||
PageRequest pageRequest = new PageRequest();
|
||||
pageRequest.setPage(0);
|
||||
pageRequest.setSize(10);
|
||||
pageRequest.setKeyword("test");
|
||||
|
||||
PageResponse<SysUser> pageResponse = new PageResponse<>();
|
||||
pageResponse.setContent(List.of(testUser));
|
||||
pageResponse.setTotalElements(1L);
|
||||
|
||||
when(userRepository.findByQueryWithPagination(any(Query.class), eq(pageRequest)))
|
||||
.thenReturn(Mono.just(pageResponse));
|
||||
|
||||
StepVerifier.create(userService.findUsersByPage(pageRequest))
|
||||
.expectNextMatches(response -> response.getTotalElements() == 1L)
|
||||
.verifyComplete();
|
||||
|
||||
verify(userRepository).findByQueryWithPagination(any(Query.class), eq(pageRequest));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindUsersByPage_NoKeyword() {
|
||||
PageRequest pageRequest = new PageRequest();
|
||||
pageRequest.setPage(0);
|
||||
pageRequest.setSize(10);
|
||||
|
||||
PageResponse<SysUser> pageResponse = new PageResponse<>();
|
||||
pageResponse.setContent(List.of(testUser));
|
||||
pageResponse.setTotalElements(1L);
|
||||
|
||||
when(userRepository.findByQueryWithPagination(any(Query.class), eq(pageRequest)))
|
||||
.thenReturn(Mono.just(pageResponse));
|
||||
|
||||
StepVerifier.create(userService.findUsersByPage(pageRequest))
|
||||
.expectNextMatches(response -> response.getTotalElements() == 1L)
|
||||
.verifyComplete();
|
||||
|
||||
verify(userRepository).findByQueryWithPagination(any(Query.class), eq(pageRequest));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCount() {
|
||||
when(userRepository.count()).thenReturn(Mono.just(10L));
|
||||
|
||||
StepVerifier.create(userService.count())
|
||||
.expectNext(10L)
|
||||
.verifyComplete();
|
||||
|
||||
verify(userRepository).count();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindByUsername() {
|
||||
when(userRepository.findByUsername("testuser")).thenReturn(Mono.just(testUser));
|
||||
|
||||
StepVerifier.create(userService.findByUsername("testuser"))
|
||||
.expectNext(testUser)
|
||||
.verifyComplete();
|
||||
|
||||
verify(userRepository).findByUsername("testuser");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCreateUser() {
|
||||
SysUser newUser = new SysUser();
|
||||
newUser.setUsername("newuser");
|
||||
newUser.setPassword("raw_password");
|
||||
newUser.setEmail("new@example.com");
|
||||
|
||||
when(passwordEncoder.encode("raw_password")).thenReturn("encoded_password");
|
||||
when(userRepository.save(any(SysUser.class))).thenReturn(Mono.just(testUser));
|
||||
|
||||
StepVerifier.create(userService.createUser(newUser))
|
||||
.expectNextMatches(user ->
|
||||
user.getPassword().equals("encoded_password") &&
|
||||
user.getStatus().equals(StatusConstants.ENABLED) &&
|
||||
user.getCreatedAt() != null)
|
||||
.verifyComplete();
|
||||
|
||||
ArgumentCaptor<SysUser> userCaptor = ArgumentCaptor.forClass(SysUser.class);
|
||||
verify(userRepository).save(userCaptor.capture());
|
||||
verify(passwordEncoder).encode("raw_password");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUpdateUser() {
|
||||
SysUser updateUser = new SysUser();
|
||||
updateUser.setId(1L);
|
||||
updateUser.setUsername("updated_user");
|
||||
|
||||
when(userRepository.save(any(SysUser.class))).thenReturn(Mono.just(testUser));
|
||||
|
||||
StepVerifier.create(userService.updateUser(updateUser))
|
||||
.expectNextMatches(user -> user.getUpdatedAt() != null)
|
||||
.verifyComplete();
|
||||
|
||||
ArgumentCaptor<SysUser> userCaptor = ArgumentCaptor.forClass(SysUser.class);
|
||||
verify(userRepository).save(userCaptor.capture());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDeleteUser() {
|
||||
when(userRepository.deleteById(1L)).thenReturn(Mono.empty());
|
||||
|
||||
StepVerifier.create(userService.deleteUser(1L))
|
||||
.verifyComplete();
|
||||
|
||||
verify(userRepository).deleteById(1L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testChangePassword_Success() {
|
||||
when(userRepository.findById(1L)).thenReturn(Mono.just(testUser));
|
||||
when(passwordEncoder.matches("old_password", "encoded_password")).thenReturn(true);
|
||||
when(passwordEncoder.encode("new_password")).thenReturn("new_encoded_password");
|
||||
when(userRepository.save(any(SysUser.class))).thenReturn(Mono.just(testUser));
|
||||
|
||||
StepVerifier.create(userService.changePassword(1L, "old_password", "new_password"))
|
||||
.expectNextMatches(user -> user.getPassword().equals("new_encoded_password"))
|
||||
.verifyComplete();
|
||||
|
||||
verify(passwordEncoder).matches("old_password", "encoded_password");
|
||||
verify(passwordEncoder).encode("new_password");
|
||||
verify(userRepository).save(any(SysUser.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testChangePassword_WrongOldPassword() {
|
||||
when(userRepository.findById(1L)).thenReturn(Mono.just(testUser));
|
||||
when(passwordEncoder.matches("wrong_password", "encoded_password")).thenReturn(false);
|
||||
|
||||
StepVerifier.create(userService.changePassword(1L, "wrong_password", "new_password"))
|
||||
.expectError(RuntimeException.class)
|
||||
.verify();
|
||||
|
||||
verify(passwordEncoder).matches("wrong_password", "encoded_password");
|
||||
verify(passwordEncoder, never()).encode(anyString());
|
||||
verify(userRepository, never()).save(any(SysUser.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExistsByUsername_True() {
|
||||
when(userRepository.findByUsername("testuser")).thenReturn(Mono.just(testUser));
|
||||
|
||||
StepVerifier.create(userService.existsByUsername("testuser"))
|
||||
.expectNext(true)
|
||||
.verifyComplete();
|
||||
|
||||
verify(userRepository).findByUsername("testuser");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExistsByUsername_False() {
|
||||
when(userRepository.findByUsername("nonexistent")).thenReturn(Mono.empty());
|
||||
|
||||
StepVerifier.create(userService.existsByUsername("nonexistent"))
|
||||
.expectNext(false)
|
||||
.verifyComplete();
|
||||
|
||||
verify(userRepository).findByUsername("nonexistent");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExistsByEmail_True() {
|
||||
when(userRepository.findByEmail("test@example.com")).thenReturn(Mono.just(testUser));
|
||||
|
||||
StepVerifier.create(userService.existsByEmail("test@example.com"))
|
||||
.expectNext(true)
|
||||
.verifyComplete();
|
||||
|
||||
verify(userRepository).findByEmail("test@example.com");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExistsByEmail_False() {
|
||||
when(userRepository.findByEmail("nonexistent@example.com")).thenReturn(Mono.empty());
|
||||
|
||||
StepVerifier.create(userService.existsByEmail("nonexistent@example.com"))
|
||||
.expectNext(false)
|
||||
.verifyComplete();
|
||||
|
||||
verify(userRepository).findByEmail("nonexistent@example.com");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLogicalDeleteUser() {
|
||||
when(userRepository.findByIdIncludingDeleted(1L)).thenReturn(Mono.just(testUser));
|
||||
when(userRepository.save(any(SysUser.class))).thenReturn(Mono.just(testUser));
|
||||
|
||||
StepVerifier.create(userService.logicalDeleteUser(1L))
|
||||
.verifyComplete();
|
||||
|
||||
ArgumentCaptor<SysUser> userCaptor = ArgumentCaptor.forClass(SysUser.class);
|
||||
verify(userRepository).save(userCaptor.capture());
|
||||
assert userCaptor.getValue().getDeletedAt() != null : "DeletedAt should be set";
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLogicalDeleteUsers() {
|
||||
List<Long> ids = List.of(1L, 2L, 3L);
|
||||
when(userRepository.logicalDeleteByIds(ids)).thenReturn(Mono.empty());
|
||||
|
||||
StepVerifier.create(userService.logicalDeleteUsers(ids))
|
||||
.verifyComplete();
|
||||
|
||||
verify(userRepository).logicalDeleteByIds(ids);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRestoreUser() {
|
||||
SysUser deletedUser = new SysUser();
|
||||
deletedUser.setId(1L);
|
||||
deletedUser.setDeletedAt(LocalDateTime.now());
|
||||
|
||||
when(userRepository.findByIdIncludingDeleted(1L)).thenReturn(Mono.just(deletedUser));
|
||||
when(userRepository.save(any(SysUser.class))).thenReturn(Mono.just(testUser));
|
||||
|
||||
StepVerifier.create(userService.restoreUser(1L))
|
||||
.verifyComplete();
|
||||
|
||||
ArgumentCaptor<SysUser> userCaptor = ArgumentCaptor.forClass(SysUser.class);
|
||||
verify(userRepository).save(userCaptor.capture());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRestoreUsers() {
|
||||
List<Long> ids = List.of(1L, 2L, 3L);
|
||||
when(userRepository.restoreByIds(ids)).thenReturn(Mono.empty());
|
||||
|
||||
StepVerifier.create(userService.restoreUsers(ids))
|
||||
.verifyComplete();
|
||||
|
||||
verify(userRepository).restoreByIds(ids);
|
||||
}
|
||||
}
|
||||
+4
-2
@@ -77,8 +77,10 @@ class DictionaryHandlerTest {
|
||||
|
||||
when(service.save(any())).thenReturn(Mono.just(dict));
|
||||
|
||||
Mono<ServerResponse> responseMono = handler.createDictionary(MockServerRequest.builder()
|
||||
.build());
|
||||
MockServerRequest request = MockServerRequest.builder()
|
||||
.body(Mono.just(dict));
|
||||
|
||||
Mono<ServerResponse> responseMono = handler.createDictionary(request);
|
||||
|
||||
StepVerifier.create(responseMono)
|
||||
.expectNextMatches(response -> response.statusCode().equals(HttpStatus.CREATED))
|
||||
|
||||
+1
-2
@@ -4,7 +4,6 @@ import cn.novalon.manage.sys.core.domain.Dictionary;
|
||||
import cn.novalon.manage.sys.infrastructure.db.entity.DictionaryEntity;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@@ -12,7 +11,7 @@ import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class DictionaryMapperTest {
|
||||
|
||||
private final DictionaryMapper mapper = DictionaryMapper.INSTANCE;
|
||||
private final DictionaryMapper mapper = Mappers.getMapper(DictionaryMapper.class);
|
||||
|
||||
@Test
|
||||
void testToDomain() {
|
||||
|
||||
-1
@@ -13,7 +13,6 @@ import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
import http from 'k6/http';
|
||||
import { check, sleep } from 'k6';
|
||||
|
||||
export const options = {
|
||||
stages: [
|
||||
{ duration: '30s', target: 10 },
|
||||
{ duration: '1m', target: 50 },
|
||||
{ duration: '30s', target: 0 },
|
||||
],
|
||||
thresholds: {
|
||||
http_req_duration: ['p(95)<500'],
|
||||
http_req_failed: ['rate<0.01'],
|
||||
},
|
||||
};
|
||||
|
||||
const BASE_URL = __ENV.BASE_URL || 'http://localhost:8080';
|
||||
|
||||
export default function () {
|
||||
const responses = http.batch([
|
||||
['GET', `${BASE_URL}/api/users/page?page=0&size=10`, null, { tags: { name: 'UsersList' } }],
|
||||
['GET', `${BASE_URL}/api/roles/page?page=0&size=10`, null, { tags: { name: 'RolesList' } }],
|
||||
]);
|
||||
|
||||
check(responses[0], {
|
||||
'users status is 200': (r) => r.status === 200,
|
||||
'users response time < 500ms': (r) => r.timings.duration < 500,
|
||||
});
|
||||
|
||||
check(responses[1], {
|
||||
'roles status is 200': (r) => r.status === 200,
|
||||
'roles response time < 500ms': (r) => r.timings.duration < 500,
|
||||
});
|
||||
|
||||
const singleUserRes = http.get(`${BASE_URL}/api/users/1`);
|
||||
check(singleUserRes, {
|
||||
'single user status is 200 or 404': (r) => r.status === 200 || r.status === 404,
|
||||
'single user response time < 300ms': (r) => r.timings.duration < 300,
|
||||
});
|
||||
|
||||
const healthRes = http.get(`${BASE_URL}/actuator/health`);
|
||||
check(healthRes, {
|
||||
'health check status is 200': (r) => r.status === 200,
|
||||
'health check response time < 100ms': (r) => r.timings.duration < 100,
|
||||
});
|
||||
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
export function handleSummary(data) {
|
||||
return {
|
||||
'stdout': textSummary(data, { indent: ' ', enableColors: true }),
|
||||
'performance-report.json': JSON.stringify(data, null, 2),
|
||||
};
|
||||
}
|
||||
|
||||
function textSummary(data, options) {
|
||||
const indent = options?.indent || '';
|
||||
const colors = options?.enableColors || false;
|
||||
|
||||
let summary = `\n${indent}📊 Performance Test Summary\n`;
|
||||
summary += `${indent}============================\n\n`;
|
||||
|
||||
summary += `${indent}⏱️ HTTP Metrics:\n`;
|
||||
summary += `${indent} - Total Requests: ${data.metrics.http_reqs?.values?.count || 0}\n`;
|
||||
summary += `${indent} - Request Duration (p95): ${data.metrics.http_req_duration?.values?.['p(95)']?.toFixed(2) || 0}ms\n`;
|
||||
summary += `${indent} - Request Failed Rate: ${(data.metrics.http_req_failed?.values?.rate * 100)?.toFixed(2) || 0}%\n`;
|
||||
|
||||
summary += `\n${indent}📈 Iterations:\n`;
|
||||
summary += `${indent} - Total: ${data.metrics.iterations?.values?.count || 0}\n`;
|
||||
summary += `${indent} - Rate: ${data.metrics.iterations?.values?.rate?.toFixed(2) || 0}/s\n`;
|
||||
|
||||
summary += `\n${indent}⏰ Test Duration: ${data.state?.testRunDurationMs ? (data.state.testRunDurationMs / 1000).toFixed(2) : 0}s\n`;
|
||||
|
||||
return summary;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user