feat: add system quality improvement plan and implementation

This commit is contained in:
张翔
2026-03-12 18:20:50 +08:00
parent c8646974d8
commit fe2e4110dd
238 changed files with 21864 additions and 2026 deletions
+19
View File
@@ -0,0 +1,19 @@
FROM maven:3.9-eclipse-temurin-21 AS builder
WORKDIR /app
COPY pom.xml .
COPY manage-sys/pom.xml manage-sys/
COPY manage-sys/src manage-sys/src
RUN mvn clean package -DskipTests
FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
COPY --from=builder /app/manage-sys/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
+42 -4
View File
@@ -37,10 +37,6 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
@@ -96,11 +92,27 @@
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webflux-ui</artifactId>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.5.5.Final</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.5.5.Final</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
@@ -112,6 +124,32 @@
<mainClass>cn.novalon.manage.sys.ManageSysApplication</mainClass>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>21</source>
<target>21</target>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.5.5.Final</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>0.2.0</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,21 @@
package cn.novalon.manage.sys.config;
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 {
@Bean
public MultipartHttpMessageReader multipartHttpMessageReader() {
DefaultPartHttpMessageReader partReader = new DefaultPartHttpMessageReader();
partReader.setMaxHeadersSize(8192);
partReader.setMaxDiskUsagePerPart(10 * 1024 * 1024);
partReader.setEnableLoggingRequestDetails(true);
return new MultipartHttpMessageReader(partReader);
}
}
@@ -1,6 +1,16 @@
package cn.novalon.manage.sys.config;
import cn.novalon.manage.sys.handler.auth.SysAuthHandler;
import cn.novalon.manage.sys.handler.config.SysConfigHandler;
import cn.novalon.manage.sys.handler.dictionary.DictionaryHandler;
import cn.novalon.manage.sys.handler.dict.SysDictHandler;
import cn.novalon.manage.sys.handler.file.SysFileHandler;
import cn.novalon.manage.sys.handler.log.SysLogHandler;
import cn.novalon.manage.sys.handler.message.SysUserMessageHandler;
import cn.novalon.manage.sys.handler.notice.SysNoticeHandler;
import cn.novalon.manage.sys.handler.role.SysRoleHandler;
import cn.novalon.manage.sys.handler.stats.StatsHandler;
import cn.novalon.manage.sys.handler.user.SysUserHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.server.RouterFunction;
@@ -24,4 +34,141 @@ public class SystemRouter {
.DELETE("/api/dictionaries/{id}", dictionaryHandler::deleteDictionary)
.build();
}
@Bean
public RouterFunction<ServerResponse> userRoutes(SysUserHandler userHandler) {
return route()
.GET("/api/users", userHandler::getAllUsers)
.GET("/api/users/page", userHandler::getUsersByPage)
.GET("/api/users/count", userHandler::getUserCount)
.GET("/api/users/{id}", userHandler::getUserById)
.GET("/api/users/username/{username}", userHandler::getUserByUsername)
.POST("/api/users", userHandler::createUser)
.PUT("/api/users/{id}", userHandler::updateUser)
.DELETE("/api/users/{id}", userHandler::deleteUser)
.POST("/api/users/{id}/password", userHandler::changePassword)
.DELETE("/api/users/{id}/logical", userHandler::logicalDeleteUser)
.POST("/api/users/logical-delete", userHandler::logicalDeleteUsers)
.POST("/api/users/{id}/restore", userHandler::restoreUser)
.POST("/api/users/restore", userHandler::restoreUsers)
.GET("/api/users/check/username", userHandler::checkUsernameExists)
.GET("/api/users/check/email", userHandler::checkEmailExists)
.build();
}
@Bean
public RouterFunction<ServerResponse> roleRoutes(SysRoleHandler roleHandler) {
return route()
.GET("/api/roles", roleHandler::getAllRoles)
.GET("/api/roles/page", roleHandler::getRolesByPage)
.GET("/api/roles/count", roleHandler::getRoleCount)
.GET("/api/roles/name/{roleName}", roleHandler::getRoleByName)
.GET("/api/roles/check-name", roleHandler::checkNameExists)
.GET("/api/roles/{id}", roleHandler::getRoleById)
.POST("/api/roles", roleHandler::createRole)
.PUT("/api/roles/{id}", roleHandler::updateRole)
.DELETE("/api/roles/{id}", roleHandler::deleteRole)
.POST("/api/roles/{id}/restore", roleHandler::restoreRole)
.build();
}
@Bean
public RouterFunction<ServerResponse> configRoutes(SysConfigHandler configHandler) {
return route()
.GET("/api/config", configHandler::getAllConfigs)
.GET("/api/config/{id}", configHandler::getConfigById)
.GET("/api/config/key/{configKey}", configHandler::getConfigByKey)
.POST("/api/config", configHandler::createConfig)
.PUT("/api/config/{id}", configHandler::updateConfig)
.DELETE("/api/config/{id}", configHandler::deleteConfig)
.build();
}
@Bean
public RouterFunction<ServerResponse> noticeRoutes(SysNoticeHandler noticeHandler) {
return route()
.GET("/api/notices", noticeHandler::getAllNotices)
.GET("/api/notices/{id}", noticeHandler::getNoticeById)
.GET("/api/notices/status/{status}", noticeHandler::getNoticesByStatus)
.POST("/api/notices", noticeHandler::createNotice)
.PUT("/api/notices/{id}", noticeHandler::updateNotice)
.DELETE("/api/notices/{id}", noticeHandler::deleteNotice)
.build();
}
@Bean
public RouterFunction<ServerResponse> fileRoutes(SysFileHandler fileHandler) {
return route()
.GET("/api/files", fileHandler::getAllFiles)
.GET("/api/files/{id}", fileHandler::getFileById)
.POST("/api/files/upload", fileHandler::uploadFile)
.GET("/api/files/{id}/download", fileHandler::downloadFile)
.GET("/api/files/download/{fileName}", fileHandler::downloadFileByName)
.GET("/api/files/{id}/preview", fileHandler::previewFile)
.GET("/api/files/preview/{fileName}", fileHandler::previewFileByName)
.DELETE("/api/files/{id}", fileHandler::deleteFile)
.build();
}
@Bean
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/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)
.build();
}
@Bean
public RouterFunction<ServerResponse> authRoutes(SysAuthHandler authHandler) {
return route()
.POST("/api/auth/login", authHandler::login)
.POST("/api/auth/register", authHandler::register)
.POST("/api/auth/logout", authHandler::logout)
.build();
}
@Bean
public RouterFunction<ServerResponse> messageRoutes(SysUserMessageHandler messageHandler) {
return route()
.GET("/api/messages/user/{userId}", messageHandler::getMessagesByUser)
.GET("/api/messages/user/{userId}/unread", messageHandler::getUnreadCount)
.GET("/api/messages/user/{userId}/unread/list", messageHandler::getUnreadList)
.POST("/api/messages", messageHandler::createMessage)
.PUT("/api/messages/{id}/read", messageHandler::markAsRead)
.DELETE("/api/messages/{id}", messageHandler::deleteMessage)
.build();
}
@Bean
public RouterFunction<ServerResponse> statsRoutes(StatsHandler statsHandler) {
return route()
.GET("/api/stats/overview", statsHandler::getOverview)
.build();
}
@Bean
public RouterFunction<ServerResponse> dictRoutes(SysDictHandler dictHandler) {
return route()
.GET("/api/dict/types", dictHandler::getAllDictTypes)
.GET("/api/dict/types/{id}", dictHandler::getDictTypeById)
.GET("/api/dict/types/type/{dictType}", dictHandler::getDictTypeByType)
.POST("/api/dict/types", dictHandler::createDictType)
.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)
.POST("/api/dict/data", dictHandler::createDictData)
.PUT("/api/dict/data/{id}", dictHandler::updateDictData)
.DELETE("/api/dict/data/{id}", dictHandler::deleteDictData)
.build();
}
}
@@ -1,54 +0,0 @@
package cn.novalon.manage.sys.config;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Component
public class SystemWebSocketHandler extends TextWebSocketHandler {
private final Map<String, WebSocketSession> sessions = new ConcurrentHashMap<>();
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
sessions.put(session.getId(), session);
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
sessions.remove(session.getId());
}
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
// Handle incoming messages if needed
}
public void sendMessageToUser(String userId, String message) {
sessions.values().forEach(session -> {
try {
if (session.isOpen()) {
session.sendMessage(new TextMessage(message));
}
} catch (IOException e) {
}
});
}
public void broadcast(String message) {
sessions.values().forEach(session -> {
try {
if (session.isOpen()) {
session.sendMessage(new TextMessage(message));
}
} catch (IOException e) {
}
});
}
}
@@ -0,0 +1,14 @@
package cn.novalon.manage.sys.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.config.WebFluxConfigurer;
@Configuration
public class WebFluxConfig implements WebFluxConfigurer {
@Override
public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
configurer.defaultCodecs().maxInMemorySize(16 * 1024 * 1024);
}
}
@@ -0,0 +1,25 @@
package cn.novalon.manage.sys.core.constants;
/**
* @author zhangxiang
* @version 1.0
* @description 数据库字段名常量
* @date 2026/03/11
**/
public class FieldConstants {
public static final String USERNAME = "username";
public static final String PASSWORD = "password";
public static final String EMAIL = "email";
public static final String PHONE = "phone";
public static final String STATUS = "status";
public static final String ROLE_NAME = "roleName";
public static final String ROLE_KEY = "roleKey";
public static final String MENU_NAME = "menuName";
public static final String MENU_TYPE = "menuType";
public static final String ROLE_ID = "roleId";
public static final String PARENT_ID = "parentId";
private FieldConstants() {
}
}
@@ -0,0 +1,17 @@
package cn.novalon.manage.sys.core.constants;
/**
* @author zhangxiang
* @version 1.0
* @description 菜单类型常量
* @date 2026/03/11
**/
public class MenuTypeConstants {
public static final String DIRECTORY = "M";
public static final String MENU = "C";
public static final String BUTTON = "F";
private MenuTypeConstants() {
}
}
@@ -0,0 +1,17 @@
package cn.novalon.manage.sys.core.constants;
/**
* @author zhangxiang
* @version 1.0
* @description 状态常量
* @date 2026/03/11
**/
public class StatusConstants {
public static final Integer DISABLED = 0;
public static final Integer ENABLED = 1;
public static final Integer DELETED = 2;
private StatusConstants() {
}
}
@@ -2,12 +2,18 @@ package cn.novalon.manage.sys.core.domain;
import java.time.LocalDateTime;
/**
* @author zhangxiang
* @version 1.0
* @description 基础领域对象
* @date 2026/03/11
**/
public abstract class BaseDomain {
private Long id;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
private LocalDateTime deletedAt;
protected Long id;
protected LocalDateTime createdAt;
protected LocalDateTime updatedAt;
protected LocalDateTime deletedAt;
public Long getId() {
return id;
@@ -0,0 +1,99 @@
package cn.novalon.manage.sys.core.domain;
import java.time.LocalDateTime;
public class Dictionary {
private Long id;
private String type;
private String code;
private String name;
private String value;
private String remark;
private Integer sort;
private String createBy;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
public Dictionary() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
public Integer getSort() {
return sort;
}
public void setSort(Integer sort) {
this.sort = sort;
}
public String getCreateBy() {
return createBy;
}
public void setCreateBy(String createBy) {
this.createBy = createBy;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
public void setCreatedAt(LocalDateTime createdAt) {
this.createdAt = createdAt;
}
public LocalDateTime getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(LocalDateTime updatedAt) {
this.updatedAt = updatedAt;
}
}
@@ -1,5 +1,15 @@
package cn.novalon.manage.sys.core.domain;
import cn.novalon.manage.sys.core.utils.SnowflakeId;
import java.time.LocalDateTime;
/**
* @author zhangxiang
* @version 1.0
* @description 角色领域对象
* @date 2026/03/11
**/
public class SysRole extends BaseDomain {
private String roleName;
@@ -38,4 +48,28 @@ public class SysRole extends BaseDomain {
public void setStatus(Integer status) {
this.status = status;
}
/**
* 生成主键ID
*
* @return 主键ID
*/
public Long generateId() {
this.id = SnowflakeId.nextId();
return this.id;
}
/**
* 删除角色
*/
public void delete() {
this.deletedAt = LocalDateTime.now();
}
/**
* 恢复角色
*/
public void restore() {
this.deletedAt = null;
}
}
@@ -1,5 +1,15 @@
package cn.novalon.manage.sys.core.domain;
import cn.novalon.manage.sys.core.utils.SnowflakeId;
import java.time.LocalDateTime;
/**
* @author zhangxiang
* @version 1.0
* @description 用户领域对象
* @date 2026/03/11
**/
public class SysUser extends BaseDomain {
private String username;
@@ -47,4 +57,21 @@ public class SysUser extends BaseDomain {
public void setStatus(Integer status) {
this.status = status;
}
/**
* 生成主键ID
*
* @return 主键ID
*/
public Long generateId() {
this.id = SnowflakeId.nextId();
return this.id;
}
/**
* 删除用户
*/
public void delete() {
this.deletedAt = LocalDateTime.now();
}
}
@@ -0,0 +1,38 @@
package cn.novalon.manage.sys.core.domain.query;
/**
* @author zhangxiang
* @version 1.0
* @description 菜单查询对象
* @date 2026/03/11
**/
public class SysMenuQuery {
private String menuName;
private String menuType;
private String status;
public String getMenuName() {
return menuName;
}
public void setMenuName(String menuName) {
this.menuName = menuName;
}
public String getMenuType() {
return menuType;
}
public void setMenuType(String menuType) {
this.menuType = menuType;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}
@@ -0,0 +1,38 @@
package cn.novalon.manage.sys.core.domain.query;
/**
* @author zhangxiang
* @version 1.0
* @description 角色查询对象
* @date 2026/03/11
**/
public class SysRoleQuery {
private String roleName;
private String roleKey;
private Integer status;
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public String getRoleKey() {
return roleKey;
}
public void setRoleKey(String roleKey) {
this.roleKey = roleKey;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
}
@@ -0,0 +1,47 @@
package cn.novalon.manage.sys.core.domain.query;
/**
* @author zhangxiang
* @version 1.0
* @description 用户查询对象
* @date 2026/03/11
**/
public class SysUserQuery {
private String username;
private String email;
private Integer status;
private Long roleId;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public Long getRoleId() {
return roleId;
}
public void setRoleId(Long roleId) {
this.roleId = roleId;
}
}
@@ -0,0 +1,21 @@
package cn.novalon.manage.sys.core.exception;
public class DictionaryAlreadyExistsException extends RuntimeException {
private final String type;
private final String code;
public DictionaryAlreadyExistsException(String type, String code) {
super("Dictionary with type '" + type + "' and code '" + code + "' already exists");
this.type = type;
this.code = code;
}
public String getType() {
return type;
}
public String getCode() {
return code;
}
}
@@ -4,6 +4,8 @@ import cn.novalon.manage.sys.core.domain.OperationLog;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.LocalDateTime;
public interface IOperationLogRepository {
Mono<OperationLog> findById(Long id);
@@ -15,4 +17,8 @@ public interface IOperationLogRepository {
Flux<OperationLog> findAll();
Flux<OperationLog> findByUsername(String username);
Mono<Long> count();
Mono<Long> countByCreatedAtAfter(LocalDateTime dateTime);
}
@@ -1,6 +1,10 @@
package cn.novalon.manage.sys.core.repository;
import cn.novalon.manage.sys.core.domain.SysRole;
import cn.novalon.manage.sys.dto.request.PageRequest;
import cn.novalon.manage.sys.dto.response.PageResponse;
import org.springframework.data.domain.Sort;
import org.springframework.data.relational.core.query.Query;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@@ -8,9 +12,27 @@ public interface ISysRoleRepository {
Mono<SysRole> findById(Long id);
Mono<SysRole> findByIdIncludingDeleted(Long id);
Mono<SysRole> save(SysRole sysRole);
Mono<Void> deleteById(Long id);
Flux<SysRole> findAll();
Flux<SysRole> findAll(Sort sort);
Flux<SysRole> findByRoleNameLikeOrRoleKeyLike(String roleName, String roleKey, Sort sort);
Mono<Long> count();
Mono<Long> countByRoleNameLikeOrRoleKeyLike(String roleName, String roleKey);
Mono<PageResponse<SysRole>> findByQueryWithPagination(Query query, PageRequest pageRequest);
Mono<SysRole> findByRoleName(String roleName);
Mono<Boolean> existsByRoleName(String roleName);
Mono<SysRole> updateRole(SysRole role);
}
@@ -1,18 +1,50 @@
package cn.novalon.manage.sys.core.repository;
import cn.novalon.manage.sys.core.domain.SysUser;
import cn.novalon.manage.sys.dto.request.PageRequest;
import cn.novalon.manage.sys.dto.response.PageResponse;
import org.springframework.data.domain.Sort;
import org.springframework.data.relational.core.query.Query;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.List;
public interface ISysUserRepository {
Mono<SysUser> findByUsername(String username);
Mono<SysUser> findByEmail(String email);
Mono<SysUser> findById(Long id);
Mono<SysUser> findByIdIncludingDeleted(Long id);
Mono<SysUser> save(SysUser sysUser);
Mono<Void> deleteById(Long id);
Flux<SysUser> findAll();
Flux<SysUser> findAll(Sort sort);
Flux<SysUser> findByDeletedAtIsNull();
Flux<SysUser> findByDeletedAtIsNull(Sort sort);
Mono<Long> count();
Mono<PageResponse<SysUser>> findByQueryWithPagination(Query query, PageRequest pageRequest);
Mono<Boolean> existsByUsername(String username);
Mono<Boolean> existsByEmail(String email);
Mono<Void> logicalDeleteById(Long id);
Mono<Void> logicalDeleteByIds(List<Long> ids);
Mono<Void> restoreById(Long id);
Mono<Void> restoreByIds(List<Long> ids);
}
@@ -0,0 +1,15 @@
package cn.novalon.manage.sys.core.service;
import cn.novalon.manage.sys.core.domain.Dictionary;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
public interface IDictionaryService {
Flux<Dictionary> findAll();
Mono<Dictionary> findById(Long id);
Flux<Dictionary> findByType(String type);
Mono<Boolean> checkTypeAndCodeExists(String type, String code);
Mono<Dictionary> save(Dictionary dictionary);
Mono<Dictionary> update(Long id, Dictionary dictionary);
Mono<Void> deleteById(Long id);
}
@@ -8,4 +8,6 @@ public interface IOperationLogService {
Mono<OperationLog> save(OperationLog log);
Flux<OperationLog> findAll();
Flux<OperationLog> findByUsername(String username);
Mono<Long> count();
Mono<Long> countToday();
}
@@ -1,14 +1,19 @@
package cn.novalon.manage.sys.core.service;
import cn.novalon.manage.sys.core.domain.SysExceptionLog;
import cn.novalon.manage.sys.dto.request.PageRequest;
import cn.novalon.manage.sys.dto.response.PageResponse;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.LocalDateTime;
public interface ISysExceptionLogService {
Mono<SysExceptionLog> findById(Long id);
Flux<SysExceptionLog> findAll();
Flux<SysExceptionLog> findByUsername(String username);
Flux<SysExceptionLog> findByCreateTimeBetween(LocalDateTime startTime, LocalDateTime endTime);
Mono<SysExceptionLog> save(SysExceptionLog exceptionLog);
Mono<PageResponse<SysExceptionLog>> findExceptionLogsByPage(PageRequest pageRequest);
Mono<Long> count();
}
@@ -3,12 +3,15 @@ package cn.novalon.manage.sys.core.service;
import cn.novalon.manage.sys.core.domain.SysFile;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.http.codec.multipart.FilePart;
import org.springframework.web.multipart.MultipartFile;
public interface ISysFileService {
Flux<SysFile> findAll();
Flux<SysFile> findByCreateBy(String createBy);
Mono<SysFile> findById(Long id);
Mono<SysFile> findByFileName(String fileName);
Mono<SysFile> upload(MultipartFile file, String createBy);
Mono<SysFile> uploadFilePart(FilePart filePart, String createBy);
Mono<Void> deleteById(Long id);
}
@@ -1,14 +1,19 @@
package cn.novalon.manage.sys.core.service;
import cn.novalon.manage.sys.core.domain.SysLoginLog;
import cn.novalon.manage.sys.dto.request.PageRequest;
import cn.novalon.manage.sys.dto.response.PageResponse;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.LocalDateTime;
public interface ISysLoginLogService {
Mono<SysLoginLog> findById(Long id);
Flux<SysLoginLog> findAll();
Flux<SysLoginLog> findByUsername(String username);
Flux<SysLoginLog> findByLoginTimeBetween(LocalDateTime startTime, LocalDateTime endTime);
Mono<SysLoginLog> save(SysLoginLog loginLog);
Mono<PageResponse<SysLoginLog>> findLoginLogsByPage(PageRequest pageRequest);
Mono<Long> count();
}
@@ -1,13 +1,21 @@
package cn.novalon.manage.sys.core.service;
import cn.novalon.manage.sys.core.domain.SysRole;
import cn.novalon.manage.sys.dto.request.PageRequest;
import cn.novalon.manage.sys.dto.response.PageResponse;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
public interface ISysRoleService {
Mono<SysRole> findById(Long id);
Flux<SysRole> findAll();
Mono<PageResponse<SysRole>> findRolesByPage(PageRequest pageRequest);
Mono<Long> count();
Mono<SysRole> createRole(SysRole role);
Mono<SysRole> updateRole(SysRole role);
Mono<Void> deleteRole(Long id);
Mono<SysRole> findByRoleName(String roleName);
Mono<Boolean> existsByRoleName(String roleName);
Mono<SysRole> logicalDeleteRole(Long id);
Mono<SysRole> restoreRole(Long id);
}
@@ -10,4 +10,5 @@ public interface ISysUserMessageService {
Mono<Long> countUnread(Long userId);
Mono<SysUserMessage> save(SysUserMessage message);
Mono<Void> markAsRead(Long id);
Mono<Void> deleteById(Long id);
}
@@ -1,13 +1,28 @@
package cn.novalon.manage.sys.core.service;
import cn.novalon.manage.sys.core.domain.SysUser;
import cn.novalon.manage.sys.dto.request.PageRequest;
import cn.novalon.manage.sys.dto.response.PageResponse;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.List;
public interface ISysUserService {
Mono<SysUser> findById(Long id);
Flux<SysUser> findAll();
Flux<SysUser> findAll(boolean includeDeleted);
Mono<PageResponse<SysUser>> findUsersByPage(PageRequest pageRequest);
Mono<Long> count();
Mono<SysUser> findByUsername(String username);
Mono<Boolean> existsByUsername(String username);
Mono<Boolean> existsByEmail(String email);
Mono<SysUser> createUser(SysUser user);
Mono<SysUser> updateUser(SysUser user);
Mono<Void> deleteUser(Long id);
Mono<Void> logicalDeleteUser(Long id);
Mono<Void> logicalDeleteUsers(List<Long> ids);
Mono<Void> restoreUser(Long id);
Mono<Void> restoreUsers(List<Long> ids);
Mono<SysUser> changePassword(Long userId, String oldPassword, String newPassword);
}
@@ -0,0 +1,96 @@
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.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;
import java.time.LocalDateTime;
@Service
public class DictionaryService implements IDictionaryService {
private final DictionaryDao dao;
private final DictionaryConverter converter;
public DictionaryService(DictionaryDao dao, DictionaryConverter converter) {
this.dao = dao;
this.converter = converter;
}
@Override
public Flux<Dictionary> findAll() {
return dao.findByDeletedAtIsNullOrderBySortAsc()
.map(converter::toDomain);
}
@Override
public Mono<Dictionary> findById(Long id) {
return dao.findById(id)
.map(converter::toDomain);
}
@Override
public Flux<Dictionary> findByType(String type) {
return dao.findByType(type)
.map(converter::toDomain);
}
@Override
public Mono<Boolean> checkTypeAndCodeExists(String type, String code) {
return dao.findByTypeAndCode(type, code)
.map(entity -> true)
.defaultIfEmpty(false);
}
@Override
public Mono<Dictionary> save(Dictionary dictionary) {
if (dictionary.getId() == null) {
dictionary.setCreatedAt(LocalDateTime.now());
return checkTypeAndCodeExists(dictionary.getType(), dictionary.getCode())
.flatMap(exists -> {
if (exists) {
return Mono.error(new DictionaryAlreadyExistsException(dictionary.getType(), dictionary.getCode()));
}
dictionary.setUpdatedAt(LocalDateTime.now());
return dao.save(converter.toEntity(dictionary))
.map(converter::toDomain);
});
}
dictionary.setUpdatedAt(LocalDateTime.now());
return dao.save(converter.toEntity(dictionary))
.map(converter::toDomain);
}
@Override
public Mono<Dictionary> update(Long id, Dictionary dictionary) {
return dao.findById(id)
.flatMap(existing -> {
if (dictionary.getName() != null) {
existing.setName(dictionary.getName());
}
if (dictionary.getValue() != null) {
existing.setValue(dictionary.getValue());
}
if (dictionary.getRemark() != null) {
existing.setRemark(dictionary.getRemark());
}
if (dictionary.getSort() != null) {
existing.setSort(dictionary.getSort());
}
existing.setUpdatedAt(LocalDateTime.now());
return dao.save(existing);
})
.map(converter::toDomain);
}
@Override
public Mono<Void> deleteById(Long id) {
return dao.deleteByIdAndDeletedAtIsNull(id);
}
}
@@ -33,4 +33,15 @@ public class OperationLogService implements IOperationLogService {
public Flux<OperationLog> findByUsername(String username) {
return logRepository.findByUsername(username);
}
@Override
public Mono<Long> count() {
return logRepository.count();
}
@Override
public Mono<Long> countToday() {
LocalDateTime startOfDay = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0);
return logRepository.countByCreatedAtAfter(startOfDay);
}
}
@@ -9,12 +9,12 @@ import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@Service
public class SysConfigServiceImpl implements ISysConfigService {
public class SysConfigService implements ISysConfigService {
private final SysConfigDao dao;
private final SysConfigConverter converter;
public SysConfigServiceImpl(SysConfigDao dao, SysConfigConverter converter) {
public SysConfigService(SysConfigDao dao, SysConfigConverter converter) {
this.dao = dao;
this.converter = converter;
}
@@ -9,12 +9,12 @@ import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@Service
public class SysDictDataServiceImpl implements ISysDictDataService {
public class SysDictDataService implements ISysDictDataService {
private final SysDictDataDao dao;
private final SysDictDataConverter converter;
public SysDictDataServiceImpl(SysDictDataDao dao, SysDictDataConverter converter) {
public SysDictDataService(SysDictDataDao dao, SysDictDataConverter converter) {
this.dao = dao;
this.converter = converter;
}
@@ -9,12 +9,12 @@ import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@Service
public class SysDictTypeServiceImpl implements ISysDictTypeService {
public class SysDictTypeService implements ISysDictTypeService {
private final SysDictTypeDao dao;
private final SysDictTypeConverter converter;
public SysDictTypeServiceImpl(SysDictTypeDao dao, SysDictTypeConverter converter) {
public SysDictTypeService(SysDictTypeDao dao, SysDictTypeConverter converter) {
this.dao = dao;
this.converter = converter;
}
@@ -0,0 +1,134 @@
package cn.novalon.manage.sys.core.service.impl;
import cn.novalon.manage.sys.core.domain.SysExceptionLog;
import cn.novalon.manage.sys.core.service.ISysExceptionLogService;
import cn.novalon.manage.sys.infrastructure.db.converter.SysExceptionLogConverter;
import cn.novalon.manage.sys.infrastructure.db.dao.SysExceptionLogDao;
import cn.novalon.manage.sys.dto.request.PageRequest;
import cn.novalon.manage.sys.dto.response.PageResponse;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.LocalDateTime;
import java.util.List;
@Service
public class SysExceptionLogService implements ISysExceptionLogService {
private final SysExceptionLogDao dao;
private final SysExceptionLogConverter converter;
public SysExceptionLogService(SysExceptionLogDao dao, SysExceptionLogConverter converter) {
this.dao = dao;
this.converter = converter;
}
@Override
public Flux<SysExceptionLog> findAll() {
return dao.findAllByOrderByCreateTimeDesc()
.map(converter::toDomain);
}
@Override
public Flux<SysExceptionLog> findByUsername(String username) {
return dao.findByUsernameOrderByCreateTimeDesc(username)
.map(converter::toDomain);
}
@Override
public Flux<SysExceptionLog> findByCreateTimeBetween(LocalDateTime startTime, LocalDateTime endTime) {
return dao.findByCreateTimeBetweenOrderByCreateTimeDesc(startTime, endTime)
.map(converter::toDomain);
}
@Override
public Mono<SysExceptionLog> save(SysExceptionLog exceptionLog) {
return dao.save(converter.toEntity(exceptionLog))
.map(converter::toDomain);
}
@Override
public Mono<SysExceptionLog> findById(Long id) {
return dao.findById(id)
.map(converter::toDomain);
}
@Override
public Mono<PageResponse<SysExceptionLog>> findExceptionLogsByPage(PageRequest pageRequest) {
Flux<SysExceptionLog> allLogs = dao.findAllByOrderByCreateTimeDesc()
.map(converter::toDomain);
if (pageRequest.getKeyword() != null && !pageRequest.getKeyword().isEmpty()) {
String keyword = pageRequest.getKeyword().toLowerCase();
allLogs = allLogs
.filter(log -> (log.getUsername() != null && log.getUsername().toLowerCase().contains(keyword)) ||
(log.getTitle() != null && log.getTitle().toLowerCase().contains(keyword)) ||
(log.getExceptionName() != null && log.getExceptionName().toLowerCase().contains(keyword)));
}
return allLogs
.collectList()
.map(list -> {
if (pageRequest.getSort() != null && !pageRequest.getSort().isEmpty()) {
list.sort((a, b) -> {
int comparison = 0;
if ("username".equals(pageRequest.getSort())) {
comparison = compareStrings(a.getUsername(), b.getUsername());
} else if ("title".equals(pageRequest.getSort())) {
comparison = compareStrings(a.getTitle(), b.getTitle());
} else if ("createTime".equals(pageRequest.getSort())) {
comparison = compareLocalDateTimes(a.getCreateTime(), b.getCreateTime());
}
return "desc".equalsIgnoreCase(pageRequest.getOrder()) ? -comparison : comparison;
});
}
return list;
})
.zipWith(dao.count())
.map(tuple -> {
List<SysExceptionLog> all = tuple.getT1();
long totalCount = tuple.getT2();
int totalPages = (int) Math.ceil((double) totalCount / pageRequest.getSize());
int fromIndex = pageRequest.getPage() * pageRequest.getSize();
int toIndex = Math.min(fromIndex + pageRequest.getSize(), all.size());
List<SysExceptionLog> pageData = fromIndex < all.size()
? all.subList(fromIndex, toIndex)
: List.of();
return new PageResponse<SysExceptionLog>(
pageData,
totalPages,
totalCount,
pageRequest.getPage(),
pageRequest.getSize());
});
}
private int compareStrings(String a, String b) {
if (a == null && b == null)
return 0;
if (a == null)
return -1;
if (b == null)
return 1;
return a.compareTo(b);
}
private int compareLocalDateTimes(LocalDateTime a, LocalDateTime b) {
if (a == null && b == null)
return 0;
if (a == null)
return -1;
if (b == null)
return 1;
return a.compareTo(b);
}
@Override
public Mono<Long> count() {
return dao.count();
}
}
@@ -1,47 +0,0 @@
package cn.novalon.manage.sys.core.service.impl;
import cn.novalon.manage.sys.core.domain.SysExceptionLog;
import cn.novalon.manage.sys.core.service.ISysExceptionLogService;
import cn.novalon.manage.sys.infrastructure.db.converter.SysExceptionLogConverter;
import cn.novalon.manage.sys.infrastructure.db.dao.SysExceptionLogDao;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.LocalDateTime;
@Service
public class SysExceptionLogServiceImpl implements ISysExceptionLogService {
private final SysExceptionLogDao dao;
private final SysExceptionLogConverter converter;
public SysExceptionLogServiceImpl(SysExceptionLogDao dao, SysExceptionLogConverter converter) {
this.dao = dao;
this.converter = converter;
}
@Override
public Flux<SysExceptionLog> findAll() {
return dao.findAllByOrderByCreateTimeDesc()
.map(converter::toDomain);
}
@Override
public Flux<SysExceptionLog> findByUsername(String username) {
return dao.findByUsernameOrderByCreateTimeDesc(username)
.map(converter::toDomain);
}
@Override
public Flux<SysExceptionLog> findByCreateTimeBetween(LocalDateTime startTime, LocalDateTime endTime) {
return dao.findByCreateTimeBetweenOrderByCreateTimeDesc(startTime, endTime)
.map(converter::toDomain);
}
@Override
public Mono<SysExceptionLog> save(SysExceptionLog exceptionLog) {
return dao.save(converter.toEntity(exceptionLog))
.map(converter::toDomain);
}
}
@@ -4,6 +4,7 @@ import cn.novalon.manage.sys.core.domain.SysFile;
import cn.novalon.manage.sys.core.service.ISysFileService;
import cn.novalon.manage.sys.infrastructure.db.converter.SysFileConverter;
import cn.novalon.manage.sys.infrastructure.db.dao.SysFileDao;
import org.springframework.http.codec.multipart.FilePart;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import reactor.core.publisher.Flux;
@@ -16,13 +17,13 @@ import java.time.LocalDateTime;
import java.util.UUID;
@Service
public class SysFileServiceImpl implements ISysFileService {
public class SysFileService implements ISysFileService {
private final SysFileDao dao;
private final SysFileConverter converter;
private final Path uploadPath = Paths.get("./uploads");
public SysFileServiceImpl(SysFileDao dao, SysFileConverter converter) {
public SysFileService(SysFileDao dao, SysFileConverter converter) {
this.dao = dao;
this.converter = converter;
}
@@ -45,6 +46,13 @@ public class SysFileServiceImpl implements ISysFileService {
.map(converter::toDomain);
}
@Override
public Mono<SysFile> findByFileName(String fileName) {
return dao.findByFilePathContaining(fileName)
.map(converter::toDomain)
.next();
}
@Override
public Mono<SysFile> upload(MultipartFile file, String createBy) {
try {
@@ -57,7 +65,7 @@ public class SysFileServiceImpl implements ISysFileService {
SysFile sysFile = new SysFile();
sysFile.setFileName(file.getOriginalFilename());
sysFile.setFilePath("/api/files/download/" + fileName);
sysFile.setFilePath(filePath.toString());
sysFile.setFileSize(String.valueOf(file.getSize()));
sysFile.setFileType(file.getContentType());
sysFile.setStorageType("local");
@@ -75,4 +83,32 @@ public class SysFileServiceImpl implements ISysFileService {
public Mono<Void> deleteById(Long id) {
return dao.deleteByIdAndDeletedAtIsNull(id);
}
@Override
public Mono<SysFile> uploadFilePart(FilePart filePart, String createBy) {
try {
if (!Files.exists(uploadPath)) {
Files.createDirectories(uploadPath);
}
String fileName = UUID.randomUUID() + "_" + filePart.filename();
Path filePath = uploadPath.resolve(fileName);
return filePart.transferTo(filePath.toFile())
.then(Mono.fromCallable(() -> {
SysFile sysFile = new SysFile();
sysFile.setFileName(filePart.filename());
sysFile.setFilePath(filePath.toString());
sysFile.setFileSize("0");
sysFile.setFileType(filePart.headers().getContentType().toString());
sysFile.setStorageType("local");
sysFile.setCreateBy(createBy);
sysFile.setCreatedAt(LocalDateTime.now());
return sysFile;
}))
.flatMap(sysFile -> dao.save(converter.toEntity(sysFile)))
.map(converter::toDomain);
} catch (Exception e) {
return Mono.error(new RuntimeException("文件上传失败: " + e.getMessage()));
}
}
}
@@ -0,0 +1,129 @@
package cn.novalon.manage.sys.core.service.impl;
import cn.novalon.manage.sys.core.domain.SysLoginLog;
import cn.novalon.manage.sys.core.service.ISysLoginLogService;
import cn.novalon.manage.sys.infrastructure.db.converter.SysLoginLogConverter;
import cn.novalon.manage.sys.infrastructure.db.dao.SysLoginLogDao;
import cn.novalon.manage.sys.dto.request.PageRequest;
import cn.novalon.manage.sys.dto.response.PageResponse;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.LocalDateTime;
import java.util.List;
@Service
public class SysLoginLogService implements ISysLoginLogService {
private final SysLoginLogDao dao;
private final SysLoginLogConverter converter;
public SysLoginLogService(SysLoginLogDao dao, SysLoginLogConverter converter) {
this.dao = dao;
this.converter = converter;
}
@Override
public Flux<SysLoginLog> findAll() {
return dao.findAllByOrderByLoginTimeDesc()
.map(converter::toDomain);
}
@Override
public Flux<SysLoginLog> findByUsername(String username) {
return dao.findByUsernameOrderByLoginTimeDesc(username)
.map(converter::toDomain);
}
@Override
public Flux<SysLoginLog> findByLoginTimeBetween(LocalDateTime startTime, LocalDateTime endTime) {
return dao.findByLoginTimeBetweenOrderByLoginTimeDesc(startTime, endTime)
.map(converter::toDomain);
}
@Override
public Mono<SysLoginLog> save(SysLoginLog loginLog) {
return dao.save(converter.toEntity(loginLog))
.map(converter::toDomain);
}
@Override
public Mono<SysLoginLog> findById(Long id) {
return dao.findById(id)
.map(converter::toDomain);
}
@Override
public Mono<PageResponse<SysLoginLog>> findLoginLogsByPage(PageRequest pageRequest) {
Flux<SysLoginLog> allLogs = dao.findAllByOrderByLoginTimeDesc()
.map(converter::toDomain);
if (pageRequest.getKeyword() != null && !pageRequest.getKeyword().isEmpty()) {
String keyword = pageRequest.getKeyword().toLowerCase();
allLogs = allLogs.filter(log ->
(log.getUsername() != null && log.getUsername().toLowerCase().contains(keyword)) ||
(log.getIp() != null && log.getIp().toLowerCase().contains(keyword)) ||
(log.getMessage() != null && log.getMessage().toLowerCase().contains(keyword))
);
}
return allLogs
.collectList()
.map(list -> {
if (pageRequest.getSort() != null && !pageRequest.getSort().isEmpty()) {
list.sort((a, b) -> {
int comparison = 0;
if ("username".equals(pageRequest.getSort())) {
comparison = compareStrings(a.getUsername(), b.getUsername());
} else if ("ip".equals(pageRequest.getSort())) {
comparison = compareStrings(a.getIp(), b.getIp());
} else if ("loginTime".equals(pageRequest.getSort())) {
comparison = compareLocalDateTimes(a.getLoginTime(), b.getLoginTime());
}
return "desc".equalsIgnoreCase(pageRequest.getOrder()) ? -comparison : comparison;
});
}
return list;
})
.zipWith(dao.count())
.map(tuple -> {
List<SysLoginLog> all = tuple.getT1();
long totalCount = tuple.getT2();
int totalPages = (int) Math.ceil((double) totalCount / pageRequest.getSize());
int fromIndex = pageRequest.getPage() * pageRequest.getSize();
int toIndex = Math.min(fromIndex + pageRequest.getSize(), all.size());
List<SysLoginLog> pageData = fromIndex < all.size()
? all.subList(fromIndex, toIndex)
: List.of();
return new PageResponse<SysLoginLog>(
pageData,
totalPages,
totalCount,
pageRequest.getPage(),
pageRequest.getSize());
});
}
private int compareStrings(String a, String b) {
if (a == null && b == null) return 0;
if (a == null) return -1;
if (b == null) return 1;
return a.compareTo(b);
}
private int compareLocalDateTimes(LocalDateTime a, LocalDateTime b) {
if (a == null && b == null) return 0;
if (a == null) return -1;
if (b == null) return 1;
return a.compareTo(b);
}
@Override
public Mono<Long> count() {
return dao.count();
}
}
@@ -1,47 +0,0 @@
package cn.novalon.manage.sys.core.service.impl;
import cn.novalon.manage.sys.core.domain.SysLoginLog;
import cn.novalon.manage.sys.core.service.ISysLoginLogService;
import cn.novalon.manage.sys.infrastructure.db.converter.SysLoginLogConverter;
import cn.novalon.manage.sys.infrastructure.db.dao.SysLoginLogDao;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.LocalDateTime;
@Service
public class SysLoginLogServiceImpl implements ISysLoginLogService {
private final SysLoginLogDao dao;
private final SysLoginLogConverter converter;
public SysLoginLogServiceImpl(SysLoginLogDao dao, SysLoginLogConverter converter) {
this.dao = dao;
this.converter = converter;
}
@Override
public Flux<SysLoginLog> findAll() {
return dao.findAllByOrderByLoginTimeDesc()
.map(converter::toDomain);
}
@Override
public Flux<SysLoginLog> findByUsername(String username) {
return dao.findByUsernameOrderByLoginTimeDesc(username)
.map(converter::toDomain);
}
@Override
public Flux<SysLoginLog> findByLoginTimeBetween(LocalDateTime startTime, LocalDateTime endTime) {
return dao.findByLoginTimeBetweenOrderByLoginTimeDesc(startTime, endTime)
.map(converter::toDomain);
}
@Override
public Mono<SysLoginLog> save(SysLoginLog loginLog) {
return dao.save(converter.toEntity(loginLog))
.map(converter::toDomain);
}
}
@@ -1,50 +0,0 @@
package cn.novalon.manage.sys.core.service.impl;
import cn.novalon.manage.sys.core.domain.SysNotice;
import cn.novalon.manage.sys.core.service.ISysNoticeService;
import cn.novalon.manage.sys.infrastructure.db.converter.SysNoticeConverter;
import cn.novalon.manage.sys.infrastructure.db.dao.SysNoticeDao;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@Service
public class SysNoticeServiceImpl implements ISysNoticeService {
private final SysNoticeDao dao;
private final SysNoticeConverter converter;
public SysNoticeServiceImpl(SysNoticeDao dao, SysNoticeConverter converter) {
this.dao = dao;
this.converter = converter;
}
@Override
public Flux<SysNotice> findAll() {
return dao.findByDeletedAtIsNull()
.map(converter::toDomain);
}
@Override
public Flux<SysNotice> findByStatus(String status) {
return dao.findByStatusAndDeletedAtIsNull(status)
.map(converter::toDomain);
}
@Override
public Mono<SysNotice> findById(Long id) {
return dao.findById(id)
.map(converter::toDomain);
}
@Override
public Mono<SysNotice> save(SysNotice notice) {
return dao.save(converter.toEntity(notice))
.map(converter::toDomain);
}
@Override
public Mono<Void> deleteById(Long id) {
return dao.deleteByIdAndDeletedAtIsNull(id);
}
}
@@ -1,8 +1,16 @@
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.domain.query.SysRoleQuery;
import cn.novalon.manage.sys.core.repository.ISysRoleRepository;
import cn.novalon.manage.sys.core.service.ISysRoleService;
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;
import reactor.core.publisher.Mono;
@@ -28,10 +36,32 @@ public class SysRoleService implements ISysRoleService {
return roleRepository.findAll();
}
@Override
public Mono<PageResponse<SysRole>> findRolesByPage(PageRequest pageRequest) {
SysRoleQuery query = new SysRoleQuery();
if (pageRequest.getKeyword() != null && !pageRequest.getKeyword().isEmpty()) {
query.setRoleName(pageRequest.getKeyword());
query.setRoleKey(pageRequest.getKeyword());
}
SysRoleQueryCriteria criteria = new SysRoleQueryCriteria();
criteria.convert(query);
Query queryObj = QueryUtil.getQuery(criteria);
return roleRepository.findByQueryWithPagination(queryObj, pageRequest);
}
@Override
public Mono<Long> count() {
return roleRepository.count();
}
@Override
public Mono<SysRole> createRole(SysRole role) {
role.setCreatedAt(LocalDateTime.now());
role.setStatus(1);
role.setStatus(StatusConstants.ENABLED);
return roleRepository.save(role);
}
@@ -45,4 +75,32 @@ public class SysRoleService implements ISysRoleService {
public Mono<Void> deleteRole(Long id) {
return roleRepository.deleteById(id);
}
@Override
public Mono<SysRole> findByRoleName(String roleName) {
return roleRepository.findByRoleName(roleName);
}
@Override
public Mono<Boolean> existsByRoleName(String roleName) {
return roleRepository.existsByRoleName(roleName);
}
@Override
public Mono<SysRole> logicalDeleteRole(Long id) {
return roleRepository.findByIdIncludingDeleted(id)
.flatMap(role -> {
role.delete();
return roleRepository.updateRole(role);
});
}
@Override
public Mono<SysRole> restoreRole(Long id) {
return roleRepository.findByIdIncludingDeleted(id)
.flatMap(role -> {
role.restore();
return roleRepository.updateRole(role);
});
}
}
@@ -61,4 +61,9 @@ public class SysUserMessageService implements ISysUserMessageService {
})
.then();
}
@Override
public Mono<Void> deleteById(Long id) {
return dao.deleteById(id);
}
}
@@ -1,54 +0,0 @@
package cn.novalon.manage.sys.core.service.impl;
import cn.novalon.manage.sys.core.domain.SysUserMessage;
import cn.novalon.manage.sys.core.service.ISysUserMessageService;
import cn.novalon.manage.sys.infrastructure.db.converter.SysUserMessageConverter;
import cn.novalon.manage.sys.infrastructure.db.dao.SysUserMessageDao;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@Service
public class SysUserMessageServiceImpl implements ISysUserMessageService {
private final SysUserMessageDao dao;
private final SysUserMessageConverter converter;
public SysUserMessageServiceImpl(SysUserMessageDao dao, SysUserMessageConverter converter) {
this.dao = dao;
this.converter = converter;
}
@Override
public Flux<SysUserMessage> findByUserId(Long userId) {
return dao.findByUserIdOrderByCreateTimeDesc(userId)
.map(converter::toDomain);
}
@Override
public Flux<SysUserMessage> findByUserIdAndIsRead(Long userId, String isRead) {
return dao.findByUserIdAndIsReadOrderByCreateTimeDesc(userId, isRead)
.map(converter::toDomain);
}
@Override
public Mono<Long> countUnread(Long userId) {
return dao.countByUserIdAndIsRead(userId, "0");
}
@Override
public Mono<SysUserMessage> save(SysUserMessage message) {
return dao.save(converter.toEntity(message))
.map(converter::toDomain);
}
@Override
public Mono<Void> markAsRead(Long id) {
return dao.findById(id)
.flatMap(entity -> {
entity.setIsRead("1");
return dao.save(entity);
})
.then();
}
}
@@ -1,13 +1,22 @@
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.domain.query.SysUserQuery;
import cn.novalon.manage.sys.core.repository.ISysUserRepository;
import cn.novalon.manage.sys.core.service.ISysUserService;
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.SysUserQueryCriteria;
import cn.novalon.manage.sys.infrastructure.db.utils.QueryUtil;
import org.springframework.data.relational.core.query.Query;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.LocalDateTime;
import java.util.List;
@Service
public class SysUserService implements ISysUserService {
@@ -25,6 +34,42 @@ public class SysUserService implements ISysUserService {
return userRepository.findById(id);
}
@Override
public Flux<SysUser> findAll() {
return userRepository.findAll();
}
@Override
public Flux<SysUser> findAll(boolean includeDeleted) {
if (includeDeleted) {
return userRepository.findAll();
} else {
return userRepository.findByDeletedAtIsNull();
}
}
@Override
public Mono<PageResponse<SysUser>> findUsersByPage(PageRequest pageRequest) {
SysUserQuery query = new SysUserQuery();
if (pageRequest.getKeyword() != null && !pageRequest.getKeyword().isEmpty()) {
query.setUsername(pageRequest.getKeyword());
query.setEmail(pageRequest.getKeyword());
}
SysUserQueryCriteria criteria = new SysUserQueryCriteria();
criteria.convert(query);
Query queryObj = QueryUtil.getQuery(criteria);
return userRepository.findByQueryWithPagination(queryObj, pageRequest);
}
@Override
public Mono<Long> count() {
return userRepository.count();
}
@Override
public Mono<SysUser> findByUsername(String username) {
return userRepository.findByUsername(username);
@@ -34,7 +79,7 @@ public class SysUserService implements ISysUserService {
public Mono<SysUser> createUser(SysUser user) {
user.setPassword(passwordEncoder.encode(user.getPassword()));
user.setCreatedAt(LocalDateTime.now());
user.setStatus(1);
user.setStatus(StatusConstants.ENABLED);
return userRepository.save(user);
}
@@ -61,4 +106,48 @@ public class SysUserService implements ISysUserService {
return userRepository.save(user);
});
}
@Override
public Mono<Boolean> existsByUsername(String username) {
return userRepository.findByUsername(username)
.map(user -> user != null)
.defaultIfEmpty(false);
}
@Override
public Mono<Boolean> existsByEmail(String email) {
return userRepository.findByEmail(email)
.map(user -> user != null)
.defaultIfEmpty(false);
}
@Override
public Mono<Void> logicalDeleteUser(Long id) {
return userRepository.findByIdIncludingDeleted(id)
.flatMap(user -> {
user.setDeletedAt(LocalDateTime.now());
return userRepository.save(user);
})
.then();
}
@Override
public Mono<Void> logicalDeleteUsers(List<Long> ids) {
return userRepository.logicalDeleteByIds(ids);
}
@Override
public Mono<Void> restoreUser(Long id) {
return userRepository.findByIdIncludingDeleted(id)
.flatMap(user -> {
user.setDeletedAt(null);
return userRepository.save(user);
})
.then();
}
@Override
public Mono<Void> restoreUsers(List<Long> ids) {
return userRepository.restoreByIds(ids);
}
}
@@ -0,0 +1,220 @@
package cn.novalon.manage.sys.core.utils;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.LockSupport;
/**
* Twitter的Snowflake算法实现(性能优化版)
*
* 优化点:
* 1. 使用自适应等待策略,减少CPU空转
* 2. 时间戳缓存机制,降低系统调用频率
* 3. 增强CAS重试策略,提升并发性能
* 4. 完善异常处理和资源管理
*
* @author zhangxiang
* @version 2.0
* @date 2026/03/11
*/
public final class SnowflakeId {
private static final int DEFAULT_WORKER_BITS = 10;
private static final int DEFAULT_SEQ_BITS = 12;
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 long TIME_CACHE_DURATION_MS = 16;
private static final AtomicLong lastTimestamp = new AtomicLong(-1L);
private static final AtomicLong sequence = new AtomicLong(0);
private static volatile SnowflakeConfig config;
private static volatile long workerId;
private static volatile long lastTimeCacheMs;
private static volatile int timeCacheHits;
static {
configure(DEFAULT_WORKER_BITS, DEFAULT_SEQ_BITS, DEFAULT_EPOCH);
}
private static void configure(int workerBits, int seqBits, long epoch) {
validateBits(workerBits, seqBits);
config = new SnowflakeConfig(epoch, workerBits, seqBits);
workerId = resolveWorkerId(config.maxWorkerId);
lastTimeCacheMs = 0;
timeCacheHits = 0;
}
public static long nextId() {
for (int i = 0; i < MAX_RETRIES; i++) {
try {
return nextIdInternal();
} catch (ClockBackwardException e) {
long backwardMs = e.getBackwardMs();
if (backwardMs > MAX_BACKWARD_MS) {
throw e;
}
if (i < SPIN_THRESHOLD) {
LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(1));
} else {
LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(10));
}
}
}
throw new IllegalStateException("Failed to generate ID after " + MAX_RETRIES + " retries");
}
private static long nextIdInternal() {
long currentTs = timeGen();
long lastTs;
long seq;
do {
lastTs = lastTimestamp.get();
if (currentTs < lastTs) {
long backwardMs = lastTs - currentTs;
if (backwardMs <= MAX_BACKWARD_MS) {
lastTimestamp.set(currentTs);
lastTs = currentTs;
} else {
throw new ClockBackwardException(backwardMs);
}
}
if (currentTs == lastTs) {
seq = sequence.incrementAndGet() & config.sequenceMask;
if (seq == 0) {
currentTs = waitNextMillis(currentTs);
}
} else {
seq = 0;
}
} while (!lastTimestamp.compareAndSet(lastTs, currentTs));
return ((currentTs - config.epoch) << config.timestampShift)
| (workerId << config.workerShift)
| seq;
}
private static long waitNextMillis(long currentTs) {
long deadline = currentTs + 2;
int spinCount = 0;
while (currentTs <= lastTimestamp.get()) {
if (currentTs >= deadline) {
return currentTs;
}
if (spinCount < 10) {
spinCount++;
} else if (spinCount < 50) {
LockSupport.parkNanos(100_000);
spinCount++;
} else {
LockSupport.parkNanos(500_000);
}
currentTs = timeGen();
}
return currentTs;
}
private static long timeGen() {
long now = System.currentTimeMillis();
long cached = lastTimeCacheMs;
if (now - cached < TIME_CACHE_DURATION_MS) {
timeCacheHits++;
return cached;
}
synchronized (SnowflakeId.class) {
cached = lastTimeCacheMs;
if (now - cached < TIME_CACHE_DURATION_MS) {
timeCacheHits++;
return cached;
}
lastTimeCacheMs = now;
return now;
}
}
public static int getTimeCacheHits() {
return timeCacheHits;
}
public static void resetTimeCache() {
synchronized (SnowflakeId.class) {
lastTimeCacheMs = 0;
timeCacheHits = 0;
}
}
private static void validateBits(int workerBits, int seqBits) {
if (workerBits < 0 || workerBits > 22) {
throw new IllegalArgumentException("WorkerID位数必须在0-22之间");
}
if (seqBits < 0 || seqBits > 22) {
throw new IllegalArgumentException("序列号位数必须在0-22之间");
}
if (workerBits + seqBits > 22) {
throw new IllegalArgumentException("WorkerID和序列号位数总和不能超过22位,当前为: " + (workerBits + seqBits));
}
if (workerBits + seqBits == 0) {
throw new IllegalArgumentException("WorkerID和序列号位数总和不能为0");
}
}
private static long resolveWorkerId(long maxWorkerId) {
long id = generateNewId();
if (id < 0 || id > maxWorkerId) {
throw new IllegalStateException("WorkerID超出有效范围: " + id + " (有效范围: 0-" + maxWorkerId + ")");
}
return id;
}
private static long generateNewId() {
long newId = ThreadLocalRandom.current().nextLong(config.maxWorkerId + 1);
return newId;
}
public static void config(int workerBits, int seqBits, long epoch) {
configure(workerBits, seqBits, epoch);
}
public static long getWorkerId() {
return workerId;
}
private static class SnowflakeConfig {
final long epoch;
final int timestampShift;
final int workerShift;
final long sequenceMask;
final long maxWorkerId;
SnowflakeConfig(long epoch, int workerBits, int seqBits) {
this.epoch = epoch;
this.timestampShift = workerBits + seqBits;
this.workerShift = seqBits;
this.sequenceMask = ~(-1L << seqBits);
this.maxWorkerId = ~(-1L << workerBits);
}
}
public static class ClockBackwardException extends RuntimeException {
private static final long serialVersionUID = 1L;
private final long backwardMs;
ClockBackwardException(long backwardMs) {
super("Clock moved backwards by " + backwardMs + "ms");
this.backwardMs = backwardMs;
}
public long getBackwardMs() {
return backwardMs;
}
}
}
@@ -0,0 +1,49 @@
package cn.novalon.manage.sys.dto.request;
public class PageRequest {
private int page = 0;
private int size = 10;
private String sort = "id";
private String order = "asc";
private String keyword;
public int getPage() {
return page;
}
public void setPage(int page) {
this.page = page;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public String getSort() {
return sort;
}
public void setSort(String sort) {
this.sort = sort;
}
public String getOrder() {
return order;
}
public void setOrder(String order) {
this.order = order;
}
public String getKeyword() {
return keyword;
}
public void setKeyword(String keyword) {
this.keyword = keyword;
}
}
@@ -0,0 +1,82 @@
package cn.novalon.manage.sys.dto.response;
import java.util.List;
public class PageResponse<T> {
private List<T> content;
private int totalPages;
private long totalElements;
private int currentPage;
private int pageSize;
private boolean first;
private boolean last;
public PageResponse() {
}
public PageResponse(List<T> content, int totalPages, long totalElements, int currentPage, int pageSize) {
this.content = content;
this.totalPages = totalPages;
this.totalElements = totalElements;
this.currentPage = currentPage;
this.pageSize = pageSize;
this.first = currentPage == 0;
this.last = currentPage >= totalPages - 1;
}
public List<T> getContent() {
return content;
}
public void setContent(List<T> content) {
this.content = content;
}
public int getTotalPages() {
return totalPages;
}
public void setTotalPages(int totalPages) {
this.totalPages = totalPages;
}
public long getTotalElements() {
return totalElements;
}
public void setTotalElements(long totalElements) {
this.totalElements = totalElements;
}
public int getCurrentPage() {
return currentPage;
}
public void setCurrentPage(int currentPage) {
this.currentPage = currentPage;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public boolean isFirst() {
return first;
}
public void setFirst(boolean first) {
this.first = first;
}
public boolean isLast() {
return last;
}
public void setLast(boolean last) {
this.last = last;
}
}
@@ -1,18 +1,26 @@
package cn.novalon.manage.sys.handler;
import cn.novalon.manage.sys.core.domain.SysExceptionLog;
import cn.novalon.manage.sys.core.exception.DictionaryAlreadyExistsException;
import cn.novalon.manage.sys.core.service.ISysExceptionLogService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.ServerWebInputException;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
@RestControllerAdvice
public class GlobalExceptionHandler {
@@ -26,15 +34,15 @@ public class GlobalExceptionHandler {
}
@ExceptionHandler(Exception.class)
public ResponseEntity<Map<String, Object>> handleException(Exception ex, WebRequest request) {
public ResponseEntity<Map<String, Object>> handleException(Exception ex, ServerWebExchange exchange) {
logger.error("Exception occurred: ", ex);
SysExceptionLog exceptionLog = new SysExceptionLog();
exceptionLog.setTitle("System Exception");
exceptionLog.setExceptionName(ex.getClass().getSimpleName());
exceptionLog.setExceptionMsg(ex.getMessage());
exceptionLog.setMethodName(request.getDescription(false));
exceptionLog.setIp(getClientIp(request));
exceptionLog.setMethodName(exchange.getRequest().getPath().value());
exceptionLog.setIp(getClientIp(exchange));
exceptionLog.setCreateTime(LocalDateTime.now());
StringBuilder stackTrace = new StringBuilder();
@@ -54,7 +62,7 @@ public class GlobalExceptionHandler {
}
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<Map<String, Object>> handleIllegalArgumentException(IllegalArgumentException ex, WebRequest request) {
public ResponseEntity<Map<String, Object>> handleIllegalArgumentException(IllegalArgumentException ex, ServerWebExchange exchange) {
logger.warn("Illegal argument: ", ex);
Map<String, Object> response = new HashMap<>();
@@ -65,10 +73,86 @@ public class GlobalExceptionHandler {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);
}
private String getClientIp(WebRequest request) {
String ip = request.getHeader("X-Forwarded-For");
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, Object>> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex, ServerWebExchange exchange) {
logger.warn("Validation failed: ", ex);
Map<String, Object> response = new HashMap<>();
response.put("code", HttpStatus.BAD_REQUEST.value());
String errorMessage = ex.getBindingResult().getFieldErrors().stream()
.map(FieldError::getDefaultMessage)
.collect(Collectors.joining(", "));
response.put("message", errorMessage);
response.put("timestamp", LocalDateTime.now());
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);
}
@ExceptionHandler(ServerWebInputException.class)
public ResponseEntity<Map<String, Object>> handleServerWebInputException(ServerWebInputException ex, ServerWebExchange exchange) {
logger.warn("Server web input exception: ", ex);
Map<String, Object> response = new HashMap<>();
response.put("code", HttpStatus.BAD_REQUEST.value());
response.put("message", ex.getReason());
response.put("timestamp", LocalDateTime.now());
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);
}
@ExceptionHandler(ResponseStatusException.class)
public ResponseEntity<Map<String, Object>> handleResponseStatusException(ResponseStatusException ex, ServerWebExchange exchange) {
logger.warn("Response status exception: ", ex);
Map<String, Object> response = new HashMap<>();
response.put("code", ex.getStatusCode().value());
response.put("message", ex.getReason());
response.put("timestamp", LocalDateTime.now());
return ResponseEntity.status(ex.getStatusCode()).body(response);
}
@ExceptionHandler(DuplicateKeyException.class)
public ResponseEntity<Map<String, Object>> handleDuplicateKeyException(DuplicateKeyException ex, ServerWebExchange exchange) {
logger.warn("Duplicate key: ", ex);
Map<String, Object> response = new HashMap<>();
response.put("code", HttpStatus.CONFLICT.value());
response.put("message", "Duplicate key violation");
response.put("timestamp", LocalDateTime.now());
return ResponseEntity.status(HttpStatus.CONFLICT).body(response);
}
@ExceptionHandler(DataIntegrityViolationException.class)
public ResponseEntity<Map<String, Object>> handleDataIntegrityViolationException(DataIntegrityViolationException ex, ServerWebExchange exchange) {
logger.warn("Data integrity violation: ", ex);
Map<String, Object> response = new HashMap<>();
response.put("code", HttpStatus.CONFLICT.value());
response.put("message", "Data integrity violation");
response.put("timestamp", LocalDateTime.now());
return ResponseEntity.status(HttpStatus.CONFLICT).body(response);
}
@ExceptionHandler(DictionaryAlreadyExistsException.class)
public ResponseEntity<Map<String, Object>> handleDictionaryAlreadyExistsException(DictionaryAlreadyExistsException ex, ServerWebExchange exchange) {
logger.warn("Dictionary already exists: type={}, code={}", ex.getType(), ex.getCode());
Map<String, Object> response = new HashMap<>();
response.put("code", HttpStatus.CONFLICT.value());
response.put("message", ex.getMessage());
response.put("timestamp", LocalDateTime.now());
return ResponseEntity.status(HttpStatus.CONFLICT).body(response);
}
private String getClientIp(ServerWebExchange exchange) {
String ip = exchange.getRequest().getHeaders().getFirst("X-Forwarded-For");
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("X-Real-IP");
ip = exchange.getRequest().getHeaders().getFirst("X-Real-IP");
}
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = "127.0.0.1";
@@ -6,15 +6,14 @@ import cn.novalon.manage.sys.dto.response.AuthResponse;
import cn.novalon.manage.sys.security.JwtTokenProvider;
import cn.novalon.manage.sys.core.domain.SysUser;
import cn.novalon.manage.sys.core.service.ISysUserService;
import jakarta.validation.Valid;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
@RestController
@RequestMapping("/api/auth")
@Component
public class SysAuthHandler {
private final ISysUserService userService;
@@ -27,33 +26,34 @@ public class SysAuthHandler {
this.jwtTokenProvider = jwtTokenProvider;
}
@PostMapping("/login")
public Mono<ResponseEntity<AuthResponse>> login(@Valid @RequestBody LoginRequest request) {
return userService.findByUsername(request.getUsername())
.filter(user -> passwordEncoder.matches(request.getPassword(), user.getPassword()))
.filter(user -> 1 == user.getStatus())
.map(user -> {
String token = jwtTokenProvider.generateToken(user.getUsername(), user.getId());
AuthResponse response = new AuthResponse(token, user.getId(), user.getUsername());
return ResponseEntity.ok(response);
})
.defaultIfEmpty(ResponseEntity.status(HttpStatus.UNAUTHORIZED).build());
public Mono<ServerResponse> login(ServerRequest request) {
return request.bodyToMono(LoginRequest.class)
.flatMap(loginRequest -> userService.findByUsername(loginRequest.getUsername())
.filter(user -> passwordEncoder.matches(loginRequest.getPassword(), user.getPassword()))
.filter(user -> 1 == user.getStatus())
.flatMap(user -> {
String token = jwtTokenProvider.generateToken(user.getUsername(), user.getId());
AuthResponse response = new AuthResponse(token, user.getId(), user.getUsername());
return ServerResponse.ok().bodyValue(response);
})
.switchIfEmpty(ServerResponse.status(HttpStatus.UNAUTHORIZED).build()));
}
@PostMapping("/register")
public Mono<ResponseEntity<SysUser>> register(@Valid @RequestBody UserRegisterRequest request) {
SysUser user = new SysUser();
user.setUsername(request.getUsername());
user.setPassword(request.getPassword());
user.setEmail(request.getEmail());
return userService.findByUsername(request.getUsername())
.flatMap(existing -> Mono.<ResponseEntity<SysUser>>error(new RuntimeException("用户名已存在")))
.switchIfEmpty(userService.createUser(user)
.map(u -> ResponseEntity.status(HttpStatus.CREATED).body(u)));
public Mono<ServerResponse> register(ServerRequest request) {
return request.bodyToMono(UserRegisterRequest.class)
.flatMap(registerRequest -> {
SysUser user = new SysUser();
user.setUsername(registerRequest.getUsername());
user.setPassword(registerRequest.getPassword());
user.setEmail(registerRequest.getEmail());
return userService.findByUsername(registerRequest.getUsername())
.flatMap(existing -> Mono.<ServerResponse>error(new RuntimeException("用户名已存在")))
.switchIfEmpty(userService.createUser(user)
.flatMap(u -> ServerResponse.status(HttpStatus.CREATED).bodyValue(u)));
});
}
@PostMapping("/logout")
public Mono<ResponseEntity<Void>> logout() {
return Mono.just(ResponseEntity.ok().build());
public Mono<ServerResponse> logout(ServerRequest request) {
return ServerResponse.ok().build();
}
}
@@ -3,13 +3,12 @@ package cn.novalon.manage.sys.handler.config;
import cn.novalon.manage.sys.core.domain.SysConfig;
import cn.novalon.manage.sys.core.service.ISysConfigService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
@RestController
@RequestMapping("/api/config")
@Component
public class SysConfigHandler {
private final ISysConfigService configService;
@@ -18,47 +17,48 @@ public class SysConfigHandler {
this.configService = configService;
}
@GetMapping
public Flux<SysConfig> getAllConfigs() {
return configService.findAll();
public Mono<ServerResponse> getAllConfigs(ServerRequest request) {
return ServerResponse.ok()
.body(configService.findAll(), SysConfig.class);
}
@GetMapping("/{id}")
public Mono<ResponseEntity<SysConfig>> getConfigById(@PathVariable Long id) {
public Mono<ServerResponse> getConfigById(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return configService.findById(id)
.map(ResponseEntity::ok)
.defaultIfEmpty(ResponseEntity.notFound().build());
.flatMap(config -> ServerResponse.ok().bodyValue(config))
.switchIfEmpty(ServerResponse.notFound().build());
}
@GetMapping("/key/{configKey}")
public Mono<ResponseEntity<SysConfig>> getConfigByKey(@PathVariable String configKey) {
public Mono<ServerResponse> getConfigByKey(ServerRequest request) {
String configKey = request.pathVariable("configKey");
return configService.findByConfigKey(configKey)
.map(ResponseEntity::ok)
.defaultIfEmpty(ResponseEntity.notFound().build());
.flatMap(config -> ServerResponse.ok().bodyValue(config))
.switchIfEmpty(ServerResponse.notFound().build());
}
@PostMapping
public Mono<ResponseEntity<SysConfig>> createConfig(@RequestBody SysConfig config) {
return configService.save(config)
.map(c -> ResponseEntity.status(HttpStatus.CREATED).body(c));
public Mono<ServerResponse> createConfig(ServerRequest request) {
return request.bodyToMono(SysConfig.class)
.flatMap(configService::save)
.flatMap(config -> ServerResponse.status(HttpStatus.CREATED).bodyValue(config));
}
@PutMapping("/{id}")
public Mono<ResponseEntity<SysConfig>> updateConfig(@PathVariable Long id, @RequestBody SysConfig config) {
return configService.findById(id)
.flatMap(existing -> {
existing.setConfigName(config.getConfigName());
existing.setConfigValue(config.getConfigValue());
existing.setConfigType(config.getConfigType());
return configService.save(existing);
})
.map(ResponseEntity::ok)
.defaultIfEmpty(ResponseEntity.notFound().build());
public Mono<ServerResponse> updateConfig(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return request.bodyToMono(SysConfig.class)
.flatMap(config -> configService.findById(id)
.flatMap(existing -> {
existing.setConfigName(config.getConfigName());
existing.setConfigValue(config.getConfigValue());
existing.setConfigType(config.getConfigType());
return configService.save(existing);
}))
.flatMap(updatedConfig -> ServerResponse.ok().bodyValue(updatedConfig))
.switchIfEmpty(ServerResponse.notFound().build());
}
@DeleteMapping("/{id}")
public Mono<ResponseEntity<Void>> deleteConfig(@PathVariable Long id) {
public Mono<ServerResponse> deleteConfig(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return configService.deleteById(id)
.then(Mono.just(ResponseEntity.noContent().build()));
.then(ServerResponse.noContent().build());
}
}
@@ -5,13 +5,12 @@ import cn.novalon.manage.sys.core.domain.SysDictData;
import cn.novalon.manage.sys.core.service.ISysDictTypeService;
import cn.novalon.manage.sys.core.service.ISysDictDataService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
@RestController
@RequestMapping("/api/dict")
@Component
public class SysDictHandler {
private final ISysDictTypeService dictTypeService;
@@ -22,93 +21,96 @@ public class SysDictHandler {
this.dictDataService = dictDataService;
}
@GetMapping("/types")
public Flux<SysDictType> getAllDictTypes() {
return dictTypeService.findAll();
public Mono<ServerResponse> getAllDictTypes(ServerRequest request) {
return ServerResponse.ok()
.body(dictTypeService.findAll(), SysDictType.class);
}
@GetMapping("/types/{id}")
public Mono<ResponseEntity<SysDictType>> getDictTypeById(@PathVariable Long id) {
public Mono<ServerResponse> getDictTypeById(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return dictTypeService.findById(id)
.map(ResponseEntity::ok)
.defaultIfEmpty(ResponseEntity.notFound().build());
.flatMap(dictType -> ServerResponse.ok().bodyValue(dictType))
.switchIfEmpty(ServerResponse.notFound().build());
}
@GetMapping("/types/type/{dictType}")
public Mono<ResponseEntity<SysDictType>> getDictTypeByType(@PathVariable String dictType) {
public Mono<ServerResponse> getDictTypeByType(ServerRequest request) {
String dictType = request.pathVariable("dictType");
return dictTypeService.findByDictType(dictType)
.map(ResponseEntity::ok)
.defaultIfEmpty(ResponseEntity.notFound().build());
.flatMap(type -> ServerResponse.ok().bodyValue(type))
.switchIfEmpty(ServerResponse.notFound().build());
}
@PostMapping("/types")
public Mono<ResponseEntity<SysDictType>> createDictType(@RequestBody SysDictType dictType) {
return dictTypeService.save(dictType)
.map(dt -> ResponseEntity.status(HttpStatus.CREATED).body(dt));
public Mono<ServerResponse> createDictType(ServerRequest request) {
return request.bodyToMono(SysDictType.class)
.flatMap(dictTypeService::save)
.flatMap(dt -> ServerResponse.status(HttpStatus.CREATED).bodyValue(dt));
}
@PutMapping("/types/{id}")
public Mono<ResponseEntity<SysDictType>> updateDictType(@PathVariable Long id, @RequestBody SysDictType dictType) {
return dictTypeService.findById(id)
.flatMap(existing -> {
existing.setDictName(dictType.getDictName());
existing.setStatus(dictType.getStatus());
existing.setRemark(dictType.getRemark());
return dictTypeService.save(existing);
})
.map(ResponseEntity::ok)
.defaultIfEmpty(ResponseEntity.notFound().build());
public Mono<ServerResponse> updateDictType(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return request.bodyToMono(SysDictType.class)
.flatMap(dictType -> dictTypeService.findById(id)
.flatMap(existing -> {
existing.setDictName(dictType.getDictName());
existing.setStatus(dictType.getStatus());
existing.setRemark(dictType.getRemark());
return dictTypeService.save(existing);
}))
.flatMap(updated -> ServerResponse.ok().bodyValue(updated))
.switchIfEmpty(ServerResponse.notFound().build());
}
@DeleteMapping("/types/{id}")
public Mono<ResponseEntity<Void>> deleteDictType(@PathVariable Long id) {
public Mono<ServerResponse> deleteDictType(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return dictTypeService.deleteById(id)
.then(Mono.just(ResponseEntity.noContent().build()));
.then(ServerResponse.noContent().build());
}
@GetMapping("/data")
public Flux<SysDictData> getAllDictData() {
return dictDataService.findAll();
public Mono<ServerResponse> getAllDictData(ServerRequest request) {
return ServerResponse.ok()
.body(dictDataService.findAll(), SysDictData.class);
}
@GetMapping("/data/{id}")
public Mono<ResponseEntity<SysDictData>> getDictDataById(@PathVariable Long id) {
public Mono<ServerResponse> getDictDataById(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return dictDataService.findById(id)
.map(ResponseEntity::ok)
.defaultIfEmpty(ResponseEntity.notFound().build());
.flatMap(dictData -> ServerResponse.ok().bodyValue(dictData))
.switchIfEmpty(ServerResponse.notFound().build());
}
@GetMapping("/data/type/{dictType}")
public Flux<SysDictData> getDictDataByType(@PathVariable String dictType) {
return dictDataService.findByDictType(dictType);
public Mono<ServerResponse> getDictDataByType(ServerRequest request) {
String dictType = request.pathVariable("dictType");
return ServerResponse.ok()
.body(dictDataService.findByDictType(dictType), SysDictData.class);
}
@PostMapping("/data")
public Mono<ResponseEntity<SysDictData>> createDictData(@RequestBody SysDictData dictData) {
return dictDataService.save(dictData)
.map(dd -> ResponseEntity.status(HttpStatus.CREATED).body(dd));
public Mono<ServerResponse> createDictData(ServerRequest request) {
return request.bodyToMono(SysDictData.class)
.flatMap(dictDataService::save)
.flatMap(dd -> ServerResponse.status(HttpStatus.CREATED).bodyValue(dd));
}
@PutMapping("/data/{id}")
public Mono<ResponseEntity<SysDictData>> updateDictData(@PathVariable Long id, @RequestBody SysDictData dictData) {
return dictDataService.findById(id)
.flatMap(existing -> {
existing.setDictLabel(dictData.getDictLabel());
existing.setDictValue(dictData.getDictValue());
existing.setDictSort(dictData.getDictSort());
existing.setCssClass(dictData.getCssClass());
existing.setListClass(dictData.getListClass());
existing.setIsDefault(dictData.getIsDefault());
existing.setStatus(dictData.getStatus());
return dictDataService.save(existing);
})
.map(ResponseEntity::ok)
.defaultIfEmpty(ResponseEntity.notFound().build());
public Mono<ServerResponse> updateDictData(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return request.bodyToMono(SysDictData.class)
.flatMap(dictData -> dictDataService.findById(id)
.flatMap(existing -> {
existing.setDictLabel(dictData.getDictLabel());
existing.setDictValue(dictData.getDictValue());
existing.setDictSort(dictData.getDictSort());
existing.setCssClass(dictData.getCssClass());
existing.setListClass(dictData.getListClass());
existing.setIsDefault(dictData.getIsDefault());
existing.setStatus(dictData.getStatus());
return dictDataService.save(existing);
}))
.flatMap(updated -> ServerResponse.ok().bodyValue(updated))
.switchIfEmpty(ServerResponse.notFound().build());
}
@DeleteMapping("/data/{id}")
public Mono<ResponseEntity<Void>> deleteDictData(@PathVariable Long id) {
public Mono<ServerResponse> deleteDictData(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return dictDataService.deleteById(id)
.then(Mono.just(ResponseEntity.noContent().build()));
.then(ServerResponse.noContent().build());
}
}
@@ -8,10 +8,12 @@ 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.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import reactor.core.publisher.Flux;
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;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
import java.io.IOException;
@@ -20,8 +22,7 @@ import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Base64;
@RestController
@RequestMapping("/api/files")
@Component
public class SysFileHandler {
private final ISysFileService fileService;
@@ -30,28 +31,37 @@ public class SysFileHandler {
this.fileService = fileService;
}
@GetMapping
public Flux<SysFile> getAllFiles() {
return fileService.findAll();
public Mono<ServerResponse> getAllFiles(ServerRequest request) {
return ServerResponse.ok()
.body(fileService.findAll(), SysFile.class);
}
@GetMapping("/{id}")
public Mono<ResponseEntity<SysFile>> getFileById(@PathVariable Long id) {
public Mono<ServerResponse> getFileById(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return fileService.findById(id)
.map(ResponseEntity::ok)
.defaultIfEmpty(ResponseEntity.notFound().build());
.flatMap(file -> ServerResponse.ok().bodyValue(file))
.switchIfEmpty(ServerResponse.notFound().build());
}
@PostMapping("/upload")
public Mono<ResponseEntity<SysFile>> uploadFile(
@RequestParam("file") MultipartFile file,
@RequestParam(value = "createBy", required = false) String createBy) {
return fileService.upload(file, createBy)
.map(f -> ResponseEntity.status(HttpStatus.CREATED).body(f));
public Mono<ServerResponse> uploadFile(ServerRequest request) {
return request.multipartData()
.flatMap(data -> {
FilePart filePart = (FilePart) data.toSingleValueMap().get("file");
return ReactiveSecurityContextHolder.getContext()
.map(securityContext -> {
Object principal = securityContext.getAuthentication().getPrincipal();
if (principal instanceof Long) {
return principal.toString();
}
return "unknown";
})
.flatMap(createBy -> fileService.uploadFilePart(filePart, createBy))
.flatMap(file -> ServerResponse.status(HttpStatus.CREATED).bodyValue(file));
});
}
@GetMapping("/{id}/download")
public Mono<ResponseEntity<Resource>> downloadFile(@PathVariable Long id) {
public Mono<ServerResponse> downloadFile(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return fileService.findById(id)
.flatMap(file -> {
try {
@@ -59,22 +69,45 @@ public class SysFileHandler {
Resource resource = UrlResource.from(filePath.toUri());
if (resource.exists() && resource.isReadable()) {
return Mono.<ResponseEntity<Resource>>just(ResponseEntity.ok()
return ServerResponse.ok()
.header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"" + file.getFileName() + "\"")
.body(resource));
.bodyValue(resource);
} else {
return Mono.<ResponseEntity<Resource>>just(ResponseEntity.notFound().build());
return ServerResponse.notFound().build();
}
} catch (Exception e) {
return Mono.<ResponseEntity<Resource>>just(ResponseEntity.notFound().build());
return ServerResponse.notFound().build();
}
})
.switchIfEmpty(Mono.<ResponseEntity<Resource>>just(ResponseEntity.notFound().build()));
.switchIfEmpty(ServerResponse.notFound().build());
}
@GetMapping("/{id}/preview")
public Mono<ResponseEntity<FilePreviewResponse>> previewFile(@PathVariable Long id) {
public Mono<ServerResponse> downloadFileByName(ServerRequest request) {
String fileName = request.pathVariable("fileName");
return fileService.findByFileName(fileName)
.flatMap(file -> {
try {
Path filePath = Paths.get(file.getFilePath());
Resource resource = UrlResource.from(filePath.toUri());
if (resource.exists() && resource.isReadable()) {
return ServerResponse.ok()
.header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"" + file.getFileName() + "\"")
.bodyValue(resource);
} else {
return ServerResponse.notFound().build();
}
} catch (Exception e) {
return ServerResponse.notFound().build();
}
})
.switchIfEmpty(ServerResponse.notFound().build());
}
public Mono<ServerResponse> previewFile(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return fileService.findById(id)
.flatMap(file -> {
try {
@@ -101,17 +134,53 @@ public class SysFileHandler {
response.setPreviewData(null);
}
return Mono.<ResponseEntity<FilePreviewResponse>>just(ResponseEntity.ok(response));
return ServerResponse.ok().bodyValue(response);
} catch (IOException e) {
return Mono.<ResponseEntity<FilePreviewResponse>>just(ResponseEntity.notFound().build());
return ServerResponse.notFound().build();
}
})
.switchIfEmpty(Mono.<ResponseEntity<FilePreviewResponse>>just(ResponseEntity.notFound().build()));
.switchIfEmpty(ServerResponse.notFound().build());
}
@DeleteMapping("/{id}")
public Mono<ResponseEntity<Void>> deleteFile(@PathVariable Long id) {
public Mono<ServerResponse> previewFileByName(ServerRequest request) {
String fileName = request.pathVariable("fileName");
return fileService.findByFileName(fileName)
.flatMap(file -> {
try {
Path filePath = Paths.get(file.getFilePath());
byte[] fileBytes = Files.readAllBytes(filePath);
FilePreviewResponse response = new FilePreviewResponse();
response.setFileName(file.getFileName());
response.setFileType(file.getFileType());
response.setFileSize((long) fileBytes.length);
String fileType = file.getFileType().toLowerCase();
if (fileType.startsWith("image/")) {
response.setPreviewType("image");
response.setPreviewData(Base64.getEncoder().encodeToString(fileBytes));
} else if (fileType.equals("application/pdf")) {
response.setPreviewType("pdf");
response.setPreviewData(Base64.getEncoder().encodeToString(fileBytes));
} else if (fileType.startsWith("text/")) {
response.setPreviewType("text");
response.setPreviewData(new String(fileBytes));
} else {
response.setPreviewType("unsupported");
response.setPreviewData(null);
}
return ServerResponse.ok().bodyValue(response);
} catch (IOException e) {
return ServerResponse.notFound().build();
}
})
.switchIfEmpty(ServerResponse.notFound().build());
}
public Mono<ServerResponse> deleteFile(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return fileService.deleteById(id)
.then(Mono.just(ResponseEntity.noContent().build()));
.then(ServerResponse.noContent().build());
}
}
@@ -0,0 +1,107 @@
package cn.novalon.manage.sys.handler.log;
import cn.novalon.manage.sys.core.domain.SysLoginLog;
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;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
@Component
public class SysLogHandler {
private final ISysLoginLogService loginLogService;
private final ISysExceptionLogService exceptionLogService;
public SysLogHandler(ISysLoginLogService loginLogService, ISysExceptionLogService exceptionLogService) {
this.loginLogService = loginLogService;
this.exceptionLogService = exceptionLogService;
}
public Mono<ServerResponse> getAllLoginLogs(ServerRequest request) {
return ServerResponse.ok()
.body(loginLogService.findAll(), SysLoginLog.class);
}
public Mono<ServerResponse> getLoginLogById(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return loginLogService.findById(id)
.flatMap(log -> ServerResponse.ok().bodyValue(log))
.switchIfEmpty(ServerResponse.notFound().build());
}
public Mono<ServerResponse> createLoginLog(ServerRequest request) {
return request.bodyToMono(SysLoginLog.class)
.flatMap(loginLogService::save)
.flatMap(log -> ServerResponse.status(HttpStatus.CREATED).bodyValue(log));
}
public Mono<ServerResponse> getLoginLogsByPage(ServerRequest request) {
int page = Integer.parseInt(request.queryParam("page").orElse("0"));
int size = Integer.parseInt(request.queryParam("size").orElse("10"));
String sort = request.queryParam("sort").orElse("loginTime");
String order = request.queryParam("order").orElse("desc");
String keyword = request.queryParam("keyword").orElse(null);
PageRequest pageRequest = new PageRequest();
pageRequest.setPage(page);
pageRequest.setSize(size);
pageRequest.setSort(sort);
pageRequest.setOrder(order);
pageRequest.setKeyword(keyword);
return loginLogService.findLoginLogsByPage(pageRequest)
.flatMap(response -> ServerResponse.ok().bodyValue(response));
}
public Mono<ServerResponse> getLoginLogCount(ServerRequest request) {
return loginLogService.count()
.flatMap(count -> ServerResponse.ok().bodyValue(count));
}
public Mono<ServerResponse> getAllExceptionLogs(ServerRequest request) {
return ServerResponse.ok()
.body(exceptionLogService.findAll(), SysExceptionLog.class);
}
public Mono<ServerResponse> getExceptionLogById(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return exceptionLogService.findById(id)
.flatMap(log -> ServerResponse.ok().bodyValue(log))
.switchIfEmpty(ServerResponse.notFound().build());
}
public Mono<ServerResponse> createExceptionLog(ServerRequest request) {
return request.bodyToMono(SysExceptionLog.class)
.flatMap(exceptionLogService::save)
.flatMap(log -> ServerResponse.status(HttpStatus.CREATED).bodyValue(log));
}
public Mono<ServerResponse> getExceptionLogsByPage(ServerRequest request) {
int page = Integer.parseInt(request.queryParam("page").orElse("0"));
int size = Integer.parseInt(request.queryParam("size").orElse("10"));
String sort = request.queryParam("sort").orElse("id");
String order = request.queryParam("order").orElse("desc");
String keyword = request.queryParam("keyword").orElse(null);
PageRequest pageRequest = new PageRequest();
pageRequest.setPage(page);
pageRequest.setSize(size);
pageRequest.setSort(sort);
pageRequest.setOrder(order);
pageRequest.setKeyword(keyword);
return exceptionLogService.findExceptionLogsByPage(pageRequest)
.flatMap(response -> ServerResponse.ok().bodyValue(response));
}
public Mono<ServerResponse> getExceptionLogCount(ServerRequest request) {
return exceptionLogService.count()
.flatMap(count -> ServerResponse.ok().bodyValue(count));
}
}
@@ -0,0 +1,55 @@
package cn.novalon.manage.sys.handler.message;
import cn.novalon.manage.sys.core.domain.SysUserMessage;
import cn.novalon.manage.sys.core.service.ISysUserMessageService;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
@Component
public class SysUserMessageHandler {
private final ISysUserMessageService messageService;
public SysUserMessageHandler(ISysUserMessageService messageService) {
this.messageService = messageService;
}
public Mono<ServerResponse> getMessagesByUser(ServerRequest request) {
Long userId = Long.valueOf(request.pathVariable("userId"));
return ServerResponse.ok()
.body(messageService.findByUserId(userId), SysUserMessage.class);
}
public Mono<ServerResponse> getUnreadCount(ServerRequest request) {
Long userId = Long.valueOf(request.pathVariable("userId"));
return messageService.countUnread(userId)
.flatMap(count -> ServerResponse.ok().bodyValue(count));
}
public Mono<ServerResponse> getUnreadList(ServerRequest request) {
Long userId = Long.valueOf(request.pathVariable("userId"));
return ServerResponse.ok()
.body(messageService.findByUserIdAndIsRead(userId, "0"), SysUserMessage.class);
}
public Mono<ServerResponse> createMessage(ServerRequest request) {
return request.bodyToMono(SysUserMessage.class)
.flatMap(messageService::save)
.flatMap(message -> ServerResponse.status(HttpStatus.CREATED).bodyValue(message));
}
public Mono<ServerResponse> markAsRead(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return messageService.markAsRead(id)
.then(ServerResponse.ok().build());
}
public Mono<ServerResponse> deleteMessage(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return messageService.deleteById(id)
.then(ServerResponse.noContent().build());
}
}
@@ -3,13 +3,12 @@ package cn.novalon.manage.sys.handler.notice;
import cn.novalon.manage.sys.core.domain.SysNotice;
import cn.novalon.manage.sys.core.service.ISysNoticeService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
@RestController
@RequestMapping("/api/notices")
@Component
public class SysNoticeHandler {
private final ISysNoticeService noticeService;
@@ -18,46 +17,48 @@ public class SysNoticeHandler {
this.noticeService = noticeService;
}
@GetMapping
public Flux<SysNotice> getAllNotices() {
return noticeService.findAll();
public Mono<ServerResponse> getAllNotices(ServerRequest request) {
return ServerResponse.ok()
.body(noticeService.findAll(), SysNotice.class);
}
@GetMapping("/{id}")
public Mono<ResponseEntity<SysNotice>> getNoticeById(@PathVariable Long id) {
public Mono<ServerResponse> getNoticeById(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return noticeService.findById(id)
.map(ResponseEntity::ok)
.defaultIfEmpty(ResponseEntity.notFound().build());
.flatMap(notice -> ServerResponse.ok().bodyValue(notice))
.switchIfEmpty(ServerResponse.notFound().build());
}
@GetMapping("/status/{status}")
public Flux<SysNotice> getNoticesByStatus(@PathVariable String status) {
return noticeService.findByStatus(status);
public Mono<ServerResponse> getNoticesByStatus(ServerRequest request) {
String status = request.pathVariable("status");
return ServerResponse.ok()
.body(noticeService.findByStatus(status), SysNotice.class);
}
@PostMapping
public Mono<ResponseEntity<SysNotice>> createNotice(@RequestBody SysNotice notice) {
return noticeService.save(notice)
.map(n -> ResponseEntity.status(HttpStatus.CREATED).body(n));
public Mono<ServerResponse> createNotice(ServerRequest request) {
return request.bodyToMono(SysNotice.class)
.flatMap(noticeService::save)
.flatMap(notice -> ServerResponse.status(HttpStatus.CREATED).bodyValue(notice));
}
@PutMapping("/{id}")
public Mono<ResponseEntity<SysNotice>> updateNotice(@PathVariable Long id, @RequestBody SysNotice notice) {
return noticeService.findById(id)
.flatMap(existing -> {
existing.setNoticeTitle(notice.getNoticeTitle());
existing.setNoticeType(notice.getNoticeType());
existing.setNoticeContent(notice.getNoticeContent());
existing.setStatus(notice.getStatus());
return noticeService.save(existing);
})
.map(ResponseEntity::ok)
.defaultIfEmpty(ResponseEntity.notFound().build());
public Mono<ServerResponse> updateNotice(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return request.bodyToMono(SysNotice.class)
.flatMap(notice -> noticeService.findById(id)
.flatMap(existing -> {
existing.setNoticeTitle(notice.getNoticeTitle());
existing.setNoticeType(notice.getNoticeType());
existing.setNoticeContent(notice.getNoticeContent());
existing.setStatus(notice.getStatus());
return noticeService.save(existing);
}))
.flatMap(updatedNotice -> ServerResponse.ok().bodyValue(updatedNotice))
.switchIfEmpty(ServerResponse.notFound().build());
}
@DeleteMapping("/{id}")
public Mono<ResponseEntity<Void>> deleteNotice(@PathVariable Long id) {
public Mono<ServerResponse> deleteNotice(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return noticeService.deleteById(id)
.then(Mono.just(ResponseEntity.noContent().build()));
.then(ServerResponse.noContent().build());
}
}
@@ -0,0 +1,103 @@
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 org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
@Component
public class SysRoleHandler {
private final ISysRoleService roleService;
public SysRoleHandler(ISysRoleService roleService) {
this.roleService = roleService;
}
public Mono<ServerResponse> getAllRoles(ServerRequest request) {
return ServerResponse.ok()
.body(roleService.findAll(), SysRole.class);
}
public Mono<ServerResponse> getRolesByPage(ServerRequest request) {
int page = Integer.parseInt(request.queryParam("page").orElse("0"));
int size = Integer.parseInt(request.queryParam("size").orElse("10"));
String sort = request.queryParam("sort").orElse("id");
String order = request.queryParam("order").orElse("asc");
String keyword = request.queryParam("keyword").orElse(null);
PageRequest pageRequest = new PageRequest();
pageRequest.setPage(page);
pageRequest.setSize(size);
pageRequest.setSort(sort);
pageRequest.setOrder(order);
pageRequest.setKeyword(keyword);
return roleService.findRolesByPage(pageRequest)
.flatMap(response -> ServerResponse.ok().bodyValue(response));
}
public Mono<ServerResponse> getRoleCount(ServerRequest request) {
return roleService.count()
.flatMap(count -> ServerResponse.ok().bodyValue(count));
}
public Mono<ServerResponse> getRoleByName(ServerRequest request) {
String roleName = request.pathVariable("roleName");
return roleService.findByRoleName(roleName)
.flatMap(role -> ServerResponse.ok().bodyValue(role))
.switchIfEmpty(ServerResponse.notFound().build());
}
public Mono<ServerResponse> checkNameExists(ServerRequest request) {
String name = request.queryParam("name").orElse(null);
return roleService.existsByRoleName(name)
.flatMap(exists -> ServerResponse.ok().bodyValue(exists));
}
public Mono<ServerResponse> getRoleById(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return roleService.findById(id)
.flatMap(role -> ServerResponse.ok().bodyValue(role))
.switchIfEmpty(ServerResponse.notFound().build());
}
public Mono<ServerResponse> createRole(ServerRequest request) {
return request.bodyToMono(SysRole.class)
.flatMap(roleService::createRole)
.flatMap(role -> ServerResponse.status(HttpStatus.CREATED).bodyValue(role));
}
public Mono<ServerResponse> updateRole(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return request.bodyToMono(SysRole.class)
.flatMap(role -> roleService.findById(id)
.flatMap(existing -> {
if (role.getRoleName() != null) existing.setRoleName(role.getRoleName());
if (role.getRoleKey() != null) existing.setRoleKey(role.getRoleKey());
if (role.getRoleSort() != null) existing.setRoleSort(role.getRoleSort());
if (role.getStatus() != null) existing.setStatus(role.getStatus());
return roleService.updateRole(existing);
}))
.flatMap(updatedRole -> ServerResponse.ok().bodyValue(updatedRole))
.switchIfEmpty(ServerResponse.notFound().build());
}
public Mono<ServerResponse> deleteRole(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return roleService.logicalDeleteRole(id)
.flatMap(role -> ServerResponse.ok().bodyValue(role))
.switchIfEmpty(ServerResponse.notFound().build());
}
public Mono<ServerResponse> restoreRole(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return roleService.restoreRole(id)
.flatMap(role -> ServerResponse.ok().bodyValue(role))
.switchIfEmpty(ServerResponse.notFound().build());
}
}
@@ -0,0 +1,78 @@
package cn.novalon.manage.sys.handler.stats;
import cn.novalon.manage.sys.core.service.ISysUserService;
import cn.novalon.manage.sys.core.service.ISysRoleService;
import cn.novalon.manage.sys.core.service.IOperationLogService;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
@Component
public class StatsHandler {
private final ISysUserService userService;
private final ISysRoleService roleService;
private final IOperationLogService operationLogService;
public StatsHandler(ISysUserService userService, ISysRoleService roleService, IOperationLogService operationLogService) {
this.userService = userService;
this.roleService = roleService;
this.operationLogService = operationLogService;
}
public Mono<ServerResponse> getOverview(ServerRequest request) {
return Mono.zip(
userService.count(),
roleService.count(),
operationLogService.count(),
operationLogService.countToday()
).flatMap(tuple -> {
OverviewStats stats = new OverviewStats();
stats.setUserCount(tuple.getT1());
stats.setRoleCount(tuple.getT2());
stats.setOperationLogCount(tuple.getT3());
stats.setTodayOperationCount(tuple.getT4());
return ServerResponse.ok().bodyValue(stats);
});
}
public static class OverviewStats {
private Long userCount;
private Long roleCount;
private Long operationLogCount;
private Long todayOperationCount;
public Long getUserCount() {
return userCount;
}
public void setUserCount(Long userCount) {
this.userCount = userCount;
}
public Long getRoleCount() {
return roleCount;
}
public void setRoleCount(Long roleCount) {
this.roleCount = roleCount;
}
public Long getOperationLogCount() {
return operationLogCount;
}
public void setOperationLogCount(Long operationLogCount) {
this.operationLogCount = operationLogCount;
}
public Long getTodayOperationCount() {
return todayOperationCount;
}
public void setTodayOperationCount(Long todayOperationCount) {
this.todayOperationCount = todayOperationCount;
}
}
}
@@ -1,62 +0,0 @@
package cn.novalon.manage.sys.handler.sys;
import cn.novalon.manage.sys.core.domain.SysConfig;
import cn.novalon.manage.sys.core.service.ISysConfigService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.LocalDateTime;
@RestController
@RequestMapping("/api/config")
public class SysConfigHandler {
private final ISysConfigService configService;
public SysConfigHandler(ISysConfigService configService) {
this.configService = configService;
}
@GetMapping
public Flux<SysConfig> getAllConfigs() {
return configService.findAll();
}
@GetMapping("/{id}")
public Mono<ResponseEntity<SysConfig>> getConfigById(@PathVariable Long id) {
return configService.findById(id)
.map(config -> ResponseEntity.ok(config))
.defaultIfEmpty(ResponseEntity.notFound().build());
}
@GetMapping("/key/{configKey}")
public Mono<ResponseEntity<SysConfig>> getConfigByKey(@PathVariable String configKey) {
return configService.findByConfigKey(configKey)
.map(config -> ResponseEntity.ok(config))
.defaultIfEmpty(ResponseEntity.notFound().build());
}
@PostMapping
public Mono<ResponseEntity<SysConfig>> createConfig(@RequestBody SysConfig config) {
config.setConfigType("N");
config.setCreatedAt(LocalDateTime.now());
return configService.save(config)
.map(saved -> ResponseEntity.ok(saved));
}
@PutMapping("/{id}")
public Mono<ResponseEntity<SysConfig>> updateConfig(@PathVariable Long id, @RequestBody SysConfig config) {
config.setId(id);
config.setUpdatedAt(LocalDateTime.now());
return configService.save(config)
.map(saved -> ResponseEntity.ok(saved));
}
@DeleteMapping("/{id}")
public Mono<ResponseEntity<Void>> deleteConfig(@PathVariable Long id) {
return configService.deleteById(id)
.then(Mono.just(ResponseEntity.noContent().build()));
}
}
@@ -1,62 +0,0 @@
package cn.novalon.manage.sys.handler.sys;
import cn.novalon.manage.sys.core.domain.SysDictType;
import cn.novalon.manage.sys.core.service.ISysDictTypeService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.LocalDateTime;
@RestController
@RequestMapping("/api/dict")
public class SysDictHandler {
private final ISysDictTypeService dictTypeService;
public SysDictHandler(ISysDictTypeService dictTypeService) {
this.dictTypeService = dictTypeService;
}
@GetMapping("/types")
public Flux<SysDictType> getAllDictTypes() {
return dictTypeService.findAll();
}
@GetMapping("/types/{id}")
public Mono<ResponseEntity<SysDictType>> getDictTypeById(@PathVariable Long id) {
return dictTypeService.findById(id)
.map(dictType -> ResponseEntity.ok(dictType))
.defaultIfEmpty(ResponseEntity.notFound().build());
}
@GetMapping("/types/type/{dictType}")
public Mono<ResponseEntity<SysDictType>> getDictTypeByDictType(@PathVariable String dictType) {
return dictTypeService.findByDictType(dictType)
.map(dictTypeResult -> ResponseEntity.ok(dictTypeResult))
.defaultIfEmpty(ResponseEntity.notFound().build());
}
@PostMapping("/types")
public Mono<ResponseEntity<SysDictType>> createDictType(@RequestBody SysDictType dictType) {
dictType.setStatus("0");
dictType.setCreatedAt(LocalDateTime.now());
return dictTypeService.save(dictType)
.map(saved -> ResponseEntity.ok(saved));
}
@PutMapping("/types/{id}")
public Mono<ResponseEntity<SysDictType>> updateDictType(@PathVariable Long id, @RequestBody SysDictType dictType) {
dictType.setId(id);
dictType.setUpdatedAt(LocalDateTime.now());
return dictTypeService.save(dictType)
.map(saved -> ResponseEntity.ok(saved));
}
@DeleteMapping("/types/{id}")
public Mono<ResponseEntity<Void>> deleteDictType(@PathVariable Long id) {
return dictTypeService.deleteById(id)
.then(Mono.just(ResponseEntity.noContent().build()));
}
}
@@ -1,88 +0,0 @@
package cn.novalon.manage.sys.handler.sys;
import cn.novalon.manage.sys.core.domain.SysFile;
import cn.novalon.manage.sys.core.service.ISysFileService;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.net.MalformedURLException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@RestController
@RequestMapping("/api/files")
public class SysFileHandler {
private final ISysFileService fileService;
private final Path uploadPath = Paths.get("./uploads");
public SysFileHandler(ISysFileService fileService) {
this.fileService = fileService;
}
@GetMapping
public Flux<SysFile> getAllFiles() {
return fileService.findAll();
}
@GetMapping("/{id}")
public Mono<ResponseEntity<SysFile>> getFileById(@PathVariable Long id) {
return fileService.findById(id)
.map(file -> ResponseEntity.ok(file))
.defaultIfEmpty(ResponseEntity.notFound().build());
}
@PostMapping("/upload")
public Mono<ResponseEntity<SysFile>> uploadFile(@RequestParam("file") MultipartFile file,
@RequestParam(value = "createBy", required = false, defaultValue = "anonymous") String createBy) {
return fileService.upload(file, createBy)
.map(saved -> ResponseEntity.ok(saved));
}
@GetMapping("/download/{fileName}")
public Mono<Resource> downloadFile(@PathVariable String fileName) throws MalformedURLException {
Path filePath = uploadPath.resolve(fileName);
Resource resource = new UrlResource(filePath.toUri());
return Mono.just(resource);
}
@GetMapping("/preview/{fileName}")
public Mono<ResponseEntity<byte[]>> previewFile(@PathVariable String fileName) throws MalformedURLException {
return Mono.fromCallable(() -> {
Path filePath = uploadPath.resolve(fileName);
byte[] data = Files.readAllBytes(filePath);
return data;
}).map(data -> {
String contentType = "application/octet-stream";
try {
contentType = Files.probeContentType(uploadPath.resolve(fileName));
} catch (Exception e) {
}
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType(contentType))
.body(data);
});
}
@DeleteMapping("/{id}")
public Mono<ResponseEntity<Void>> deleteFile(@PathVariable Long id) {
return fileService.findById(id)
.flatMap(file -> {
try {
String fileName = file.getFilePath().substring(file.getFilePath().lastIndexOf("/") + 1);
Files.deleteIfExists(uploadPath.resolve(fileName));
} catch (Exception e) {
}
return fileService.deleteById(id);
})
.then(Mono.just(ResponseEntity.noContent().build()));
}
}
@@ -1,77 +0,0 @@
package cn.novalon.manage.sys.handler.sys;
import cn.novalon.manage.sys.core.domain.SysLoginLog;
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 org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.LocalDateTime;
@RestController
@RequestMapping("/api/logs")
public class SysLogHandler {
private final ISysLoginLogService loginLogService;
private final ISysExceptionLogService exceptionLogService;
public SysLogHandler(ISysLoginLogService loginLogService, ISysExceptionLogService exceptionLogService) {
this.loginLogService = loginLogService;
this.exceptionLogService = exceptionLogService;
}
@GetMapping("/login")
public Flux<SysLoginLog> getLoginLogs() {
return loginLogService.findAll();
}
@GetMapping("/login/{id}")
public Mono<ResponseEntity<SysLoginLog>> getLoginLogById(@PathVariable Long id) {
return loginLogService.findAll()
.filter(log -> log.getId().equals(id))
.next()
.map(log -> ResponseEntity.ok(log))
.defaultIfEmpty(ResponseEntity.notFound().build());
}
@PostMapping("/login")
public Mono<ResponseEntity<SysLoginLog>> createLoginLog(@RequestBody SysLoginLog log) {
log.setLoginTime(LocalDateTime.now());
return loginLogService.save(log)
.map(saved -> ResponseEntity.ok(saved));
}
@GetMapping("/login/user/{username}")
public Flux<SysLoginLog> getLoginLogsByUsername(@PathVariable String username) {
return loginLogService.findByUsername(username);
}
@GetMapping("/exception")
public Flux<SysExceptionLog> getExceptionLogs() {
return exceptionLogService.findAll();
}
@GetMapping("/exception/{id}")
public Mono<ResponseEntity<SysExceptionLog>> getExceptionLogById(@PathVariable Long id) {
return exceptionLogService.findAll()
.filter(log -> log.getId().equals(id))
.next()
.map(log -> ResponseEntity.ok(log))
.defaultIfEmpty(ResponseEntity.notFound().build());
}
@GetMapping("/exception/user/{username}")
public Flux<SysExceptionLog> getExceptionLogsByUsername(@PathVariable String username) {
return exceptionLogService.findByUsername(username);
}
@PostMapping("/exception")
public Mono<ResponseEntity<SysExceptionLog>> createExceptionLog(@RequestBody SysExceptionLog log) {
log.setCreateTime(LocalDateTime.now());
return exceptionLogService.save(log)
.map(saved -> ResponseEntity.ok(saved));
}
}
@@ -1,56 +0,0 @@
package cn.novalon.manage.sys.handler.sys;
import cn.novalon.manage.sys.core.domain.SysMenu;
import cn.novalon.manage.sys.core.service.ISysMenuService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@RestController
@RequestMapping("/api/menus")
public class SysMenuHandler {
private final ISysMenuService menuService;
public SysMenuHandler(ISysMenuService menuService) {
this.menuService = menuService;
}
@GetMapping
public Flux<SysMenu> getAllMenus() {
return menuService.findAll();
}
@GetMapping("/tree")
public Flux<SysMenu> getMenuTree() {
return menuService.buildMenuTree(menuService.findAll());
}
@GetMapping("/{id}")
public Mono<ResponseEntity<SysMenu>> getMenuById(@PathVariable Long id) {
return menuService.findById(id)
.map(ResponseEntity::ok)
.defaultIfEmpty(ResponseEntity.notFound().build());
}
@PostMapping
public Mono<ResponseEntity<SysMenu>> createMenu(@RequestBody SysMenu menu) {
return menuService.createMenu(menu)
.map(m -> ResponseEntity.status(HttpStatus.CREATED).body(m));
}
@PutMapping("/{id}")
public Mono<ResponseEntity<SysMenu>> updateMenu(@PathVariable Long id, @RequestBody SysMenu menu) {
menu.setId(id);
return menuService.updateMenu(menu)
.map(ResponseEntity::ok);
}
@DeleteMapping("/{id}")
public Mono<ResponseEntity<Void>> deleteMenu(@PathVariable Long id) {
return menuService.deleteMenu(id)
.then(Mono.just(ResponseEntity.noContent().build()));
}
}
@@ -1,47 +0,0 @@
package cn.novalon.manage.sys.handler.sys;
import cn.novalon.manage.sys.core.domain.SysUserMessage;
import cn.novalon.manage.sys.core.service.ISysUserMessageService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@RestController
@RequestMapping("/api/messages")
public class SysMessageHandler {
private final ISysUserMessageService messageService;
public SysMessageHandler(ISysUserMessageService messageService) {
this.messageService = messageService;
}
@GetMapping("/user/{userId}")
public Flux<SysUserMessage> getMessagesByUserId(@PathVariable Long userId) {
return messageService.findByUserId(userId);
}
@GetMapping("/user/{userId}/unread")
public Mono<Long> getUnreadCount(@PathVariable Long userId) {
return messageService.countUnread(userId);
}
@GetMapping("/user/{userId}/unread/list")
public Flux<SysUserMessage> getUnreadMessages(@PathVariable Long userId) {
return messageService.findByUserIdAndIsRead(userId, "0");
}
@PostMapping
public Mono<ResponseEntity<SysUserMessage>> createMessage(@RequestBody SysUserMessage message) {
message.setIsRead("0");
return messageService.save(message)
.map(saved -> ResponseEntity.ok(saved));
}
@PutMapping("/{id}/read")
public Mono<ResponseEntity<Void>> markAsRead(@PathVariable Long id) {
return messageService.markAsRead(id)
.then(Mono.just(ResponseEntity.ok().<Void>build()));
}
}
@@ -1,60 +0,0 @@
package cn.novalon.manage.sys.handler.sys;
import cn.novalon.manage.sys.core.domain.SysNotice;
import cn.novalon.manage.sys.core.service.ISysNoticeService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.LocalDateTime;
@RestController
@RequestMapping("/api/notices")
public class SysNoticeHandler {
private final ISysNoticeService noticeService;
public SysNoticeHandler(ISysNoticeService noticeService) {
this.noticeService = noticeService;
}
@GetMapping
public Flux<SysNotice> getAllNotices() {
return noticeService.findAll();
}
@GetMapping("/{id}")
public Mono<ResponseEntity<SysNotice>> getNoticeById(@PathVariable Long id) {
return noticeService.findById(id)
.map(notice -> ResponseEntity.ok(notice))
.defaultIfEmpty(ResponseEntity.notFound().build());
}
@GetMapping("/status/{status}")
public Flux<SysNotice> getNoticesByStatus(@PathVariable String status) {
return noticeService.findByStatus(status);
}
@PostMapping
public Mono<ResponseEntity<SysNotice>> createNotice(@RequestBody SysNotice notice) {
notice.setStatus("0");
notice.setCreatedAt(LocalDateTime.now());
return noticeService.save(notice)
.map(saved -> ResponseEntity.ok(saved));
}
@PutMapping("/{id}")
public Mono<ResponseEntity<SysNotice>> updateNotice(@PathVariable Long id, @RequestBody SysNotice notice) {
notice.setId(id);
notice.setUpdatedAt(LocalDateTime.now());
return noticeService.save(notice)
.map(saved -> ResponseEntity.ok(saved));
}
@DeleteMapping("/{id}")
public Mono<ResponseEntity<Void>> deleteNotice(@PathVariable Long id) {
return noticeService.deleteById(id)
.then(Mono.just(ResponseEntity.noContent().build()));
}
}
@@ -1,51 +0,0 @@
package cn.novalon.manage.sys.handler.sys;
import cn.novalon.manage.sys.core.domain.SysRole;
import cn.novalon.manage.sys.core.service.ISysRoleService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@RestController
@RequestMapping("/api/roles")
public class SysRoleHandler {
private final ISysRoleService roleService;
public SysRoleHandler(ISysRoleService roleService) {
this.roleService = roleService;
}
@GetMapping
public Flux<SysRole> getAllRoles() {
return roleService.findAll();
}
@GetMapping("/{id}")
public Mono<ResponseEntity<SysRole>> getRoleById(@PathVariable Long id) {
return roleService.findById(id)
.map(ResponseEntity::ok)
.defaultIfEmpty(ResponseEntity.notFound().build());
}
@PostMapping
public Mono<ResponseEntity<SysRole>> createRole(@RequestBody SysRole role) {
return roleService.createRole(role)
.map(r -> ResponseEntity.status(HttpStatus.CREATED).body(r));
}
@PutMapping("/{id}")
public Mono<ResponseEntity<SysRole>> updateRole(@PathVariable Long id, @RequestBody SysRole role) {
role.setId(id);
return roleService.updateRole(role)
.map(ResponseEntity::ok);
}
@DeleteMapping("/{id}")
public Mono<ResponseEntity<Void>> deleteRole(@PathVariable Long id) {
return roleService.deleteRole(id)
.then(Mono.just(ResponseEntity.noContent().build()));
}
}
@@ -2,16 +2,18 @@ package cn.novalon.manage.sys.handler.user;
import cn.novalon.manage.sys.core.domain.SysUser;
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 jakarta.validation.Valid;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
@RestController
@RequestMapping("/api/users")
import java.util.List;
@Component
public class SysUserHandler {
private final ISysUserService userService;
@@ -20,56 +22,120 @@ public class SysUserHandler {
this.userService = userService;
}
@GetMapping("/{id}")
public Mono<ResponseEntity<SysUser>> getUserById(@PathVariable Long id) {
return userService.findById(id)
.map(ResponseEntity::ok)
.defaultIfEmpty(ResponseEntity.notFound().build());
public Mono<ServerResponse> getAllUsers(ServerRequest request) {
boolean includeDeleted = Boolean.valueOf(request.queryParam("includeDeleted").orElse("false"));
return ServerResponse.ok()
.body(userService.findAll(includeDeleted), SysUser.class);
}
@GetMapping("/username/{username}")
public Mono<ResponseEntity<SysUser>> getUserByUsername(@PathVariable String username) {
public Mono<ServerResponse> getUsersByPage(ServerRequest request) {
int page = Integer.parseInt(request.queryParam("page").orElse("0"));
int size = Integer.parseInt(request.queryParam("size").orElse("10"));
String sort = request.queryParam("sort").orElse("id");
String order = request.queryParam("order").orElse("asc");
String keyword = request.queryParam("keyword").orElse(null);
PageRequest pageRequest = new PageRequest();
pageRequest.setPage(page);
pageRequest.setSize(size);
pageRequest.setSort(sort);
pageRequest.setOrder(order);
pageRequest.setKeyword(keyword);
return userService.findUsersByPage(pageRequest)
.flatMap(response -> ServerResponse.ok().bodyValue(response));
}
public Mono<ServerResponse> getUserCount(ServerRequest request) {
return userService.count()
.flatMap(count -> ServerResponse.ok().bodyValue(count));
}
public Mono<ServerResponse> getUserById(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return userService.findById(id)
.flatMap(user -> ServerResponse.ok().bodyValue(user))
.switchIfEmpty(ServerResponse.notFound().build());
}
public Mono<ServerResponse> getUserByUsername(ServerRequest request) {
String username = request.pathVariable("username");
return userService.findByUsername(username)
.map(ResponseEntity::ok)
.defaultIfEmpty(ResponseEntity.notFound().build());
.flatMap(user -> ServerResponse.ok().bodyValue(user))
.switchIfEmpty(ServerResponse.notFound().build());
}
@PostMapping
public Mono<ResponseEntity<SysUser>> createUser(@RequestBody SysUser user) {
return userService.createUser(user)
.map(u -> ResponseEntity.status(HttpStatus.CREATED).body(u));
public Mono<ServerResponse> createUser(ServerRequest request) {
return request.bodyToMono(SysUser.class)
.flatMap(userService::createUser)
.flatMap(user -> ServerResponse.status(HttpStatus.CREATED).bodyValue(user));
}
@PutMapping("/{id}")
public Mono<ResponseEntity<SysUser>> updateUser(@PathVariable Long id, @Valid @RequestBody UserUpdateRequest request) {
return userService.findById(id)
.flatMap(existing -> {
if (request.getEmail() != null) {
existing.setEmail(request.getEmail());
}
if (request.getStatus() != null) {
existing.setStatus(request.getStatus());
}
if (request.getRoleId() != null) {
existing.setRoleId(request.getRoleId());
}
return userService.updateUser(existing);
})
.map(ResponseEntity::ok)
.defaultIfEmpty(ResponseEntity.notFound().build());
public Mono<ServerResponse> updateUser(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return request.bodyToMono(UserUpdateRequest.class)
.flatMap(req -> userService.findById(id)
.flatMap(existing -> {
if (req.getEmail() != null)
existing.setEmail(req.getEmail());
if (req.getStatus() != null)
existing.setStatus(req.getStatus());
if (req.getRoleId() != null)
existing.setRoleId(req.getRoleId());
return userService.updateUser(existing);
}))
.flatMap(user -> ServerResponse.ok().bodyValue(user))
.switchIfEmpty(ServerResponse.notFound().build());
}
@DeleteMapping("/{id}")
public Mono<ResponseEntity<Void>> deleteUser(@PathVariable Long id) {
public Mono<ServerResponse> deleteUser(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return userService.deleteUser(id)
.then(Mono.just(ResponseEntity.noContent().build()));
.then(ServerResponse.noContent().build());
}
@PostMapping("/{id}/password")
public Mono<ResponseEntity<SysUser>> changePassword(
@PathVariable Long id,
@Valid @RequestBody PasswordChangeRequest request) {
return userService.changePassword(id, request.getOldPassword(), request.getNewPassword())
.map(ResponseEntity::ok);
public Mono<ServerResponse> changePassword(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return request.bodyToMono(PasswordChangeRequest.class)
.flatMap(req -> userService.changePassword(id, req.getOldPassword(), req.getNewPassword()))
.flatMap(user -> ServerResponse.ok().bodyValue(user));
}
public Mono<ServerResponse> logicalDeleteUser(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return userService.logicalDeleteUser(id)
.then(ServerResponse.noContent().build());
}
public Mono<ServerResponse> logicalDeleteUsers(ServerRequest request) {
return request.bodyToMono(new org.springframework.core.ParameterizedTypeReference<List<Long>>() {
})
.flatMap(ids -> userService.logicalDeleteUsers(ids))
.then(ServerResponse.noContent().build());
}
public Mono<ServerResponse> restoreUser(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return userService.restoreUser(id)
.then(ServerResponse.noContent().build());
}
public Mono<ServerResponse> restoreUsers(ServerRequest request) {
return request.bodyToMono(new org.springframework.core.ParameterizedTypeReference<List<Long>>() {
})
.flatMap(ids -> userService.restoreUsers(ids))
.then(ServerResponse.noContent().build());
}
public Mono<ServerResponse> checkUsernameExists(ServerRequest request) {
String username = request.queryParam("username").orElse(null);
return userService.existsByUsername(username)
.flatMap(exists -> ServerResponse.ok().bodyValue(exists));
}
public Mono<ServerResponse> checkEmailExists(ServerRequest request) {
String email = request.queryParam("email").orElse(null);
return userService.existsByEmail(email)
.flatMap(exists -> ServerResponse.ok().bodyValue(exists));
}
}
@@ -5,6 +5,9 @@ import cn.novalon.manage.sys.infrastructure.db.entity.SysConfigEntity;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.stream.Collectors;
@Component
public class SysConfigConverter {
@@ -38,4 +41,22 @@ public class SysConfigConverter {
entity.setUpdatedAt(domain.getUpdatedAt());
return entity;
}
public List<SysConfig> toDomainList(List<SysConfigEntity> entities) {
if (entities == null) {
return null;
}
return entities.stream()
.map(this::toDomain)
.collect(Collectors.toList());
}
public List<SysConfigEntity> toEntityList(List<SysConfig> domains) {
if (domains == null) {
return null;
}
return domains.stream()
.map(this::toEntity)
.collect(Collectors.toList());
}
}
@@ -5,6 +5,9 @@ import cn.novalon.manage.sys.infrastructure.db.entity.SysDictDataEntity;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.stream.Collectors;
@Component
public class SysDictDataConverter {
@@ -46,4 +49,22 @@ public class SysDictDataConverter {
entity.setUpdatedAt(domain.getUpdatedAt());
return entity;
}
public List<SysDictData> toDomainList(List<SysDictDataEntity> entities) {
if (entities == null) {
return null;
}
return entities.stream()
.map(this::toDomain)
.collect(Collectors.toList());
}
public List<SysDictDataEntity> toEntityList(List<SysDictData> domains) {
if (domains == null) {
return null;
}
return domains.stream()
.map(this::toEntity)
.collect(Collectors.toList());
}
}
@@ -5,6 +5,9 @@ import cn.novalon.manage.sys.infrastructure.db.entity.SysDictTypeEntity;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.stream.Collectors;
@Component
public class SysDictTypeConverter {
@@ -38,4 +41,22 @@ public class SysDictTypeConverter {
entity.setUpdatedAt(domain.getUpdatedAt());
return entity;
}
public List<SysDictType> toDomainList(List<SysDictTypeEntity> entities) {
if (entities == null) {
return null;
}
return entities.stream()
.map(this::toDomain)
.collect(Collectors.toList());
}
public List<SysDictTypeEntity> toEntityList(List<SysDictType> domains) {
if (domains == null) {
return null;
}
return domains.stream()
.map(this::toEntity)
.collect(Collectors.toList());
}
}
@@ -5,6 +5,9 @@ import cn.novalon.manage.sys.infrastructure.db.entity.SysExceptionLogEntity;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.stream.Collectors;
@Component
public class SysExceptionLogConverter {
@@ -44,4 +47,22 @@ public class SysExceptionLogConverter {
entity.setCreateTime(domain.getCreateTime());
return entity;
}
public List<SysExceptionLog> toDomainList(List<SysExceptionLogEntity> entities) {
if (entities == null) {
return null;
}
return entities.stream()
.map(this::toDomain)
.collect(Collectors.toList());
}
public List<SysExceptionLogEntity> toEntityList(List<SysExceptionLog> domains) {
if (domains == null) {
return null;
}
return domains.stream()
.map(this::toEntity)
.collect(Collectors.toList());
}
}
@@ -5,6 +5,9 @@ import cn.novalon.manage.sys.infrastructure.db.entity.SysFileEntity;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.stream.Collectors;
@Component
public class SysFileConverter {
@@ -40,4 +43,22 @@ public class SysFileConverter {
entity.setCreatedAt(domain.getCreatedAt());
return entity;
}
public List<SysFile> toDomainList(List<SysFileEntity> entities) {
if (entities == null) {
return null;
}
return entities.stream()
.map(this::toDomain)
.collect(Collectors.toList());
}
public List<SysFileEntity> toEntityList(List<SysFile> domains) {
if (domains == null) {
return null;
}
return domains.stream()
.map(this::toEntity)
.collect(Collectors.toList());
}
}
@@ -5,6 +5,9 @@ import cn.novalon.manage.sys.infrastructure.db.entity.SysLoginLogEntity;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.stream.Collectors;
@Component
public class SysLoginLogConverter {
@@ -42,4 +45,22 @@ public class SysLoginLogConverter {
entity.setLoginTime(domain.getLoginTime());
return entity;
}
public List<SysLoginLog> toDomainList(List<SysLoginLogEntity> entities) {
if (entities == null) {
return null;
}
return entities.stream()
.map(this::toDomain)
.collect(Collectors.toList());
}
public List<SysLoginLogEntity> toEntityList(List<SysLoginLog> domains) {
if (domains == null) {
return null;
}
return domains.stream()
.map(this::toEntity)
.collect(Collectors.toList());
}
}
@@ -5,6 +5,9 @@ import cn.novalon.manage.sys.infrastructure.db.entity.SysMenuEntity;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.stream.Collectors;
@Component
public class SysMenuConverter {
@@ -46,4 +49,22 @@ public class SysMenuConverter {
entity.setDeletedAt(domain.getDeletedAt());
return entity;
}
public List<SysMenu> toDomainList(List<SysMenuEntity> entities) {
if (entities == null) {
return null;
}
return entities.stream()
.map(this::toDomain)
.collect(Collectors.toList());
}
public List<SysMenuEntity> toEntityList(List<SysMenu> domains) {
if (domains == null) {
return null;
}
return domains.stream()
.map(this::toEntity)
.collect(Collectors.toList());
}
}
@@ -5,6 +5,9 @@ import cn.novalon.manage.sys.infrastructure.db.entity.SysNoticeEntity;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.stream.Collectors;
@Component
public class SysNoticeConverter {
@@ -38,4 +41,22 @@ public class SysNoticeConverter {
entity.setUpdatedAt(domain.getUpdatedAt());
return entity;
}
public List<SysNotice> toDomainList(List<SysNoticeEntity> entities) {
if (entities == null) {
return null;
}
return entities.stream()
.map(this::toDomain)
.collect(Collectors.toList());
}
public List<SysNoticeEntity> toEntityList(List<SysNotice> domains) {
if (domains == null) {
return null;
}
return domains.stream()
.map(this::toEntity)
.collect(Collectors.toList());
}
}
@@ -5,6 +5,9 @@ import cn.novalon.manage.sys.infrastructure.db.entity.SysRoleEntity;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.stream.Collectors;
@Component
public class SysRoleConverter {
@@ -40,4 +43,22 @@ public class SysRoleConverter {
entity.setDeletedAt(domain.getDeletedAt());
return entity;
}
public List<SysRole> toDomainList(List<SysRoleEntity> entities) {
if (entities == null) {
return null;
}
return entities.stream()
.map(this::toDomain)
.collect(Collectors.toList());
}
public List<SysRoleEntity> toEntityList(List<SysRole> domains) {
if (domains == null) {
return null;
}
return domains.stream()
.map(this::toEntity)
.collect(Collectors.toList());
}
}
@@ -5,6 +5,9 @@ import cn.novalon.manage.sys.infrastructure.db.entity.SysUserMessageEntity;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.stream.Collectors;
@Component
public class SysUserMessageConverter {
@@ -38,4 +41,22 @@ public class SysUserMessageConverter {
entity.setCreateTime(domain.getCreateTime());
return entity;
}
public List<SysUserMessage> toDomainList(List<SysUserMessageEntity> entities) {
if (entities == null) {
return null;
}
return entities.stream()
.map(this::toDomain)
.collect(Collectors.toList());
}
public List<SysUserMessageEntity> toEntityList(List<SysUserMessage> domains) {
if (domains == null) {
return null;
}
return domains.stream()
.map(this::toEntity)
.collect(Collectors.toList());
}
}
@@ -0,0 +1,115 @@
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.Table;
import java.time.LocalDateTime;
@Table("sys_dictionary")
public class DictionaryEntity {
@Id
private Long id;
private String type;
private String code;
private String name;
private String value;
private String remark;
private Integer sort;
private String createBy;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
private LocalDateTime deletedAt;
public DictionaryEntity() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
public Integer getSort() {
return sort;
}
public void setSort(Integer sort) {
this.sort = sort;
}
public String getCreateBy() {
return createBy;
}
public void setCreateBy(String createBy) {
this.createBy = createBy;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
public void setCreatedAt(LocalDateTime createdAt) {
this.createdAt = createdAt;
}
public LocalDateTime getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(LocalDateTime updatedAt) {
this.updatedAt = updatedAt;
}
public LocalDateTime getDeletedAt() {
return deletedAt;
}
public void setDeletedAt(LocalDateTime deletedAt) {
this.deletedAt = deletedAt;
}
}
@@ -24,12 +24,6 @@ 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;
@@ -79,22 +73,6 @@ public class SysConfigEntity {
this.configType = configType;
}
public String getCreateBy() {
return createBy;
}
public void setCreateBy(String createBy) {
this.createBy = createBy;
}
public String getUpdateBy() {
return updateBy;
}
public void setUpdateBy(String updateBy) {
this.updateBy = updateBy;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
@@ -36,12 +36,6 @@ 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;
@@ -123,22 +117,6 @@ public class SysDictDataEntity {
this.status = status;
}
public String getCreateBy() {
return createBy;
}
public void setCreateBy(String createBy) {
this.createBy = createBy;
}
public String getUpdateBy() {
return updateBy;
}
public void setUpdateBy(String updateBy) {
this.updateBy = updateBy;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
@@ -24,12 +24,6 @@ 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;
@@ -79,22 +73,6 @@ 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;
}
@@ -24,12 +24,6 @@ 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;
@@ -79,22 +73,6 @@ 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;
}
@@ -0,0 +1,60 @@
package cn.novalon.manage.sys.infrastructure.db.entity.query;
import cn.novalon.manage.sys.core.domain.query.SysMenuQuery;
import cn.novalon.manage.sys.infrastructure.db.utils.QueryField;
/**
* @author zhangxiang
* @version 1.0
* @description 菜单查询条件对象
* @date 2026/03/11
**/
public class SysMenuQueryCriteria {
@QueryField(propName = "menuName", type = QueryField.Type.INNER_LIKE)
private String menuName;
@QueryField(propName = "menuType", type = QueryField.Type.EQUAL)
private String menuType;
@QueryField(propName = "status", type = QueryField.Type.EQUAL)
private String status;
public String getMenuName() {
return menuName;
}
public void setMenuName(String menuName) {
this.menuName = menuName;
}
public String getMenuType() {
return menuType;
}
public void setMenuType(String menuType) {
this.menuType = menuType;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
/**
* 从领域查询对象转换
*
* @param query 领域查询对象
*/
public void convert(SysMenuQuery query) {
if (query == null) {
return;
}
this.menuName = query.getMenuName();
this.menuType = query.getMenuType();
this.status = query.getStatus();
}
}
@@ -0,0 +1,60 @@
package cn.novalon.manage.sys.infrastructure.db.entity.query;
import cn.novalon.manage.sys.core.domain.query.SysRoleQuery;
import cn.novalon.manage.sys.infrastructure.db.utils.QueryField;
/**
* @author zhangxiang
* @version 1.0
* @description 角色查询条件对象
* @date 2026/03/11
**/
public class SysRoleQueryCriteria {
@QueryField(propName = "roleName", type = QueryField.Type.INNER_LIKE)
private String roleName;
@QueryField(propName = "roleKey", type = QueryField.Type.INNER_LIKE)
private String roleKey;
@QueryField(propName = "status", type = QueryField.Type.EQUAL)
private Integer status;
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public String getRoleKey() {
return roleKey;
}
public void setRoleKey(String roleKey) {
this.roleKey = roleKey;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
/**
* 从领域查询对象转换
*
* @param query 领域查询对象
*/
public void convert(SysRoleQuery query) {
if (query == null) {
return;
}
this.roleName = query.getRoleName();
this.roleKey = query.getRoleKey();
this.status = query.getStatus();
}
}
@@ -0,0 +1,72 @@
package cn.novalon.manage.sys.infrastructure.db.entity.query;
import cn.novalon.manage.sys.core.domain.query.SysUserQuery;
import cn.novalon.manage.sys.infrastructure.db.utils.QueryField;
/**
* @author zhangxiang
* @version 1.0
* @description 用户查询条件对象
* @date 2026/03/11
**/
public class SysUserQueryCriteria {
@QueryField(propName = "username", type = QueryField.Type.INNER_LIKE)
private String username;
@QueryField(propName = "email", type = QueryField.Type.INNER_LIKE)
private String email;
@QueryField(propName = "roleId", type = QueryField.Type.EQUAL)
private Long roleId;
@QueryField(propName = "status", type = QueryField.Type.EQUAL)
private Integer status;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Long getRoleId() {
return roleId;
}
public void setRoleId(Long roleId) {
this.roleId = roleId;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
/**
* 从领域查询对象转换
*
* @param query 领域查询对象
*/
public void convert(SysUserQuery query) {
if (query == null) {
return;
}
this.username = query.getUsername();
this.email = query.getEmail();
this.roleId = query.getRoleId();
this.status = query.getStatus();
}
}
@@ -0,0 +1,23 @@
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);
List<Dictionary> toDomainList(List<DictionaryEntity> entities);
List<DictionaryEntity> toEntityList(List<Dictionary> domains);
}
@@ -0,0 +1,22 @@
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);
List<OperationLog> toDomainList(List<OperationLogEntity> entities);
List<OperationLogEntity> toEntityList(List<OperationLog> domains);
}
@@ -0,0 +1,22 @@
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);
List<SysConfig> toDomainList(List<SysConfigEntity> entities);
List<SysConfigEntity> toEntityList(List<SysConfig> domains);
}
@@ -0,0 +1,22 @@
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);
List<SysDictData> toDomainList(List<SysDictDataEntity> entities);
List<SysDictDataEntity> toEntityList(List<SysDictData> domains);
}
@@ -0,0 +1,22 @@
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);
List<SysDictType> toDomainList(List<SysDictTypeEntity> entities);
List<SysDictTypeEntity> toEntityList(List<SysDictType> domains);
}
@@ -0,0 +1,22 @@
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);
List<SysExceptionLog> toDomainList(List<SysExceptionLogEntity> entities);
List<SysExceptionLogEntity> toEntityList(List<SysExceptionLog> domains);
}
@@ -0,0 +1,22 @@
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);
List<SysFile> toDomainList(List<SysFileEntity> entities);
List<SysFileEntity> toEntityList(List<SysFile> domains);
}
@@ -0,0 +1,22 @@
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);
List<SysLoginLog> toDomainList(List<SysLoginLogEntity> entities);
List<SysLoginLogEntity> toEntityList(List<SysLoginLog> domains);
}
@@ -0,0 +1,22 @@
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 java.util.List;
@Mapper(componentModel = "spring")
public interface SysMenuMapper {
SysMenuMapper INSTANCE = Mappers.getMapper(SysMenuMapper.class);
SysMenu toDomain(SysMenuEntity entity);
SysMenuEntity toEntity(SysMenu domain);
List<SysMenu> toDomainList(List<SysMenuEntity> entities);
List<SysMenuEntity> toEntityList(List<SysMenu> domains);
}
@@ -0,0 +1,22 @@
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);
List<SysNotice> toDomainList(List<SysNoticeEntity> entities);
List<SysNoticeEntity> toEntityList(List<SysNotice> domains);
}
@@ -0,0 +1,22 @@
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);
List<SysRole> toDomainList(List<SysRoleEntity> entities);
List<SysRoleEntity> toEntityList(List<SysRole> domains);
}
@@ -0,0 +1,22 @@
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);
List<SysUser> toDomainList(List<SysUserEntity> entities);
List<SysUserEntity> toEntityList(List<SysUser> domains);
}
@@ -0,0 +1,22 @@
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);
List<SysUserMessage> toDomainList(List<SysUserMessageEntity> entities);
List<SysUserMessageEntity> toEntityList(List<SysUserMessage> domains);
}
@@ -1,8 +1,8 @@
package cn.novalon.manage.sys.infrastructure.db.repository;
import cn.novalon.manage.sys.core.domain.Dictionary;
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.mapper.DictionaryMapper;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@@ -11,36 +11,36 @@ import reactor.core.publisher.Mono;
public class DictionaryRepository {
private final DictionaryDao dao;
private final DictionaryConverter converter;
private final DictionaryMapper mapper;
public DictionaryRepository(DictionaryDao dao, DictionaryConverter converter) {
public DictionaryRepository(DictionaryDao dao, DictionaryMapper mapper) {
this.dao = dao;
this.converter = converter;
this.mapper = mapper;
}
public Flux<Dictionary> findByType(String type) {
return dao.findByType(type)
.map(converter::toDomain);
.map(mapper::toDomain);
}
public Mono<Dictionary> findByTypeAndCode(String type, String code) {
return dao.findByTypeAndCode(type, code)
.map(converter::toDomain);
.map(mapper::toDomain);
}
public Flux<Dictionary> findAll() {
return dao.findByDeletedAtIsNullOrderBySortAsc()
.map(converter::toDomain);
.map(mapper::toDomain);
}
public Mono<Dictionary> findById(Long id) {
return dao.findById(id)
.map(converter::toDomain);
.map(mapper::toDomain);
}
public Mono<Dictionary> save(Dictionary dictionary) {
return dao.save(converter.toEntity(dictionary))
.map(converter::toDomain);
return dao.save(mapper.toEntity(dictionary))
.map(mapper::toDomain);
}
public Mono<Void> deleteById(Long id) {
@@ -1,7 +1,7 @@
package cn.novalon.manage.sys.infrastructure.db.repository;
import cn.novalon.manage.sys.core.domain.SysConfig;
import cn.novalon.manage.sys.infrastructure.db.converter.SysConfigConverter;
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;
@@ -15,27 +15,27 @@ import java.time.LocalDateTime;
public class SysConfigRepository {
private final SysConfigDao dao;
private final SysConfigConverter converter;
private final SysConfigMapper mapper;
public SysConfigRepository(SysConfigDao dao, SysConfigConverter converter) {
public SysConfigRepository(SysConfigDao dao, SysConfigMapper mapper) {
this.dao = dao;
this.converter = converter;
this.mapper = mapper;
}
public Mono<SysConfig> findByConfigKey(String configKey) {
return dao.findByConfigKeyAndDeletedAtIsNull(configKey)
.map(converter::toDomain);
.map(mapper::toDomain);
}
public Mono<SysConfig> findById(Long id) {
return dao.findById(id)
.filter(entity -> entity.getDeletedAt() == null)
.map(converter::toDomain);
.map(mapper::toDomain);
}
public Mono<SysConfig> save(SysConfig sysConfig) {
return dao.save(converter.toEntity(sysConfig))
.map(converter::toDomain);
return dao.save(mapper.toEntity(sysConfig))
.map(mapper::toDomain);
}
public Mono<Void> deleteById(Long id) {
@@ -49,12 +49,12 @@ public class SysConfigRepository {
public Flux<SysConfig> findAll() {
return dao.findByDeletedAtIsNull()
.map(converter::toDomain);
.map(mapper::toDomain);
}
public Flux<SysConfig> findAll(Sort sort) {
return dao.findByDeletedAtIsNull(sort)
.map(converter::toDomain);
.map(mapper::toDomain);
}
public Mono<Long> count() {
@@ -1,7 +1,7 @@
package cn.novalon.manage.sys.infrastructure.db.repository;
import cn.novalon.manage.sys.core.domain.SysFile;
import cn.novalon.manage.sys.infrastructure.db.converter.SysFileConverter;
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;
@@ -15,22 +15,22 @@ import java.time.LocalDateTime;
public class SysFileRepository {
private final SysFileDao dao;
private final SysFileConverter converter;
private final SysFileMapper mapper;
public SysFileRepository(SysFileDao dao, SysFileConverter converter) {
public SysFileRepository(SysFileDao dao, SysFileMapper mapper) {
this.dao = dao;
this.converter = converter;
this.mapper = mapper;
}
public Mono<SysFile> findById(Long id) {
return dao.findById(id)
.filter(entity -> entity.getDeletedAt() == null)
.map(converter::toDomain);
.map(mapper::toDomain);
}
public Mono<SysFile> save(SysFile sysFile) {
return dao.save(converter.toEntity(sysFile))
.map(converter::toDomain);
return dao.save(mapper.toEntity(sysFile))
.map(mapper::toDomain);
}
public Mono<Void> deleteById(Long id) {
@@ -44,32 +44,32 @@ public class SysFileRepository {
public Flux<SysFile> findByCreateBy(String createBy) {
return dao.findByCreateBy(createBy)
.map(converter::toDomain);
.map(mapper::toDomain);
}
public Flux<SysFile> findByCreateBy(String createBy, Sort sort) {
return dao.findByCreateBy(createBy, sort)
.map(converter::toDomain);
.map(mapper::toDomain);
}
public Flux<SysFile> findByCreateByOrderByCreatedAtDesc(String createBy) {
return dao.findByCreateByOrderByCreatedAtDesc(createBy)
.map(converter::toDomain);
.map(mapper::toDomain);
}
public Flux<SysFile> findAll() {
return dao.findByDeletedAtIsNull()
.map(converter::toDomain);
.map(mapper::toDomain);
}
public Flux<SysFile> findAll(Sort sort) {
return dao.findByDeletedAtIsNull(sort)
.map(converter::toDomain);
.map(mapper::toDomain);
}
public Flux<SysFile> findAllByOrderByCreatedAtDesc() {
return dao.findByDeletedAtIsNullOrderByCreatedAtDesc()
.map(converter::toDomain);
.map(mapper::toDomain);
}
public Mono<Long> count() {
@@ -1,7 +1,7 @@
package cn.novalon.manage.sys.infrastructure.db.repository;
import cn.novalon.manage.sys.core.domain.SysNotice;
import cn.novalon.manage.sys.infrastructure.db.converter.SysNoticeConverter;
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;
@@ -15,22 +15,22 @@ import java.time.LocalDateTime;
public class SysNoticeRepository {
private final SysNoticeDao dao;
private final SysNoticeConverter converter;
private final SysNoticeMapper mapper;
public SysNoticeRepository(SysNoticeDao dao, SysNoticeConverter converter) {
public SysNoticeRepository(SysNoticeDao dao, SysNoticeMapper mapper) {
this.dao = dao;
this.converter = converter;
this.mapper = mapper;
}
public Mono<SysNotice> findById(Long id) {
return dao.findById(id)
.filter(entity -> entity.getDeletedAt() == null)
.map(converter::toDomain);
.map(mapper::toDomain);
}
public Mono<SysNotice> save(SysNotice sysNotice) {
return dao.save(converter.toEntity(sysNotice))
.map(converter::toDomain);
return dao.save(mapper.toEntity(sysNotice))
.map(mapper::toDomain);
}
public Mono<Void> deleteById(Long id) {
@@ -44,22 +44,22 @@ public class SysNoticeRepository {
public Flux<SysNotice> findByStatus(String status) {
return dao.findByStatusAndDeletedAtIsNull(status)
.map(converter::toDomain);
.map(mapper::toDomain);
}
public Flux<SysNotice> findByStatus(String status, Sort sort) {
return dao.findByStatusAndDeletedAtIsNull(status, sort)
.map(converter::toDomain);
.map(mapper::toDomain);
}
public Flux<SysNotice> findAll() {
return dao.findByDeletedAtIsNull()
.map(converter::toDomain);
.map(mapper::toDomain);
}
public Flux<SysNotice> findAll(Sort sort) {
return dao.findByDeletedAtIsNull(sort)
.map(converter::toDomain);
.map(mapper::toDomain);
}
public Mono<Long> count() {

Some files were not shown because too many files have changed in this diff Show More