1、文件上传:
Controller:
java
@PostMapping("/import")
public void importImage(@RequestPart("file") FilePart filePart) {
imageService.importImage(filePart);
}
Service:
java
public void importImage(FilePart filePart) {
File saveFile = new File("/tmp/a.txt");
if (!copyFile(filePart, saveFile)) {
throw new OpsManagerException("文件保存失败!");
}
}
java
public boolean copyFile(FilePart filePart, File tempFile) {
try {
if (tempFile.exists()) {
tempFile.delete();
}
tempFile.createNewFile();
AsynchronousFileChannel channel = AsynchronousFileChannel.open(tempFile.toPath(), StandardOpenOption.WRITE);
AtomicBoolean copyFinish = new AtomicBoolean(false);
DataBufferUtils.write(filePart.content(), channel, 0).doOnComplete(() -> copyFinish.set(true)).subscribe();
AtomicInteger atomicInteger = new AtomicInteger(0);
while (!copyFinish.get()) {
Thread.sleep(5000);
atomicInteger.addAndGet(1);
if (atomicInteger.get() > 720) {
throw new OpsManagerException("文件过大");
}
}
return true;
} catch (Exception e) {
log.error("save upload file error", e);
return false;
}
}
2、文件下载:
Controller:
java
@GetMapping("/export")
public Mono<Void> downloadFile(ServerHttpResponse response) {
File file = new File("/tmp/workplace.zip");
return TaskUtils.downloadFile(file, response);
}
Service:
java
public static Mono<Void> downloadFile(File file, ServerHttpResponse response) {
try {
response.getHeaders().set(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + URLEncoder.encode(file.getName(), "UTF-8"));
response.getHeaders().setContentType(MediaType.APPLICATION_OCTET_STREAM);
response.getHeaders().set(HttpHeaders.CONTENT_LENGTH, "" + file.length());
Flux<DataBuffer> dataBufferFlux = Flux.create((FluxSink<DataBuffer> emitter) -> {
InputStream in = null;
try {
int bytesRead;
in = new FileInputStream(file);
byte[] buffer = new byte[1024 * 1024];
while ((bytesRead = in.read(buffer)) != -1) {
emitter.next(response.bufferFactory().wrap(Arrays.copyOf(buffer, bytesRead)));
}
emitter.complete();
} catch (IOException e) {
emitter.error(e);
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
return response.writeAndFlushWith(Mono.just(dataBufferFlux));
} catch (IOException ex) {
logger.error("download file error!", ex);
throw new RuntimeException("download file error!");
}
}
上面的文件下载,可能会由于垃圾回收不及时,而导致OOM,则可以使用以下代码;
java
import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.codec.multipart.FilePart;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
import java.nio.file.Path;
import java.nio.file.Paths;
@RestController
@RequestMapping("/files")
public class FileController {
// 示例:将文件直接返回给客户端
@GetMapping("/{filename}")
public Mono<ResponseEntity<Resource>> downloadFile(@PathVariable String filename) {
// 你可能需要将文件路径配置为适应你的环境
String filePath = "/path/to/your/files/" + filename;
Path path = Paths.get(filePath);
Resource resource = new org.springframework.core.io.PathResource(path);
return Mono.just(ResponseEntity.ok()
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(resource));
}
// 示例:通过FormData方式上传文件,然后将文件直接返回给客户端
@PostMapping("/upload")
public Mono<ResponseEntity<Resource>> uploadFile(@RequestPart("file") FilePart filePart) {
// 保存文件到服务器,这里简化为直接返回文件
Resource resource = new InputStreamResource(filePart.content());
return Mono.just(ResponseEntity.ok()
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(resource));
}
}
当然下载完后还可以回调:
java
mono
.doOnSuccess(value -> {
// 在成功时执行回调
System.out.println("Success: " + value);
})
.doOnError(error -> {
// 在出错时执行回调
System.err.println("Error: " + error.getMessage());
})
.subscribe(); // 订阅Mono