diff --git a/novalon-manage-api/manage-db/pom.xml b/novalon-manage-api/manage-db/pom.xml
index ed373d7..5201eb7 100644
--- a/novalon-manage-api/manage-db/pom.xml
+++ b/novalon-manage-api/manage-db/pom.xml
@@ -27,6 +27,11 @@
manage-notify
${project.version}
+
+ cn.novalon.manage
+ manage-file
+ ${project.version}
+
cn.novalon.manage
manage-common
diff --git a/novalon-manage-api/manage-db/src/main/java/cn/novalon/manage/db/converter/SysFileConverter.java b/novalon-manage-api/manage-db/src/main/java/cn/novalon/manage/db/converter/SysFileConverter.java
index d1349fa..d26e901 100644
--- a/novalon-manage-api/manage-db/src/main/java/cn/novalon/manage/db/converter/SysFileConverter.java
+++ b/novalon-manage-api/manage-db/src/main/java/cn/novalon/manage/db/converter/SysFileConverter.java
@@ -1,6 +1,6 @@
package cn.novalon.manage.db.converter;
-import cn.novalon.manage.sys.core.domain.SysFile;
+import cn.novalon.manage.file.core.domain.SysFile;
import cn.novalon.manage.db.entity.SysFileEntity;
import org.springframework.stereotype.Component;
diff --git a/novalon-manage-api/manage-db/src/main/java/cn/novalon/manage/db/repository/SysFileRepository.java b/novalon-manage-api/manage-db/src/main/java/cn/novalon/manage/db/repository/SysFileRepository.java
index eb98207..ba37b82 100644
--- a/novalon-manage-api/manage-db/src/main/java/cn/novalon/manage/db/repository/SysFileRepository.java
+++ b/novalon-manage-api/manage-db/src/main/java/cn/novalon/manage/db/repository/SysFileRepository.java
@@ -1,7 +1,7 @@
package cn.novalon.manage.db.repository;
-import cn.novalon.manage.sys.core.domain.SysFile;
-import cn.novalon.manage.sys.core.repository.ISysFileRepository;
+import cn.novalon.manage.file.core.domain.SysFile;
+import cn.novalon.manage.file.core.repository.ISysFileRepository;
import cn.novalon.manage.db.converter.SysFileConverter;
import cn.novalon.manage.db.dao.SysFileDao;
import cn.novalon.manage.db.entity.SysFileEntity;
diff --git a/novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/domain/SysFile.java b/novalon-manage-api/manage-file/src/main/java/cn/novalon/manage/file/core/domain/SysFile.java
similarity index 93%
rename from novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/domain/SysFile.java
rename to novalon-manage-api/manage-file/src/main/java/cn/novalon/manage/file/core/domain/SysFile.java
index 59dcb49..3c7d0fc 100644
--- a/novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/domain/SysFile.java
+++ b/novalon-manage-api/manage-file/src/main/java/cn/novalon/manage/file/core/domain/SysFile.java
@@ -1,13 +1,7 @@
-package cn.novalon.manage.sys.core.domain;
+package cn.novalon.manage.file.core.domain;
import java.time.LocalDateTime;
-/**
- * 文件管理领域对象
- *
- * @author 张翔
- * @date 2026-03-13
- */
public class SysFile {
private Long id;
diff --git a/novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/repository/ISysFileRepository.java b/novalon-manage-api/manage-file/src/main/java/cn/novalon/manage/file/core/repository/ISysFileRepository.java
similarity index 72%
rename from novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/repository/ISysFileRepository.java
rename to novalon-manage-api/manage-file/src/main/java/cn/novalon/manage/file/core/repository/ISysFileRepository.java
index 41f9a86..592b725 100644
--- a/novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/repository/ISysFileRepository.java
+++ b/novalon-manage-api/manage-file/src/main/java/cn/novalon/manage/file/core/repository/ISysFileRepository.java
@@ -1,15 +1,9 @@
-package cn.novalon.manage.sys.core.repository;
+package cn.novalon.manage.file.core.repository;
-import cn.novalon.manage.sys.core.domain.SysFile;
+import cn.novalon.manage.file.core.domain.SysFile;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
-/**
- * 文件仓储接口
- *
- * @author 张翔
- * @date 2026-03-13
- */
public interface ISysFileRepository {
Flux findByDeletedAtIsNullOrderByCreatedAtDesc();
@@ -23,4 +17,4 @@ public interface ISysFileRepository {
Mono save(SysFile sysFile);
Mono deleteByIdAndDeletedAtIsNull(Long id);
-}
\ No newline at end of file
+}
diff --git a/novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/service/ISysFileService.java b/novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/service/ISysFileService.java
deleted file mode 100644
index 05c69e5..0000000
--- a/novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/service/ISysFileService.java
+++ /dev/null
@@ -1,23 +0,0 @@
-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;
-
-/**
- * 文件服务接口
- *
- * @author 张翔
- * @date 2026-03-13
- */
-public interface ISysFileService {
- Flux findAll();
- Flux findByCreateBy(String createBy);
- Mono findById(Long id);
- Mono findByFileName(String fileName);
- Mono upload(MultipartFile file, String createBy);
- Mono uploadFilePart(FilePart filePart, String createBy);
- Mono deleteById(Long id);
-}
diff --git a/novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/service/impl/SysFileService.java b/novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/service/impl/SysFileService.java
deleted file mode 100644
index 09ca152..0000000
--- a/novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/service/impl/SysFileService.java
+++ /dev/null
@@ -1,105 +0,0 @@
-package cn.novalon.manage.sys.core.service.impl;
-
-import cn.novalon.manage.sys.core.domain.SysFile;
-import cn.novalon.manage.sys.core.repository.ISysFileRepository;
-import cn.novalon.manage.sys.core.service.ISysFileService;
-import org.springframework.http.codec.multipart.FilePart;
-import org.springframework.stereotype.Service;
-import org.springframework.web.multipart.MultipartFile;
-import reactor.core.publisher.Flux;
-import reactor.core.publisher.Mono;
-
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.time.LocalDateTime;
-import java.util.UUID;
-
-@Service
-public class SysFileService implements ISysFileService {
-
- private final ISysFileRepository repository;
- private final Path uploadPath = Paths.get("./uploads");
-
- public SysFileService(ISysFileRepository repository) {
- this.repository = repository;
- }
-
- @Override
- public Flux findAll() {
- return repository.findByDeletedAtIsNullOrderByCreatedAtDesc();
- }
-
- @Override
- public Flux findByCreateBy(String createBy) {
- return repository.findByCreateByOrderByCreatedAtDesc(createBy);
- }
-
- @Override
- public Mono findById(Long id) {
- return repository.findById(id);
- }
-
- @Override
- public Mono findByFileName(String fileName) {
- return repository.findByFilePathContaining(fileName)
- .next();
- }
-
- @Override
- public Mono upload(MultipartFile file, String createBy) {
- try {
- if (!Files.exists(uploadPath)) {
- Files.createDirectories(uploadPath);
- }
- String fileName = UUID.randomUUID() + "_" + file.getOriginalFilename();
- Path filePath = uploadPath.resolve(fileName);
- Files.copy(file.getInputStream(), filePath);
-
- SysFile sysFile = new SysFile();
- sysFile.setFileName(file.getOriginalFilename());
- sysFile.setFilePath(filePath.toString());
- sysFile.setFileSize(String.valueOf(file.getSize()));
- sysFile.setFileType(file.getContentType());
- sysFile.setStorageType("local");
- sysFile.setCreateBy(createBy);
- sysFile.setCreatedAt(LocalDateTime.now());
-
- return repository.save(sysFile);
- } catch (Exception e) {
- return Mono.error(new RuntimeException("文件上传失败: " + e.getMessage()));
- }
- }
-
- @Override
- public Mono deleteById(Long id) {
- return repository.deleteByIdAndDeletedAtIsNull(id);
- }
-
- @Override
- public Mono 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 -> repository.save(sysFile));
- } catch (Exception e) {
- return Mono.error(new RuntimeException("文件上传失败: " + e.getMessage()));
- }
- }
-}
diff --git a/novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/handler/file/SysFileHandler.java b/novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/handler/file/SysFileHandler.java
deleted file mode 100644
index 630ed1b..0000000
--- a/novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/handler/file/SysFileHandler.java
+++ /dev/null
@@ -1,184 +0,0 @@
-package cn.novalon.manage.sys.handler.file;
-
-import cn.novalon.manage.sys.core.domain.SysFile;
-import cn.novalon.manage.sys.core.service.ISysFileService;
-import cn.novalon.manage.sys.dto.response.FilePreviewResponse;
-import org.springframework.core.io.Resource;
-import org.springframework.core.io.UrlResource;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.codec.multipart.FilePart;
-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;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.Base64;
-
-@Component
-public class SysFileHandler {
-
- private final ISysFileService fileService;
-
- public SysFileHandler(ISysFileService fileService) {
- this.fileService = fileService;
- }
-
- public Mono getAllFiles(ServerRequest request) {
- return ServerResponse.ok()
- .body(fileService.findAll(), SysFile.class);
- }
-
- public Mono getFileById(ServerRequest request) {
- Long id = Long.valueOf(request.pathVariable("id"));
- return fileService.findById(id)
- .flatMap(file -> ServerResponse.ok().bodyValue(file))
- .switchIfEmpty(ServerResponse.notFound().build());
- }
-
- public Mono 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));
- });
- }
-
- public Mono downloadFile(ServerRequest request) {
- Long id = Long.valueOf(request.pathVariable("id"));
- return fileService.findById(id)
- .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 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 previewFile(ServerRequest request) {
- Long id = Long.valueOf(request.pathVariable("id"));
- return fileService.findById(id)
- .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, java.nio.charset.StandardCharsets.UTF_8));
- } 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 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, java.nio.charset.StandardCharsets.UTF_8));
- } 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 deleteFile(ServerRequest request) {
- Long id = Long.valueOf(request.pathVariable("id"));
- return fileService.deleteById(id)
- .then(ServerResponse.noContent().build());
- }
-}