spring boot大文件与多文件下载
一、简单大文件下载:
/*** 下载大文件* @param path 路径* @param fileName 文件名* @return* @throws IOException*/
public static ResponseEntity<InputStreamResource> downloadFile(String path, String fileName) throws IOException {Path filePath = Paths.get(path);long size = Files.size(filePath);InputStreamResource resource = new InputStreamResource(Files.newInputStream(filePath));HttpHeaders headers = new HttpHeaders();headers.add(HttpHeaders.CONTENT_DISPOSITION, STR."attachment; filename=\{URLEncoder.encode(fileName, StandardCharsets.UTF_8)}");headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM_VALUE);headers.add(HttpHeaders.ACCEPT_RANGES, "bytes");return ResponseEntity.ok().headers(headers).contentLength(size).body(resource);
}
二、多文件下载:
/*** 起线程压缩文件,返回流* @param pathList 路径集合* @param fileName 文件名* @return*/
public static ResponseEntity<InputStreamResource> zipByThread(List<String> pathList, String fileName) throws IOException {PipedInputStream pipedInputStream = new PipedInputStream();PipedOutputStream pipedOutputStream = new PipedOutputStream(pipedInputStream);// 启动新线程以写入管道输出流Thread.ofVirtual().start(() -> {try (ZipOutputStream zos = new ZipOutputStream(pipedOutputStream)) {for (String path : pathList) {Path filePath = Paths.get(path);if (Files.exists(filePath)) {if (Files.isDirectory(filePath)) {zipDirectory(filePath, filePath.getFileName().toString(), zos);} else {zipFile(filePath, zos);}}}} catch (IOException e) {log.error("文件压缩失败:{}", e.getMessage());throw new BusinessException("文件压缩失败");} finally {try {pipedOutputStream.close();} catch (IOException _) {}}});HttpHeaders headers = new HttpHeaders();headers.add(HttpHeaders.CONTENT_DISPOSITION, STR."attachment; filename=\{URLEncoder.encode(fileName, StandardCharsets.UTF_8)}");headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM_VALUE);headers.add(HttpHeaders.CONTENT_LENGTH, String.valueOf(-1));return ResponseEntity.ok().headers(headers).body(new InputStreamResource(pipedInputStream));
}/*** 压缩文件夹* @param folder* @param parentFolder* @param zos* @throws IOException*/
private static void zipDirectory(Path folder, String parentFolder, ZipOutputStream zos) throws IOException {try (Stream<Path> paths = Files.walk(folder)) {paths.filter(Files::isRegularFile).forEach(path -> {String zipEntryName = Paths.get(parentFolder).resolve(folder.relativize(path)).toString().replace("\\", "/");try {zos.putNextEntry(new ZipEntry(zipEntryName));Files.copy(path, zos);zos.closeEntry();} catch (IOException e) {throw new BusinessException("压缩文件夹失败");}});}
}/*** 压缩文件* @param file* @param zos* @throws IOException*/
private static void zipFile(Path file, ZipOutputStream zos) throws IOException {zos.putNextEntry(new ZipEntry(file.getFileName().toString()));Files.copy(file, zos);zos.closeEntry();
}
三、 Reactive WebFlux 实现非阻塞流式传输(推荐)
1.引入依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
2.单文件下载
/*** 响应式流式下载文件,支持断点续传* @param folderPath 文件路径* @param fileName 文件名* @return 响应实体*/
@GetMapping("/download/one")
public Mono<ResponseEntity<Resource>> download(@RequestParam String folderPath,@RequestParam String fileName) throws IOException {// 获取文件Path basePath = Paths.get(folderPath).toAbsolutePath().normalize();Path filePath = basePath.resolve(fileName).normalize();// 校验文件路径,防止访问到其他目录if (!filePath.startsWith(basePath)) {throw new SecurityException("文件路径不在允许的目录内");}// 读取文件Resource resource = new PathResource(filePath);if (!resource.exists()) {return Mono.just(ResponseEntity.notFound().build());}// 获取文件大小long contentLength = resource.contentLength();// 获取文件类型MediaType mediaType = MediaTypeFactory.getMediaType(resource).orElse(MediaType.APPLICATION_OCTET_STREAM);// 响应文件return Mono.just(ResponseEntity.ok().contentType(mediaType).contentLength(contentLength).header(HttpHeaders.ACCEPT_RANGES, "bytes").body(resource));
}
3.多文件下载
/*** 响应式流式下载多个文件,不支持断点续传,因为需要压缩多个文件,长度未知* @param folderPath 文件路径* @param fileNames 文件名列表* @return 响应实体*/
@GetMapping("/download/multiple")
public Mono<ResponseEntity<InputStreamResource>> downloadMultipleFile(@RequestParam String folderPath,@RequestParam List<String> fileNames) throws IOException {// 验证文件路径Path basePath = Paths.get(folderPath).toAbsolutePath().normalize();List<Path> filePaths = new ArrayList<>(fileNames.size());for (String fileName : fileNames) {Path filePath = basePath.resolve(fileName).normalize();if (!filePath.startsWith(basePath)) {throw new SecurityException("文件路径不在允许的目录内");}filePaths.add(filePath);}// 创建管道流PipedOutputStream pos = new PipedOutputStream();PipedInputStream pis = new PipedInputStream(pos, 1024 * 32);// 在单独的线程中执行压缩Thread.ofVirtual().start(() -> {try (ZipOutputStream zos = new ZipOutputStream(pos)) {// 设置压缩级别zos.setLevel(Deflater.BEST_SPEED);for (Path path : filePaths) {if (!Files.exists(path)) {continue;}if (Files.isDirectory(path)) {zipDirectory(path, path.getFileName().toString(), zos);} else {zipFile(path, zos);}}zos.finish();} catch (IOException e) {// 处理错误} finally {try {pos.close();} catch (IOException e) {// 忽略关闭异常}}});HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);headers.setContentDispositionFormData("attachment", "download.zip");headers.setContentLength(-1);return Mono.just(ResponseEntity.ok().headers(headers).body(new InputStreamResource(pis)));
}/*** 压缩文件夹* @param folder 文件夹路径* @param parentFolder 父文件夹名* @param zos 压缩输出流* @throws IOException 异常*/
private static void zipDirectory(Path folder, String parentFolder, ZipOutputStream zos) throws IOException {try (Stream<Path> paths = Files.walk(folder)) {paths.filter(Files::isRegularFile).forEach(path -> {String zipEntryName = Paths.get(parentFolder).resolve(folder.relativize(path)).toString().replace("\\", "/");try {zos.putNextEntry(new ZipEntry(zipEntryName));Files.copy(path, zos);zos.closeEntry();} catch (IOException e) {throw new RuntimeException("压缩文件夹失败");}});}
}/*** 压缩文件* @param file 文件路径* @param zos 压缩输出流* @throws IOException 异常*/
private static void zipFile(Path file, ZipOutputStream zos) throws IOException {zos.putNextEntry(new ZipEntry(file.getFileName().toString()));Files.copy(file, zos);zos.closeEntry();
}
注意
如果使用了nginx反代,下载超时需要在nginx配置
proxy_buffering off;
相关文章:
spring boot大文件与多文件下载
一、简单大文件下载: /*** 下载大文件* param path 路径* param fileName 文件名* return* throws IOException*/ public static ResponseEntity<InputStreamResource> downloadFile(String path, String fileName) throws IOException {Path filePath Path…...
事务隔离级别和MVCC
事务隔离级别 mysql是一个客户端/服务器架构的软件,对于同一个服务器来说,可以有多个客户端与之连接。每个客户端与服务器连接后就形成了一个会话。每个客户端都可以在自己的会话中向服务器发出请求语句,一个请求语句可能是某个事务的一部分…...
Ubuntu 系统深度清理:彻底卸载 Redis 服务及残留配置
Ubuntu 系统深度清理:彻底卸载 Redis 服务及残留配置 在Ubuntu系统中,Redis是一种广泛使用的内存数据存储系统,用于缓存和消息传递等场景。然而,有时候我们需要彻底卸载Redis,以清理系统资源或为其他应用腾出空间。本…...
关于群晖安装tailscale后无法直链的问题
问题是我局域网的ipv6无法正确获取到ip, 通过命令可以看到ipv6没有ip tailscale netcheck C:\Users\Administrator>tailscale netcheck 2025/04/12 23:43:34 attempting to fetch a DERPMap from https://controlplane.tailscale.comReport:* Time: 2025-04-12T15:43:38.27…...
第十二章:FreeRTOS多任务创建与删除
FreeRTOS多任务创建与删除教程 概述 本教程介绍FreeRTOS多任务的创建与删除方法,主要涉及两个核心函数: 任务创建:xTaskCreate()任务删除:vTaskDelete() 实践步骤 1. 准备工程文件 复制005工程并重命名为006 2. 创建多个任务…...
JavaScript数组方法:`some()`的全面解析与应用
文章目录 JavaScript数组方法:some()的全面解析与应用一、some()方法的基本概念语法参数说明返回值 二、some()方法的核心特点三、基础用法示例示例1:检查数组中是否有大于10的元素示例2:检查字符串数组中是否包含特定子串 四、实际应用场景1…...
IntelliJ IDEA历史版本下载安装链接
IntelliJ IDEA | Other Versions 拿走,不谢O(∩_∩)O...
Rag实现流程
Rag实现流程 目录 Rag实现流程1. 加载问答链代码解释`chain_type="stuff"` 的含义其他 `chain_type` 参数选项及特点1. `map_reduce`2. `refine`3. `map_rerank`示例代码展示不同 `chain_type` 的使用其他参数类型2. 提出问题3. 检索相关文档代码解释其他参数类型4. …...
设计模式 --- 命令模式
命令模式是一种行为设计模式,它将请求封装成一个对象,从而允许你使用不同的请求、队列或日志来参数化其他对象,同时支持请求的撤销与恢复。 优点: 1.解耦调用者与接收者:输入处理无需直接调用角色方法 2.支持撤销…...
C# TCP与ip通信
一、获取本机的ip地址 // 获取本地主机名 string hostName Dns.GetHostName(); string ip "127.0.0.1"; //Console.WriteLine("本地主机名: " hostName);// 获取本地IP地址 IPAddress[] addresses Dns.GetHostAddresses(hostName); Console.WriteLine…...
如何使用 Grafana 连接 Easyearch
Grafana 介绍 Grafana 是一款开源的跨平台数据可视化与监控分析工具,专为时序数据(如服务器性能指标、应用程序日志、业务数据等)设计。它通过直观的仪表盘(Dashboards)帮助用户实时监控系统状态、分析趋势࿰…...
ubuntu20.04 openvino的yolov8推理(nncf量化)
1.环境配置: pip install openvino-dev(2023.0.1) pip install nncf(2.5.0) pip install ultralytics 2.模型转换及nncf量化: 1.pytorch->onnx: # Pytorch模型转换为Onnx模型 python from ultralytics import YOLO model YOLO(yolov8s.pt) # yo…...
《Python星球日记》第26天:Matplotlib 可视化
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 订阅专栏:《Python星球日记》 目录 一、Matplotlib 简介1. 什么是 Matplo…...
2025蓝桥杯python A组题解
真捐款去了,好长时间没练了,感觉脑子和手都不转悠了。 B F BF BF 赛时都写假了, G G G 也只写了爆搜。 题解其实队友都写好了,我就粘一下自己的代码,稍微提点个人的理解水一篇题解 队友题解 B 思路: 我…...
OpenHarmony - 小型系统内核(LiteOS-A)(一)
OpenHarmony - 小型系统内核(LiteOS-A)(一) 一、小型系统内核概述 简介 OpenHarmony 轻量级内核是基于IoT领域轻量级物联网操作系统Huawei LiteOS内核演进发展的新一代内核,包含LiteOS-M和LiteOS-A两类内核。LiteOS-…...
Neo4j GDS-13-neo4j GDS 库中节点插入算法实现
neo4j GDS 系列 Neo4j APOC-01-图数据库 apoc 插件介绍 Neo4j GDS-01-graph-data-science 图数据科学插件库概览 Neo4j GDS-02-graph-data-science 插件库安装实战笔记 Neo4j GDS-03-graph-data-science 简单聊一聊图数据科学插件库 Neo4j GDS-04-图的中心性分析介绍 Neo…...
js中this的指向问题
前言: 在js中,this出现的位置多种多样,你会不会迷糊呢?this到底指代的是哪个对象?这篇文章带你搞懂不同场景下this的指向问题。 this出现场景: 从作用域的角度来讲,this出现的位置无非就是两…...
【3dSwap】3D-Aware Face Swapping
文章目录 3D-Aware Face Swapping背景points贡献方法从2D图像推断3D先验通过潜在代码操纵进行人脸交换联合枢轴调整目标函数实验与二维人脸交换方法比较进一步分析3D感知人脸交换消融实验局限性3D-Aware Face Swapping 会议/期刊:CVPR 2023 作者: code:https://lyx0208.gi…...
基于STM32的智能门禁系统
2.1系统方案设计 本课题为基于STM32的智能门禁系统的设计,其系统架构如图2.1所示,整个系统由STM32F103单片机和MaixBit开发板两部分构成,其中MaixBit是基于K210芯片的开发板,在此主要负责人脸的录入,识别,…...
用链表、信号,实现简易MP3项目
链表实现MP3 #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <time.h> #include <dirent.h> #include <sys/stat.h> #include <sys/types.h> #include <glob.h> #inc…...
YOLO检测目标后实现距离测量
当我们使用YOLO检测器得到检测结果后,我们如何计算检测的物体距离相机的位置呢? 目前,有三种较为主流的距离计算方法,分别是单目测距、双目测距以及基于深度估计的测距方法。 单目测距 工作原理:单目测距使用一个摄像…...
js 效果展示 拿去练手
自学完整功能,拿去练手。 鼠标移动放大 通过网盘分享的文件:图片放大 链接: https://pan.baidu.com/s/1w8SjtKi4kUNDnZtRDfYMeQ?pwd95p6 提取码: 95p6 通过网盘分享的文件:图片动画效果 链接: https://pan.baidu.com/s/1Pjphx-Cc4HQQNNujr…...
【算法】 欧拉函数与欧拉降幂 python
欧拉函数 欧拉函数 ϕ ( n ) \phi(n) ϕ(n) 表示小于等于 n 的正整数中与 n 互质的数的个数。即: ϕ ( n ) ∣ { k ∈ Z ∣ 1 ≤ k ≤ n , gcd ( k , n ) 1 } ∣ \phi(n) \left| \{ k \in \mathbb{Z}^ \mid 1 \leq k \leq n, \gcd(k, n) 1 \} \right| ϕ(n)…...
Qt触摸屏隐藏鼠标指针
Qt触摸屏隐藏鼠标指针 Chapter1 Qt触摸屏隐藏鼠标指针 Chapter1 Qt触摸屏隐藏鼠标指针 使用Qt开发的屏幕软件HMI不需要显示鼠标,qt设置,可以在只启动HMI的时候隐藏光标,退出时再显示。 1.如果只希望在某个 widget 中不显示鼠标指针…...
QT聊天项目DAY01
1.新建初始项目 2.修改UI格式 运行效果 3.创建登录界面 设计登录界面UI 设计布局 调整布局间距 往水平布局中拖入标签和文本输入框 更换控件名称并固定高度 添加窗口部件 往现有的资源文件中导入图片 添加水平布局 4.设置登陆界面为主窗口的核心组件 #pragma once#include &l…...
Stable Diffusion +双Contronet:从 ControlNet 边缘图到双条件融合:实现服装图像生成的技术演进——项目学习记录
前言 学习记录contronet优化:最近,我基于 diffusers 库的 ControlNet,探索了如何通过 Canny 边缘图控制服装图像生成,并逐步升级到融合颜色图的双条件模型。有不断的问题、解决和进步,从最初的边缘图生成到最终实现 2…...
【Hadoop入门】Hadoop生态之Spark简介
1 什么是Spark? Apache Spark 是一个开源的分布式计算框架,专为处理大规模数据而设计。它提供了高效、通用的集群计算能力,支持内存计算,能够显著提高数据处理和分析的速度。Spark 已经成为大数据处理领域的重要工具,广…...
深度学习学习笔记
目录 摘要 Abstracts 简介 Hourglass Module(Hourglass 模块) 网络结构 Intermediate Supervision(中间监督) 训练过程细节 评测结果 摘要 本周阅读了《Stacked Hourglass Networks for Human Pose Estimation》…...
小米运维面试题及参考答案(80道面试题)
请讲解一下 linux top 后进程的状态 在 Linux 系统中,使用top命令可以查看系统中正在运行的进程的相关信息,进程通常有以下几种状态: 运行(R):表示进程正在 CPU 上运行或者正在运行队列中等待运行。处于运行状态的进程正在积极地使用 CPU 资源来执行其任务。睡眠(S):进…...
动态多目标优化:基于可学习预测的动态多目标进化算法(DIP-DMOEA)求解CEC2018(DF1-DF14),提供MATLAB代码
一、DIP-DMOEA介绍 基于可学习预测的动态多目标进化算法(Learning-Based Directional Improvement Prediction for Dynamic Multiobjective Optimization,DIP-DMOEA)是2024年提出的一种动态多目标进化算法,核心在于利用神经网络学…...
第十六届蓝桥杯大赛软件赛省赛 C/C++ 大学B组
由于官方没有公布题目的数据, 所以代码仅供参考 1. 移动距离 题目链接:P12130 [蓝桥杯 2025 省 B] 移动距离 - 洛谷 【问题描述】 小明初始在二维平面的原点,他想前往坐标 (233, 666)。在移动过程中,他 只能采用以下两种移动方式…...
《Nature Methods》新算法|MARBLE利用几何深度学习解释神经群体动力学
一、写在前面 本次分享的是2025年2月发布于《Nature Methods》的题为"MARBLE:interpretable representations of neural population dynamics using geometric deep learning"的文章。在神经科学和机器学习领域交汇的今天,我们不断探索如何从复杂的神经活…...
【力扣hot100题】(093)最长公共子序列
还算是挺简单的一题。 维护二维数组代表截至至两个字符串的某个位置,前面的最长公共子序列长度。 状态转移方程就是当两字符相等是,取俩位置前一个的值加一,否则就直接等于俩位置前一个值。 class Solution { public:int longestCommonSub…...
(打卡)794. 高精度除法
C: Python: aint(input()) bint(input()) print(a//b) print(a%b)...
网络5 TCP/IP 虚拟机桥接模式、NAT、仅主机模式
TCP/IP模型 用于局域网和广域网;多个协议;每一层呼叫下一层;四层;通用标准 TCP/IP模型 OSI七层模型 应用层 应用层 表示层 会话层 传输层 传输层 网络层 网络层 链路层 数据链路层 物理层 链路层:传数据帧࿰…...
GPU虚拟化技术在深度学习集群中的应用实践
一、深度学习集群的算力困境 某些985高校AI实验室曾面临典型算力管理难题:其配备的4台8卡A100服务器(总价值超300万元)实际利用率仅38%。学生提交的PyTorch任务常因GPU抢占导致训练中断,而部分研究组独占显卡却仅运行Jupyter Not…...
从零实现基于扩散模型的文本到视频生成系统:技术详解与Pytorch代码实现
本文详细介绍了基于扩散模型构建的文本到视频生成系统,展示了在MSRV-TT和Shutterstock视频标注数据集上训练的模型输出结果。以下是模型在不同提示词下的生成示例。 首先展示一些模型生成效果展示 提示词:“A person holding a camera”(训练…...
每天学一个 Linux 命令(14):cat
Linux 文件查看与合并命令:cat cat(全称 concatenate)是 Linux 中用于查看文件内容、合并文件或创建简单文件的基础命令。它操作简单但功能灵活,是日常文件处理的常用工具。 1. 命令作用 查看文件内容:直接输出文件内容到终端。合并文件:将多个文件内容合并输出或保存到…...
05--MQTT物联网协议
一、MQTT的概念 MQTT 协议快速入门 2025:基础知识和实用教程 | EMQ 1.MQTT(Message Queuing Telemetry Transport)是一种轻量级、基于发布-订阅模式的消息传输协议,适用于资源受限的设备和低带宽、高延迟或不稳定的网络环境。它…...
免费下载 | 2025天津大学:智能制造与数字孪生技术:面向可持续制造方向发展
一、新一代智能制造模式下的思考 当代智能制造的发展阶段 智能制造定义:智能制造是基于新一代信息通信技术与先进制造技术深度融合,贯穿于设计、生产、管理、服务等制造活动的各个环节,具有自感知、自学习、自决策、自执行、自适应等功能的新…...
考研单词笔记 2025.04.12
aware a知道的,意识到的,警觉的 awareness n意识,了解,觉察 conscious a有意识的,意识到的,有意的,刻意的,神志清醒的,慎重的,关注的 unconscious a无意识…...
八股总结(Java)持续更新!
八股总结(java) ArrayList和LinkedList有什么区别 ArrayList底层是动态数组,LinkedList底层是双向链表;前者利于随机访问,后者利于头尾插入;前者内存连续分配,后者通过指针连接多块不连续的内存…...
SpringBoot3快速入门笔记
springboot3简介 SpringBoot 帮我们简单、快速地创建一个独立的、生产级别的 Spring 应用(说明:SpringBoot底层是Spring) 大多数 SpringBoot 应用只需要编写少量配置即可快速整合 Spring 平台以及第三方技术 特性: ● 快速创建…...
vue3中,element-plus中el-input的v-model和value的用法示例
el-input的v-model,邦定响应式变量 <el-col :span"6"><el-form-item label"检验类别" prop"verifyType"><el-input v-model"applyAllInfo.applyBasicInfo.verifyTypeName" readonly /></el-form-item…...
python求π近似值
【问题描述】用公式π/4≈1-1/31/5-1/7..1/(2*N-1).求圆周率PI的近似值。 从键盘输入一个整数N值,利用上述公式计算出π的近似值,然后输出π值,保留小数后8位。 【样例输入】1000 【样例输出】3.14059265 def countpi(N):p0040nowid0for i i…...
Gerapy二次开发:搜索器组件设计开发与应用(Vue父子组件通信)
搜索器组件设计开发与应用 写在前面搜索器字段定义与样式设计具体实现components/Search.vuedeploy/Index.vue后端views.py运行效果总结欢迎加入Gerapy二次开发教程专栏! 本专栏专为新手开发者精心策划了一系列内容,旨在引领你深入探索Gerapy框架的二次迭代之旅。 本专栏将全…...
深入解析Python爬虫技术:从基础到实战的功能工具开发指南
一、引言:Python 爬虫技术的核心价值 在数据驱动的时代,网络爬虫作为获取公开数据的重要工具,正发挥着越来越关键的作用。Python 凭借其简洁的语法、丰富的生态工具以及强大的扩展性,成为爬虫开发的首选语言。根据 Stack Overflow 2024 年开发者调查,68% 的专业爬虫开发者…...
Python爬虫-爬取全球股市涨跌幅和涨跌额数据
前言 本文是该专栏的第52篇,后面会持续分享python爬虫干货知识,记得关注。 本文中,笔者将基于Python爬虫,实现批量采集全球股市行情(亚洲,美洲,欧非,其他等)的各股市“涨跌幅”以及“涨跌额”数据。 具体实现思路和详细逻辑,笔者将在正文结合完整代码进行详细介绍。…...
【NLP 59、大模型应用 —— BPE 算法】
你和生生不息的河流,生动了我人生中的美好瞬间 —— 25.4.11 一、词表的构造问题 为了nlp模型训练,词表(字表)是必要的 统计训练语料中的所有字符(或词)是一种做法,但是容易出现一些问题&…...
SQL基础入门:从CRUD到JOIN再到索引(通俗易懂版)
一、为什么需要SQL? 想象你在管理一个图书馆: 传统方法:手动记录每本书的位置、借阅者、归还日期SQL方法:用数据库系统自动管理,快速查询《Java编程思想》在哪个书架 SQL(Structured Query Language&…...