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请求,则解析出起始和结束位置startRangeendRange,设置响应头的Content-RangeContent-LengthACCEPT_RANGES字段,并返回206 Partial Content状态码,表示部分内容响应,同时通过createRelative()方法读取文件指定范围的数据返回给客户端。如果没有Range请求,则按照普通下载方式设置响应头并返回整个文件。

五、实战案例演示

通过一个完整的 Spring Boot 项目实例,演示文件上传与下载功能的实际应用。包括前端页面的设计与交互(使用 HTML、JavaScript 等前端技术实现简单的文件上传和下载按钮及相关提示信息),以及后端 Spring Boot 代码的具体实现细节。展示如何将文件上传与业务逻辑相结合,例如在用户注册时上传头像,并在用户个人资料页面实现头像的下载显示;或者在一个文档管理系统中,实现文件的上传、分类存储以及用户按需下载等功能场景。

六、总结与展望

总结本文所介绍的 Spring Boot 文件上传与下载功能的实现步骤、关键要点以及注意事项。强调在实际开发过程中,安全性与稳定性是至关重要的因素,需要开发者充分考虑各种边界情况并进行合理的处理。同时,展望未来可能的扩展方向,如与云存储服务集成,实现更强大、灵活的文件管理功能,以满足日益增长的业务需求。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/70046.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Golang】GC探秘/写屏障是什么?

之前写了 一篇【Golang】内存管理 &#xff0c;有了很多的阅读量&#xff0c;那么我就接着分享一下Golang的GC相关的学习。 由于Golang的GC机制一直在持续迭代&#xff0c;本文叙述的主要是Go1.9版本及以后的GC机制&#xff0c;该版本中Golang引入了 混合写屏障大幅度地优化了S…

DeepSeek教unity------MessagePack-03

数据契约兼容性 你可以使用 [DataContract] 注解代替 [MessagePackObject]。如果类型用 DataContract 进行注解&#xff0c;可以使用 [DataMember] 注解代替 [Key]&#xff0c;并使用 [IgnoreDataMember] 代替 [IgnoreMember]。 然后&#xff0c;[DataMember(Order int)] 的…

【对比】Pandas 和 Polars 的区别

Pandas vs Polars 对比表 特性PandasPolars开发语言Python&#xff08;Cython 实现核心部分&#xff09;Rust&#xff08;高性能系统编程语言&#xff09;性能较慢&#xff0c;尤其在大数据集上&#xff08;内存占用高&#xff0c;计算效率低&#xff09;极快&#xff0c;利用…

百度千帆平台对接DeepSeek官方文档

目录 第一步&#xff1a;注册账号&#xff0c;开通千帆服务 第二步&#xff1a;创建应用&#xff0c;获取调用秘钥 第三步&#xff1a;调用模型&#xff0c;开启AI对话 方式一&#xff1a;通过API直接调用 方式二&#xff1a;使用SDK快速调用 方式三&#xff1a;在千帆大模…

49. c++计时器

为了测试某段特定代码的执行时间&#xff0c;体现代码的性能&#xff0c;可以使用计时器对代码段计时。下面使用std::chrono中的api编写简单案例&#xff1a; // // main.cpp // HelloWorld // // Created by on 2024/11/28. //#include <iostream> #include <vec…

Natural Language Processing NLP

NLP 清晰版本查看 Sentence segmentation (split)Tokenisation (split)Named entity recognition (combine) 概念主要內容典型方法Distributional Semantics&#xff08;分佈式語義&#xff09;&#xff08;分銷語義&#xff08;分佈式語義&#xff09;單詞的語義來自於它的…

Linux中线程创建,线程退出,线程接合

线程的简单了解 之前我们了解过 task_struct 是用于描述进程的核心数据结构。它包含了一个进程的所有重要信息&#xff0c;并且在进程的生命周期内保持更新。我们想要获取进程相关信息往往从这里得到。 在Linux中&#xff0c;线程的实现方式与进程类似&#xff0c;每个线程都…

HarmonyOS:使用List实现分组列表(包含粘性标题)

一、支持分组列表 在列表中支持数据的分组展示&#xff0c;可以使列表显示结构清晰&#xff0c;查找方便&#xff0c;从而提高使用效率。分组列表在实际应用中十分常见&#xff0c;如下图所示联系人列表。 联系人分组列表 在List组件中使用ListItemGroup对项目进行分组&#…

django上传文件

1、settings.py配置 # 静态文件配置 STATIC_URL /static/ STATICFILES_DIRS [BASE_DIR /static, ]上传文件 # 定义一个视图函数&#xff0c;该函数接收一个 request 参数 from django.shortcuts import render # 必备引入 import json from django.views.decorators.http i…

【前端知识】浏览器兼容方案polyfill

浏览器兼容方案polyfill 什么是 Polyfill&#xff1f;Polyfill 的作用Polyfill 的工作原理1. **特性检测**2. **加载 Polyfill**3. **模拟实现** Polyfill 的常见场景Polyfill 的使用方式Polyfill 的优缺点优点缺点 常见的 Polyfill 库总结 什么是 Polyfill&#xff1f; Polyf…

C#学习之DateTime 类

目录 一、DateTime 类的常用方法和属性的汇总表格 二、常用方法程序示例 1. 获取当前本地时间 2. 获取当前 UTC 时间 3. 格式化日期和时间 4. 获取特定部分的时间 5. 获取时间戳 6. 获取时区信息 三、总结 一、DateTime 类的常用方法和属性的汇总表格 在 C# 中&#x…

dedecms 开放重定向漏洞(附脚本)(CVE-2024-57241)

免责申明: 本文所描述的漏洞及其复现步骤仅供网络安全研究与教育目的使用。任何人不得将本文提供的信息用于非法目的或未经授权的系统测试。作者不对任何由于使用本文信息而导致的直接或间接损害承担责任。如涉及侵权,请及时与我们联系,我们将尽快处理并删除相关内容。 0x0…

如何选择合适的超参数来训练Bert和TextCNN模型?

选择合适的超参数来训练Bert和TextCNN模型是一个复杂但关键的过程&#xff0c;它会显著影响模型的性能。以下是一些常见的超参数以及选择它们的方法&#xff1a; 1. 与数据处理相关的超参数 最大序列长度&#xff08;max_length&#xff09; 含义&#xff1a;指输入到Bert模…

AWS 前端自动化部署流程指南

本文详细介绍从前端代码开发到 AWS 自动化部署的完整流程。 一、流程概览 1.1 部署流程图 #mermaid-svg-nYg7k6L5IKVBjDtr {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-nYg7k6L5IKVBjDtr .error-icon{fill:#552…

Office word打开加载比较慢处理方法

1.添加safe参数 ,找到word启动项,右击word,选择属性 , 添加/safe , 应用并确定 2.取消加载项,点击文件,点击选项 ,点击加载项,点击转到,取消所有勾选,确定。

大数据SQL调优专题——Spark执行原理

引入 在深入MapReduce中有提到&#xff0c;MapReduce虽然通过“分而治之”的思想&#xff0c;解决了海量数据的计算处理问题&#xff0c;但性能还是不太理想&#xff0c;这体现在两个方面&#xff1a; 每个任务都有比较大的overhead&#xff0c;都需要预先把程序复制到各个 w…

MYSQL下载安装及使用

MYSQL官网下载地址&#xff1a;https://downloads.mysql.com/archives/community/ 也可以直接在服务器执行指令下载&#xff0c;但是下载速度比较慢。还是自己下载好拷贝过来比较快。 wget https://dev.mysql.com/get/Downloads/mysql-5.7.38-linux-glibc2.12-x86_64.tar.gz 1…

CentOS 7.8 安装MongoDB 7 副本集(Replica Set)

文章目录 1 环境假设步骤1&#xff1a;在两台服务器上安装MongoDB步骤2&#xff1a;配置副本集步骤3&#xff1a;初始化副本集步骤4&#xff1a;验证副本集配置步骤5&#xff1a;设置安全性&#xff08;可选&#xff09;扩展配置示例&#xff1a;最佳实践&#xff1a;仲裁节点步…

AJAX 与 ASP 的深入探讨

AJAX 与 ASP 的深入探讨 引言 随着互联网技术的飞速发展,Web应用程序的交互性和性能要求越来越高。AJAX(Asynchronous JavaScript and XML)和ASP(Active Server Pages)作为两种重要的Web开发技术,在提高Web应用程序性能和用户体验方面发挥着重要作用。本文将深入探讨AJ…

内网下,Ubuntu (24.10) 离线安装docker最新版教程

一般在数据比较敏感的情况下&#xff0c;是无法使用网络的&#xff0c;而对于Ubuntu系统来说&#xff0c;怎么离线安装docker呢&#xff1f; 下面我给大家来讲一下&#xff1a; 采用二进制安装&#xff1a; 1.下载docker离线包 官网下载&#xff1a; Index of linux/static…