spring webflux文件上传与下载

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
相关推荐
曾令胜1 小时前
excel导出使用arthas动态追踪方法调用耗时后性能优化的过程
spring·性能优化·excel
.格子衫.1 小时前
Spring Boot 原理篇
java·spring boot·后端
多云几多2 小时前
Yudao单体项目 springboot Admin安全验证开启
java·spring boot·spring·springbootadmin
摇滚侠3 小时前
Spring Boot 3零基础教程,Spring Intializer,笔记05
spring boot·笔记·spring
Jabes.yang4 小时前
Java求职面试实战:从Spring Boot到微服务架构的技术探讨
java·数据库·spring boot·微服务·面试·消息队列·互联网大厂
聪明的笨猪猪4 小时前
Java Redis “高可用 — 主从复制”面试清单(含超通俗生活案例与深度理解)
java·经验分享·笔记·面试
兮动人4 小时前
Spring Bean耗时分析工具
java·后端·spring·bean耗时分析工具
MESSIR224 小时前
Spring IOC(控制反转)中常用注解
java·spring
摇滚侠4 小时前
Spring Boot 3零基础教程,Demo小结,笔记04
java·spring boot·笔记
华洛4 小时前
公开一个AI产品的商业逻辑与设计方案——AI带来的涂色卡自由
前端·后端·产品