feat: implement file service and handler in manage-file module

This commit is contained in:
张翔
2026-03-14 11:34:27 +08:00
parent 08cd057124
commit 2d14b47bcf
4 changed files with 278 additions and 0 deletions
+4
View File
@@ -26,6 +26,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
@@ -0,0 +1,21 @@
package cn.novalon.manage.file.core.service;
import cn.novalon.manage.file.core.domain.SysFile;
import org.springframework.http.codec.multipart.FilePart;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
public interface ISysFileService {
Flux<SysFile> getAllFiles();
Mono<SysFile> getFileById(Long id);
Flux<SysFile> getFilesByUser(String username);
Mono<SysFile> uploadFile(FilePart filePart, String username);
Mono<Void> downloadFile(Long id);
Mono<Void> deleteFile(Long id);
}
@@ -0,0 +1,111 @@
package cn.novalon.manage.file.core.service.impl;
import cn.novalon.manage.file.core.domain.SysFile;
import cn.novalon.manage.file.core.repository.ISysFileRepository;
import cn.novalon.manage.file.core.service.ISysFileService;
import org.springframework.http.codec.multipart.FilePart;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
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.time.LocalDateTime;
import java.util.UUID;
@Service
public class SysFileServiceImpl implements ISysFileService {
private final ISysFileRepository fileRepository;
private final String uploadDir = "/app/uploads";
public SysFileServiceImpl(ISysFileRepository fileRepository) {
this.fileRepository = fileRepository;
}
@Override
public Flux<SysFile> getAllFiles() {
return fileRepository.findByDeletedAtIsNullOrderByCreatedAtDesc();
}
@Override
public Mono<SysFile> getFileById(Long id) {
return fileRepository.findById(id);
}
@Override
public Flux<SysFile> getFilesByUser(String username) {
return fileRepository.findByCreateByOrderByCreatedAtDesc(username);
}
@Override
public Mono<SysFile> uploadFile(FilePart filePart, String username) {
String originalFilename = filePart.filename();
String fileExtension = originalFilename.substring(originalFilename.lastIndexOf("."));
String newFileName = UUID.randomUUID().toString() + fileExtension;
Path uploadPath = Paths.get(uploadDir);
return Mono.fromCallable(() -> {
if (!Files.exists(uploadPath)) {
Files.createDirectories(uploadPath);
}
return uploadPath;
})
.flatMap(path -> {
Path filePath = path.resolve(newFileName);
return filePart.transferTo(filePath.toFile())
.thenReturn(filePath);
})
.flatMap(filePath -> {
try {
long fileSize = Files.size(filePath);
String contentType = filePart.headers().getContentType() != null
? filePart.headers().getContentType().toString()
: "application/octet-stream";
SysFile sysFile = new SysFile();
sysFile.setFileName(originalFilename);
sysFile.setFilePath(filePath.toString());
sysFile.setFileSize(String.valueOf(fileSize));
sysFile.setFileType(contentType);
sysFile.setStorageType("LOCAL");
sysFile.setCreateBy(username);
sysFile.setCreatedAt(LocalDateTime.now());
return fileRepository.save(sysFile);
} catch (IOException e) {
return Mono.error(e);
}
});
}
@Override
public Mono<Void> downloadFile(Long id) {
return fileRepository.findById(id)
.flatMap(file -> {
try {
Path filePath = Paths.get(file.getFilePath());
byte[] fileContent = Files.readAllBytes(filePath);
return Mono.empty();
} catch (IOException e) {
return Mono.error(e);
}
});
}
@Override
public Mono<Void> deleteFile(Long id) {
return fileRepository.findById(id)
.flatMap(file -> {
try {
Path filePath = Paths.get(file.getFilePath());
Files.deleteIfExists(filePath);
return fileRepository.deleteByIdAndDeletedAtIsNull(id);
} catch (IOException e) {
return Mono.error(e);
}
});
}
}
@@ -0,0 +1,142 @@
package cn.novalon.manage.file.handler;
import cn.novalon.manage.file.core.domain.SysFile;
import cn.novalon.manage.file.core.service.ISysFileService;
import org.springframework.http.codec.multipart.FilePart;
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.Flux;
import reactor.core.publisher.Mono;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@Component
public class SysFileHandler {
private final ISysFileService fileService;
public SysFileHandler(ISysFileService fileService) {
this.fileService = fileService;
}
public Mono<ServerResponse> getAllFiles(ServerRequest request) {
Flux<SysFile> files = fileService.getAllFiles();
return ServerResponse.ok().body(files, SysFile.class);
}
public Mono<ServerResponse> getFileById(ServerRequest request) {
Long id = Long.parseLong(request.pathVariable("id"));
return fileService.getFileById(id)
.flatMap(file -> ServerResponse.ok().bodyValue(file))
.switchIfEmpty(ServerResponse.notFound().build());
}
public Mono<ServerResponse> uploadFile(ServerRequest request) {
String username = request.headers().firstHeader("X-Username");
if (username == null) {
username = "system";
}
final String finalUsername = username;
return request.multipartData()
.flatMap(multipartData -> {
var part = multipartData.getFirst("file");
if (part == null) {
return ServerResponse.badRequest().bodyValue("No file uploaded");
}
if (!(part instanceof FilePart)) {
return ServerResponse.badRequest().bodyValue("Invalid file part");
}
final FilePart filePart = (FilePart) part;
return fileService.uploadFile(filePart, finalUsername)
.flatMap(file -> ServerResponse.ok().bodyValue(file));
})
.switchIfEmpty(ServerResponse.badRequest().bodyValue("No file data"));
}
public Mono<ServerResponse> downloadFile(ServerRequest request) {
Long id = Long.parseLong(request.pathVariable("id"));
return fileService.getFileById(id)
.flatMap(file -> {
try {
Path filePath = Paths.get(file.getFilePath());
byte[] fileContent = Files.readAllBytes(filePath);
return ServerResponse.ok()
.header("Content-Disposition", "attachment; filename=\"" + file.getFileName() + "\"")
.header("Content-Type", file.getFileType())
.bodyValue(fileContent);
} catch (Exception e) {
return ServerResponse.notFound().build();
}
})
.switchIfEmpty(ServerResponse.notFound().build());
}
public Mono<ServerResponse> downloadFileByName(ServerRequest request) {
String fileName = request.pathVariable("fileName");
return fileService.getAllFiles()
.filter(file -> file.getFileName().equals(fileName))
.next()
.flatMap(file -> {
try {
Path filePath = Paths.get(file.getFilePath());
byte[] fileContent = Files.readAllBytes(filePath);
return ServerResponse.ok()
.header("Content-Disposition", "attachment; filename=\"" + file.getFileName() + "\"")
.header("Content-Type", file.getFileType())
.bodyValue(fileContent);
} catch (Exception e) {
return ServerResponse.notFound().build();
}
})
.switchIfEmpty(ServerResponse.notFound().build());
}
public Mono<ServerResponse> previewFile(ServerRequest request) {
Long id = Long.parseLong(request.pathVariable("id"));
return fileService.getFileById(id)
.flatMap(file -> {
try {
Path filePath = Paths.get(file.getFilePath());
byte[] fileContent = Files.readAllBytes(filePath);
return ServerResponse.ok()
.header("Content-Type", file.getFileType())
.bodyValue(fileContent);
} catch (Exception e) {
return ServerResponse.notFound().build();
}
})
.switchIfEmpty(ServerResponse.notFound().build());
}
public Mono<ServerResponse> previewFileByName(ServerRequest request) {
String fileName = request.pathVariable("fileName");
return fileService.getAllFiles()
.filter(file -> file.getFileName().equals(fileName))
.next()
.flatMap(file -> {
try {
Path filePath = Paths.get(file.getFilePath());
byte[] fileContent = Files.readAllBytes(filePath);
return ServerResponse.ok()
.header("Content-Type", file.getFileType())
.bodyValue(fileContent);
} catch (Exception e) {
return ServerResponse.notFound().build();
}
})
.switchIfEmpty(ServerResponse.notFound().build());
}
public Mono<ServerResponse> deleteFile(ServerRequest request) {
Long id = Long.parseLong(request.pathVariable("id"));
return fileService.deleteFile(id)
.then(ServerResponse.ok().build())
.onErrorResume(e -> ServerResponse.badRequest().bodyValue(e.getMessage()));
}
}