refactor: migrate SysFile to manage-file module

This commit is contained in:
张翔
2026-03-14 10:33:35 +08:00
parent 4db2019d95
commit 2dd239a142
8 changed files with 12 additions and 331 deletions
+5
View File
@@ -27,6 +27,11 @@
<artifactId>manage-notify</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>cn.novalon.manage</groupId>
<artifactId>manage-file</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>cn.novalon.manage</groupId>
<artifactId>manage-common</artifactId>
@@ -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;
@@ -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;
@@ -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;
@@ -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<SysFile> findByDeletedAtIsNullOrderByCreatedAtDesc();
@@ -23,4 +17,4 @@ public interface ISysFileRepository {
Mono<SysFile> save(SysFile sysFile);
Mono<Void> deleteByIdAndDeletedAtIsNull(Long id);
}
}
@@ -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<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,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<SysFile> findAll() {
return repository.findByDeletedAtIsNullOrderByCreatedAtDesc();
}
@Override
public Flux<SysFile> findByCreateBy(String createBy) {
return repository.findByCreateByOrderByCreatedAtDesc(createBy);
}
@Override
public Mono<SysFile> findById(Long id) {
return repository.findById(id);
}
@Override
public Mono<SysFile> findByFileName(String fileName) {
return repository.findByFilePathContaining(fileName)
.next();
}
@Override
public Mono<SysFile> 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<Void> deleteById(Long id) {
return repository.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 -> repository.save(sysFile));
} catch (Exception e) {
return Mono.error(new RuntimeException("文件上传失败: " + e.getMessage()));
}
}
}
@@ -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<ServerResponse> getAllFiles(ServerRequest request) {
return ServerResponse.ok()
.body(fileService.findAll(), SysFile.class);
}
public Mono<ServerResponse> 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<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));
});
}
public Mono<ServerResponse> 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<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 {
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<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, 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<ServerResponse> deleteFile(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return fileService.deleteById(id)
.then(ServerResponse.noContent().build());
}
}