Spring Boot 2.x迁移至3.x:如何将Flux<Part>转换为MultipartFile?
从Flux兼容MultipartFile的最小改动方案
针对Spring Boot 3.x WebFlux环境下兼容原有MultipartFile代码的需求,有两种实用方案可以最小化代码改动:
方案1:直接在WebFlux控制器中复用MultipartFile(简单场景首选)
WebFlux的注解式控制器(@RestController/@Controller)支持同步参数类型,包括MultipartFile。Spring会自动将请求中的Part转换为MultipartFile,原有代码几乎不需要修改:
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<?> upload(@RequestPart(value = "file", required = false) MultipartFile file) { // 原有的Spring MVC处理代码完全保留,无需修改 }
注意:这种方式是阻塞式的,文件会被加载到内存或临时磁盘文件中,适合小文件上传场景。如果是大文件流式处理,建议用方案2。
方案2:自定义转换器适配流式场景(大文件兼容)
如果必须使用流式的Flux<Part>,可以通过适配器类将Part包装为MultipartFile,业务代码无需改动:
1. 实现MultipartFile适配器类
import org.springframework.http.codec.multipart.Part; import org.springframework.web.multipart.MultipartFile; import reactor.core.publisher.Mono; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; public class PartMultipartFileAdapter implements MultipartFile { private final Part part; private final byte[] content; private PartMultipartFileAdapter(Part part, byte[] content) { this.part = part; this.content = content; } public static Mono<MultipartFile> fromPart(Part part) { return part.content() .reduce(new ByteArrayOutputStream(), (os, buffer) -> { os.write(buffer.array(), buffer.position(), buffer.remaining()); return os; }) .map(os -> new PartMultipartFileAdapter(part, os.toByteArray())); } @Override public String getName() { return part.name(); } @Override public String getOriginalFilename() { return part.filename().orElse(""); } @Override public String getContentType() { return part.headers().getContentType().toString(); } @Override public boolean isEmpty() { return content.length == 0; } @Override public long getSize() { return content.length; } @Override public byte[] getBytes() throws IOException { return content; } @Override public InputStream getInputStream() throws IOException { return new ByteArrayInputStream(content); } @Override public void transferTo(java.io.File dest) throws IOException, IllegalStateException { try (InputStream in = getInputStream()) { java.nio.file.Files.copy(in, dest.toPath()); } } }
2. 控制器层做转换,复用原有业务代码
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) public Mono<ResponseEntity<?>> upload(@RequestPart(value = "file", required = false) Flux<Part> fileFlux) { return fileFlux .next() // 单文件上传取第一个Part .flatMap(PartMultipartFileAdapter::fromPart) .map(this::handleUpload) // 直接调用原有处理MultipartFile的方法 .map(ResponseEntity::ok) .defaultIfEmpty(ResponseEntity.badRequest().body("No file uploaded")); } // 原有业务方法完全保留 private ResponseEntity<?> handleUpload(MultipartFile file) { // Existing code for Spring MVC }
如果是多文件上传,只需将next()改为collectList(),再批量转换为List<MultipartFile>后传入原有批量处理方法即可。
内容的提问来源于stack exchange,提问作者Digital
相关产品推荐
相关产品推荐

