news 2026/6/10 15:40:40

Spring Boot 实战:轻松实现文件上传与下载功能

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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 "上传文件为空,请选择文件后再次上传。"; } // 检查文件大小是否超过 5MB if (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 Content return 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 文件上传与下载功能的实现步骤、关键要点以及注意事项。强调在实际开发过程中,安全性与稳定性是至关重要的因素,需要开发者充分考虑各种边界情况并进行合理的处理。同时,展望未来可能的扩展方向,如与云存储服务集成,实现更强大、灵活的文件管理功能,以满足日益增长的业务需求。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 11:01:44

HY-MT1.5-1.8B部署:嵌入式Linux系统适配

HY-MT1.5-1.8B部署&#xff1a;嵌入式Linux系统适配 1. 引言 1.1 背景与需求 随着全球化进程的加速&#xff0c;跨语言交流已成为企业、开发者乃至个人用户的刚需。传统翻译服务多依赖云端大模型和高算力服务器&#xff0c;难以满足低延迟、高隐私、离线可用等边缘计算场景的…

作者头像 李华
网站建设 2026/6/9 14:29:16

HY-MT1.5-7B代码实例:混合语言场景优化方案

HY-MT1.5-7B代码实例&#xff1a;混合语言场景优化方案 1. 引言 随着全球化进程的加速&#xff0c;跨语言交流需求日益增长&#xff0c;尤其是在多语种混杂、方言与标准语并存的复杂语境中&#xff0c;传统翻译模型往往难以准确理解上下文语义和语言风格。为应对这一挑战&…

作者头像 李华
网站建设 2026/6/9 16:05:56

混元翻译模型1.5部署实战:5种民族语言支持教程

混元翻译模型1.5部署实战&#xff1a;5种民族语言支持教程 1. 引言 随着全球化进程的加速&#xff0c;多语言翻译技术已成为跨文化交流、信息互通的核心基础设施。在这一背景下&#xff0c;腾讯开源了新一代混元翻译大模型 HY-MT1.5&#xff0c;致力于提供高质量、低延迟、多场…

作者头像 李华
网站建设 2026/6/10 12:57:18

Spring Boot 中使用 @Transactional 注解配置事务管理

事务管理是应用系统开发中必不可少的一部分。Spring 为事务管理提供了丰富的功能支持。Spring 事务管理分为编程式和声明式的两种方式。编程式事务指的是通过编码方式实现事务&#xff1b;声明式事务基于 AOP,将具体业务逻辑与事务处理解耦。声明式事务管理使业务代码逻辑不受污…

作者头像 李华
网站建设 2026/6/10 12:52:31

Spring Boot 中 RabbitMQ 的使用

目录 引入依赖 添加配置 Simple&#xff08;简单模式&#xff09; 生产者代码 消费者代码 ?编辑 Work Queue&#xff08;工作队列&#xff09; 生产者代码 消费者代码 Publish/Subscribe&#xff08;发布/订阅&#xff09; 生产者代码 消费者代码 Routing&#x…

作者头像 李华
网站建设 2026/6/10 2:18:40

MDK中STM32调试技巧:超详细版操作指南

MDK中STM32调试实战&#xff1a;从断点到寄存器的深度掌控你有没有遇到过这样的场景&#xff1f;代码写完&#xff0c;下载进STM32板子&#xff0c;结果LED不闪、串口无输出。翻来覆去查了三遍初始化函数&#xff0c;时钟开了&#xff0c;GPIO配了&#xff0c;中断也使能了——…

作者头像 李华