You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring WebFlux如何直接获取Multipart FilePart的原始文件路径?

Spring WebFlux获取Multipart上传文件的原始本地Path(无需复制文件)

我们的Spring WebFlux应用通过端点接收包含文件的multipart数据,上传完成后需要将文件传递给同一服务器上的杀毒扫描器。目前使用FilePart#transferTo(dest)的方案会创建文件副本,而Spring内部存储的文件实际Path存在DefaultParts的私有字段中,没有公开方法可直接访问。我们不想用反射的方式获取该Path(示例代码如下),希望找到更可靠的替代方案:

return Mono.fromCallable(() -> {
    final Object content = FieldUtils.readField(filePart, "content", true);
    return (Path) FieldUtils.readField(content, "file", true);
});

可行解决方案

1. 自定义文件存储策略(推荐)

通过自定义FileStorageStrategy,在文件上传阶段就跟踪并记录文件的本地Path,后续无需复制即可直接获取。这种方式不依赖Spring内部实现,稳定性和可维护性更高。

步骤1:实现可跟踪的文件存储策略

继承Spring默认的DefaultFileStorageStrategy,重写文件创建方法,将生成的文件Path与唯一标识关联存储:

import org.springframework.http.codec.multipart.DefaultFileStorageStrategy;
import java.nio.file.Path;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

public class TrackableFileStorageStrategy extends DefaultFileStorageStrategy {
    private final Map<String, Path> partPathMap = new ConcurrentHashMap<>();

    @Override
    protected Path createFile(String filename) throws Exception {
        Path tempFile = super.createFile(filename);
        // 生成唯一标识,可通过请求上下文或FilePart的name关联到具体文件
        String partUniqueId = UUID.randomUUID().toString();
        partPathMap.put(partUniqueId, tempFile);
        return tempFile;
    }

    // 根据唯一标识获取文件Path,使用后移除避免内存泄漏
    public Path getFilePath(String partUniqueId) {
        return partPathMap.remove(partUniqueId);
    }
}

步骤2:配置Multipart消息读取器

将自定义的存储策略注入到SynchronossPartHttpMessageReader中,替换默认的文件处理逻辑:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.codec.multipart.MultipartHttpMessageReader;
import org.springframework.http.codec.multipart.SynchronossPartHttpMessageReader;

@Configuration
public class MultipartConfig {
    @Bean
    public MultipartHttpMessageReader multipartHttpMessageReader() {
        TrackableFileStorageStrategy storageStrategy = new TrackableFileStorageStrategy();
        SynchronossPartHttpMessageReader partReader = new SynchronossPartHttpMessageReader();
        partReader.setFileStorageStrategy(storageStrategy);
        return new MultipartHttpMessageReader(partReader);
    }

    // 将自定义存储策略暴露为Bean,方便在请求处理时注入使用
    @Bean
    public TrackableFileStorageStrategy trackableFileStorageStrategy() {
        return new TrackableFileStorageStrategy();
    }
}

步骤3:在请求处理中获取Path

在处理multipart请求时,通过自定义存储策略获取对应文件的Path:

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;

@RestController
public class UploadController {
    private final TrackableFileStorageStrategy storageStrategy;

    public UploadController(TrackableFileStorageStrategy storageStrategy) {
        this.storageStrategy = storageStrategy;
    }

    @PostMapping("/upload")
    public Mono<Void> handleUpload(@RequestPart("file") FilePart filePart) {
        // 这里需要根据实际场景关联partUniqueId与filePart,比如用filePart.name()作为标识
        // 注意:如果同一请求有多个同名文件,需要额外处理唯一标识
        String partId = filePart.name();
        Path file = storageStrategy.getFilePath(partId);
        
        // 将file传递给杀毒扫描器处理
        return scanFile(file)
                .then();
    }

    private Mono<Void> scanFile(Path file) {
        // 调用杀毒扫描器的逻辑
        return Mono.empty();
    }
}

2. 利用临时文件生命周期(不推荐)

Spring WebFlux默认会将上传的文件写入临时目录,且会在请求处理完成后自动清理。如果杀毒扫描器能在清理前完成扫描,可以通过配置spring.codec.multipart.max-in-memory-size=0强制所有文件写入磁盘,但这种方式仍无法通过公开API直接获取Path,可靠性远不如自定义存储策略。


为什么不推荐反射方案?

反射方式完全依赖Spring内部类的私有字段(如DefaultParts的content、FilePartContent的file),一旦Spring版本升级,内部类结构或字段名发生变化,代码会直接失效,同时破坏了封装性,后续维护成本极高。

内容的提问来源于stack exchange,提问作者Bapt_

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 18:23:25