webflux 的文件上传下载功能
文件上传
RestController架构
webflux直接提供了RequestPart注解,让我们拿到上传的文件数据
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public Mono<String> requestBodyFlux(@RequestPart("file") FilePart filePart) throws IOException {
System.out.println(filePart.filename());
Path tempFile = Files.createTempFile("test", filePart.filename());
//NOTE 方法一
AsynchronousFileChannel channel =
AsynchronousFileChannel.open(tempFile, StandardOpenOption.WRITE);
DataBufferUtils.write(filePart.content(), channel, 0)
.doOnComplete(() -> {
System.out.println("finish");
})
.subscribe();
//NOTE 方法二
//filePart.transferTo(tempFile.toFile());
return Mono.just(filePart.filename());
}
说明:使用RequestPart来接收,得到的是FilePart
FilePart的content是Flux,可以使用DataBufferUtils写到文件或者直接使用transferTo写入到文件
Route Handler架构
很多时候,我们使用 router 如下指定接口访问入口
@Bean
RouterFunction<ServerResponse> myRouter(IndustryChainHandler icHandler) {
return nest(
path("/v2.0/mynetwork"),
route(POST("/upload"), myHandler::upload));
}
此时不方便直接拿到RequestPart 数据,但是其实数据都还是在ServerRequest里面,变换一下就可以了。
public Mono<ServerResponse> upload(ServerRequest request) {
return ok().contentType(APPLICATION_JSON_UTF8).body(
request.body(BodyExtractors.toMultipartData()).map(parts -> {
Map<String, Part> map = parts.toSingleValueMap();
// ‘files’ 为客户端上传文件key
FilePart filePart = (FilePart) map.get("files");
try {
// 第一个参数是上传文件的前缀,可以随便起名字
Path tempFile = Files.createTempFile("upload_file", filePart.filename());
File dest = tempFile.toFile();
filePart.transferTo(dest);
return filePart.filename();
} catch (IOException e) {
e.printStackTrace();
}
return "";
}).map(filename -> {
if (!StringUtils.isEmpty(filename)) {
return "OK";
} else {
return "error";
}
}), String.class
);
文件下载
方法1:
@GetMapping("/download")
public Mono<Void> downloadByWriteWith(ServerHttpResponse response) throws IOException {
ZeroCopyHttpOutputMessage zeroCopyResponse = (ZeroCopyHttpOutputMessage) response;
response.getHeaders().set(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=myimage.png");
response.getHeaders().setContentType(MediaType.IMAGE_PNG);
Resource resource = new ClassPathResource("parallel.png");
File file = resource.getFile();
return zeroCopyResponse.writeWith(file, 0, file.length());
}
方法2:
@GetMapping("/download")
public Mono<ServerResponse> downloadByWriteWith(ServerRequest request) throws IOException {
Resource resource = new ClassPathResource("myimage.png");
return ok().header("Content-Disposition", "attachment; filename=myimage.png")
.body(BodyInserters.fromResource(resource)).switchIfEmpty(Mono.empty());
}
说明:两种方法都是将数据写入ServerHttpResponse,方法2可以在配合path.route使用