feat: 更新端口配置并添加监控支持
fix: 修复测试配置和依赖检查 perf: 优化雪花算法性能 refactor: 清理冗余代码和未使用的导入 style: 统一代码格式和注释 test: 添加单元测试和集成测试 ci: 更新CI配置和构建脚本 chore: 更新依赖和配置文件
This commit is contained in:
+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;
|
||||
}
|
||||
Reference in New Issue
Block a user