Spring Boot 实战:轻松实现文件上传与下载功能
目录
一、引言
二、Spring Boot 文件上传基础
(一)依赖引入
(二)配置文件设置
(三)文件上传接口编写
(一)文件类型限制
(二)文件大小验证
(三)防止文件覆盖
四、Spring Boot 文件下载实现
(一)简单文件下载接口编写
(二)文件下载的异常处理
(三)支持断点续传
五、实战案例演示
六、总结与展望
一、引言
在当今的 Web 应用开发中,文件上传与下载功能是极为常见且重要的需求。无论是用户上传头像、分享文档,还是系统生成报告供用户下载,都离不开这一功能模块。Spring Boot 作为一款流行的 Java 开发框架,为我们提供了简洁高效的方式来实现文件上传与下载。本文将详细介绍如何基于 Spring Boot 框架轻松搭建并实现这一功能,让你快速掌握其核心要点与实践技巧。
二、Spring Boot 文件上传基础
(一)依赖引入
在 Spring Boot 项目中,首先需要引入相关依赖。对于文件上传功能,除了基础的spring-boot-starter-web依赖外,还需要添加处理文件上传的commons-fileupload依赖。在pom.xml文件中添加如下依赖:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.4</version>
</dependency>
spring-boot-starter-web提供了构建 Web 应用的基础功能,而commons-fileupload则专门用于处理文件上传操作。
(二)配置文件设置
在application.properties配置文件中设置与文件上传相关的参数。例如:
?
# 设置单个文件上传的最大大小为 10MB
spring.servlet.multipart.max-file-size=10MB
# 设置一次请求中上传文件的总大小为 20MB
spring.servlet.multipart.max-request-size=20MB
# 设置上传文件的临时目录
spring.servlet.multipart.location=/tmp/uploads?
这里分别设置了单个文件大小限制、总请求文件大小限制以及上传文件的临时存储目录。这些配置可以根据实际项目需求进行调整。
(三)文件上传接口编写
编写一个简单的文件上传接口,接收前端传来的文件数据。创建一个FileUploadController类:
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;import java.io.File;
import java.io.IOException;@RestController
public class FileUploadController {@PostMapping("/upload")public String uploadFile(@RequestParam("file") MultipartFile file) {if (file.isEmpty()) {return "上传文件为空,请选择文件后再次上传。";}try {// 获取文件名String fileName = file.getOriginalFilename();// 获取文件存储路径,这里假设存储在项目根目录下的 uploads 文件夹中String filePath = System.getProperty("user.dir") + "/uploads/" + fileName;// 将文件保存到指定路径file.transferTo(new File(filePath));return "文件上传成功,文件路径:" + filePath;} catch (IOException e) {e.printStackTrace();return "文件上传失败:" + e.getMessage();}}
}
在上述代码中,@RestController表示这是一个处理 RESTful 风格请求的控制器类。@PostMapping("/upload")注解指定了该方法处理POST请求到/upload路径的逻辑。@RequestParam("file") MultipartFile file用于接收前端传来的名为file的文件数据。通过file.isEmpty()判断文件是否为空,如果不为空,则获取文件的原始名称getOriginalFilename(),构建文件存储路径,最后使用transferTo()方法将文件保存到指定路径。如果保存过程中出现IOException异常,则打印异常信息并返回错误提示。
(一)文件类型限制
可以通过白名单的方式对上传文件的类型进行限制。例如,只允许上传图片文件(如.jpg、.png、.gif):
private static final String[] ALLOWED_FILE_TYPES = { "image/jpeg", "image/png", "image/gif" };@PostMapping("/upload")
public String uploadFile(@RequestParam("file") MultipartFile file) {if (file.isEmpty()) {return "上传文件为空,请选择文件后再次上传。";}// 检查文件类型是否在允许列表中if (!Arrays.asList(ALLOWED_FILE_TYPES).contains(file.getContentType())) {return "不允许上传该类型的文件,请上传图片文件(jpg、png、gif)。";}try {// 后续文件保存逻辑...} catch (IOException e) {e.printStackTrace();return "文件上传失败:" + e.getMessage();}
}
上述代码中,定义了一个允许的文件类型数组ALLOWED_FILE_TYPES,然后在上传文件前检查文件的ContentType是否在允许列表中,如果不在,则返回错误提示。
(二)文件大小验证
除了配置文件中的全局限制,在代码层面也可以再次验证单个文件大小:
@PostMapping("/upload")
public String uploadFile(@RequestParam("file") MultipartFile file) {if (file.isEmpty()) {return "上传文件为空,请选择文件后再次上传。";}// 检查文件大小是否超过 5MBif (file.getSize() > 5 * 1024 * 1024) {return "上传文件过大,单个文件大小不能超过 5MB。";}// 后续文件类型检查及保存逻辑...
}
这里通过file.getSize()获取文件大小,并与设定的限制(5MB)进行比较,如果超过则返回错误提示。
(三)防止文件覆盖
采用时间戳生成唯一文件名来防止文件覆盖:
@PostMapping("/upload")
public String uploadFile(@RequestParam("file") MultipartFile file) {if (file.isEmpty()) {return "上传文件为空,请选择文件后再次上传。";}try {// 获取文件名String originalFileName = file.getOriginalFilename();// 获取文件后缀名String fileExtension = originalFileName.substring(originalFileName.lastIndexOf("."));// 生成唯一文件名,使用当前时间戳String uniqueFileName = System.currentTimeMillis() + fileExtension;// 获取文件存储路径,这里假设存储在项目根目录下的 uploads 文件夹中String filePath = System.getProperty("user.dir") + "/uploads/" + uniqueFileName;// 将文件保存到指定路径file.transferTo(new File(filePath));return "文件上传成功,文件路径:" + filePath;} catch (IOException e) {e.printStackTrace();return "文件上传失败:" + e.getMessage();}
}
通过获取原始文件名的后缀名,结合当前时间戳生成一个唯一的文件名,确保每次上传的文件都有独立的标识,避免覆盖同名文件。
四、Spring Boot 文件下载实现
(一)简单文件下载接口编写
创建一个文件下载接口,如下:
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;import java.io.File;@RestController
public class FileDownloadController {@GetMapping("/download")public ResponseEntity<FileSystemResource> downloadFile(@RequestParam("fileName") String fileName) {// 获取文件路径,这里假设文件存储在项目根目录下的 uploads 文件夹中String filePath = System.getProperty("user.dir") + "/uploads/" + fileName;File file = new File(filePath);if (file.exists()) {// 设置响应头信息,包括文件名和文件类型HttpHeaders headers = new HttpHeaders();headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + fileName);headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM_VALUE);// 返回文件资源return ResponseEntity.ok().headers(headers).body(new FileSystemResource(file));} else {return ResponseEntity.notFound().build();}}
}
在这个代码中,@GetMapping("/download")表示处理GET请求到/download路径的逻辑。根据前端传入的文件名参数fileName,构建文件路径并检查文件是否存在。如果存在,则设置响应头信息,包括Content-Disposition用于指定文件名和下载方式(attachment表示下载),Content-Type设置为APPLICATION_OCTET_STREAM_VALUE表示通用的二进制流文件类型。最后通过ResponseEntity返回文件资源,若文件不存在则返回404 Not Found状态。
(二)文件下载的异常处理
在上述代码中,如果文件不存在则返回404状态。还可以进一步处理其他可能的异常,例如文件读取错误:
@GetMapping("/download")
public ResponseEntity<FileSystemResource> downloadFile(@RequestParam("fileName") String fileName) {String filePath = System.getProperty("user.dir") + "/uploads/" + fileName;File file;try {file = new File(filePath);if (file.exists()) {// 设置响应头信息...return ResponseEntity.ok().headers(headers).body(new FileSystemResource(file));} else {return ResponseEntity.notFound().build();}} catch (Exception e) {e.printStackTrace();return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();}
}
这里捕获了可能出现的异常,并在异常发生时返回500 Internal Server Error状态码,表示服务器内部错误。
(三)支持断点续传
对于大文件下载实现断点续传功能:
@GetMapping("/download")
public ResponseEntity<Resource> downloadFile(@RequestParam("fileName") String fileName,@RequestHeader(value = "Range", required = false) String rangeHeader) {String filePath = System.getProperty("user.dir") + "/uploads/" + fileName;File file = new File(filePath);if (file.exists()) {try {// 获取文件长度long fileLength = file.length();// 处理 Range 请求头HttpHeaders headers = new HttpHeaders();if (rangeHeader!= null && rangeHeader.startsWith("bytes=")) {long startRange = Long.parseLong(rangeHeader.substring("bytes=".length()).split("-")[0]);long endRange = fileLength - 1;if (rangeHeader.contains("-")) {endRange = Long.parseLong(rangeHeader.substring("bytes=".length()).split("-")[1]);}// 设置响应头的 Content-Range 字段headers.add(HttpHeaders.CONTENT_RANGE, "bytes " + startRange + "-" + endRange + "/" + fileLength);headers.add(HttpHeaders.CONTENT_LENGTH, String.valueOf(endRange - startRange + 1));headers.add(HttpHeaders.ACCEPT_RANGES, "bytes");// 设置响应状态码为 206 Partial Contentreturn ResponseEntity.status(HttpStatus.PARTIAL_CONTENT).headers(headers).body(new FileSystemResource(file).createRelative(startRange, endRange));} else {headers.add(HttpHeaders.CONTENT_LENGTH, String.valueOf(fileLength));headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM_VALUE);headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + fileName);return ResponseEntity.ok().headers(headers).body(new FileSystemResource(file));}} catch (Exception e) {e.printStackTrace();return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();}} else {return ResponseEntity.notFound().build();}
}
在上述代码中,首先获取文件的总长度fileLength。然后检查请求头中的Range信息,如果存在Range请求,则解析出起始和结束位置startRange和endRange,设置响应头的Content-Range、Content-Length和ACCEPT_RANGES字段,并返回206 Partial Content状态码,表示部分内容响应,同时通过createRelative()方法读取文件指定范围的数据返回给客户端。如果没有Range请求,则按照普通下载方式设置响应头并返回整个文件。
五、实战案例演示
通过一个完整的 Spring Boot 项目实例,演示文件上传与下载功能的实际应用。包括前端页面的设计与交互(使用 HTML、JavaScript 等前端技术实现简单的文件上传和下载按钮及相关提示信息),以及后端 Spring Boot 代码的具体实现细节。展示如何将文件上传与业务逻辑相结合,例如在用户注册时上传头像,并在用户个人资料页面实现头像的下载显示;或者在一个文档管理系统中,实现文件的上传、分类存储以及用户按需下载等功能场景。
六、总结与展望
总结本文所介绍的 Spring Boot 文件上传与下载功能的实现步骤、关键要点以及注意事项。强调在实际开发过程中,安全性与稳定性是至关重要的因素,需要开发者充分考虑各种边界情况并进行合理的处理。同时,展望未来可能的扩展方向,如与云存储服务集成,实现更强大、灵活的文件管理功能,以满足日益增长的业务需求。
相关文章:
Spring Boot 实战:轻松实现文件上传与下载功能
目录 一、引言 二、Spring Boot 文件上传基础 (一)依赖引入 (二)配置文件设置 (三)文件上传接口编写 (一)文件类型限制 (二)文件大小验证 ࿰…...
火狐浏览器Firefox一些配置
没想到还会开这个…都是Ubuntu的错 一些个人习惯吧 标签页设置 常规-标签页 1.按最近使用顺序切换标签页 2.打开新标签而非新窗口(讨厌好多窗口) 3.打开新链接不直接切换过去(很打断思路诶) 4.关闭多个标签页时不向我确认 启动…...
[STM32 HAL库]串口中断编程思路
一、前言 最近在准备蓝桥杯比赛(嵌入式赛道),研究了以下串口空闲中断DMA接收不定长的数据,感觉这个方法的接收效率很高,十分好用。方法配置都成功了,但是有一个点需要进行考虑,就是一般我们需要…...
C++入门 详细版
欢迎来到干货小仓库!! 一分耕耘一分收获,离自己的目标越来越近。 passion!passion!!passion!!! 1.命名空间 由于C语言无法避免名字或者函数重复等问题,当有多…...
MIAOYUN信创云原生项目亮相西部“中试”生态对接活动
近日,以“构建‘中试’生态,赋能科技成果转化”为主题的“科创天府智汇蓉城”西部“中试”生态对接活动在成都高新区菁蓉汇隆重开幕。活动分为成果展览、“中试”生态主场以及成果路演洽谈对接三大板块。在成果展览环节,成都元来云志科技有限…...
网络编程 | UDP组播通信
1、什么是组播 在上一篇博客中,对UDP的广播通信进行了由浅入深的总结梳理,本文继续对UDP的知识体系进行探讨,旨在将UDP的组播通信由浅入深的讲解清楚。 组播是介于单播与广播之间,在一个局域网内,将某些主机添加到组中…...
T-SQL语言的语法
T-SQL深度解析与应用 T-SQL(Transact-SQL)是微软SQL Server使用的一种扩展SQL(结构化查询语言)。它不仅支持标准SQL的所有功能,而且增加了许多实用的扩展和特性,使得数据库的操作更加灵活和强大。本文将对…...
Java开发提效秘籍:巧用Apache Commons IO工具库
一、引言 在 Java 开发的广袤领域中,输入输出(I/O)操作宛如一座桥梁,连接着程序与外部世界,从文件的读取与写入,到网络数据的传输,I/O 操作无处不在,其重要性不言而喻。然而…...
第1章:Python TDD基础与乘法功能测试
写在前面 这本书是我们老板推荐过的,我在《价值心法》的推荐书单里也看到了它。用了一段时间 Cursor 软件后,我突然思考,对于测试开发工程师来说,什么才更有价值呢?如何让 AI 工具更好地辅助自己写代码,或许…...
web前端1--基础
(时隔数月我又来写笔记啦~) 1、下载vscode 1、官网下载:Visual Studio Code - Code Editing. Redefined 2、步骤: 1、点击同意 一直下一步 勾一个创建桌面快捷方式 在一直下一步 2、在桌面新建文件夹 拖到vscode图标上 打开v…...
.Net Core微服务入门全纪录(五)——Ocelot-API网关(下)
系列文章目录 1、.Net Core微服务入门系列(一)——项目搭建 2、.Net Core微服务入门全纪录(二)——Consul-服务注册与发现(上) 3、.Net Core微服务入门全纪录(三)——Consul-服务注…...
2024嵌入式系统的未来发展与技术洞察分享
时间如白驹过隙,不知不觉又是一年,这一年收获满满。接下来,将本年度对技术的感悟和洞察分析如下,希望对大家有所帮助。 在过去几十年里,嵌入式系统技术迅速发展,成为现代电子设备和智能硬件的核心组成部分。…...
python-44-嵌入式数据库SQLite和DuckDB
文章目录 1 SQLite1.1 世界上最流行的数据库1.1 SQLite简介1.2 插入语句1.3 查询数据1.4 更新数据1.5 删除数据2 DuckDB2.1 DuckDB简介2.2 DuckDB与Python结合使用2.2.1 创建表2.2.2 分析语句2.2.3 导出为parquet文件2.3 Windows中使用DuckDB3 参考附录1 SQLite Python的一个特…...
1.2.神经网络基础
目录 1.2.神经网络基础 1.2.1.Logistic回归 1.2.2 梯度下降算法 1.2.3 导数 1.2.4 向量化编程 1.2.5 正向传播与反向传播 1.2.6.练习 1.2.神经网络基础 1.2.1.Logistic回归 1.2.1.1.Logistic回归 逻辑回归是一个主要用于二分分类类的算法。那么逻辑回归是给定一个x ,…...
算法题目总结-双指针
文章目录 1.滑动窗口类型1.长度最小的子数组1.答案2.思路 2.无重复字符的最长子串1.答案2.思路 2.双指针类型1.盛最多水的容器1.答案2.思路 2.三数之和1.答案2.思路 1.滑动窗口类型 1.长度最小的子数组 1.答案 package com.sunxiansheng.arithmetic.day10;/*** Description:…...
人形机器人将制造iPhone!
前言 优必选机器人和富士康通过一项突破性的合作伙伴关系,正在将先进的人形机器人(如Walker S1及其升级版Walker S2)整合到制造流程中,以改变iPhone的生产方式。这一合作旨在通过提升机器人能力、优化工作流程以及实现更智能的自动…...
redis 各个模式的安装
一、Redis单机安装 1、安装gcc依赖 Redis是C语言编写的,编译需要GCC。 Redis6.x.x版本支持了多线程,需要gcc的版本大于4.9,但是CentOS7的默认版本是4.8.5。 升级gcc版本: yum -y install centos-release-scl yum -y install d…...
《王者荣耀》皮肤爬虫源码
1.爬取网页 https://pvp.qq.com/web201605/herolist.shtml 2.python代码 import requests from bs4 import BeautifulSoup import os import threading from queue import Queuedef mul(x):if not os.path.exists(x):os.mkdir(x)print("目录创建成功")else:pass h…...
学习ASP.NET Core的身份认证(基于JwtBearer的身份认证8)
为进一步测试通过请求头传递token进行身份验证,在main.htm中增加layui的数据表格组件,并调用后台服务分页显示数据,后台分页查询数据接口如下所示(测试时,直接将数据写死到代码中,没有查询数据库࿰…...
PyTorch使用教程(6)一文讲清楚torch.nn和torch.nn.functional的区别
torch.nn 和 torch.nn.functional 在 PyTorch 中都是用于构建神经网络的重要组件,但它们在设计理念、使用方式和功能上存在一些显著的区别。以下是关于这两个模块的详细区别: 1. 继承方式与结构 torch.nn torch.nn 中的模块大多数是通过继承 torch.nn…...
Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动
一、前言说明 在2011版本的gb28181协议中,拉取视频流只要求udp方式,从2016开始要求新增支持tcp被动和tcp主动两种方式,udp理论上会丢包的,所以实际使用过程可能会出现画面花屏的情况,而tcp肯定不丢包,起码…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...
ArcGIS Pro制作水平横向图例+多级标注
今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作:ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等(ArcGIS出图图例8大技巧),那这次我们看看ArcGIS Pro如何更加快捷的操作。…...
Docker 本地安装 mysql 数据库
Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...
免费PDF转图片工具
免费PDF转图片工具 一款简单易用的PDF转图片工具,可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件,也不需要在线上传文件,保护您的隐私。 工具截图 主要特点 🚀 快速转换:本地转换,无需等待上…...
【JavaSE】多线程基础学习笔记
多线程基础 -线程相关概念 程序(Program) 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现企业微信功能
1. 开发环境准备 安装DevEco Studio 3.1: 从华为开发者官网下载最新版DevEco Studio安装HarmonyOS 5.0 SDK 项目配置: // module.json5 {"module": {"requestPermissions": [{"name": "ohos.permis…...
如何应对敏捷转型中的团队阻力
应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中,明确沟通敏捷转型目的尤为关键,团队成员只有清晰理解转型背后的原因和利益,才能降低对变化的…...
离线语音识别方案分析
随着人工智能技术的不断发展,语音识别技术也得到了广泛的应用,从智能家居到车载系统,语音识别正在改变我们与设备的交互方式。尤其是离线语音识别,由于其在没有网络连接的情况下仍然能提供稳定、准确的语音处理能力,广…...
