【SpringBoot】SpringBoot:实现文件上传和下载功能

server/2024/10/18 0:25:56/

文章目录

      • 引言
      • 项目初始化
        • 添加依赖
      • 配置文件存储位置
      • 实现文件上传功能
        • 创建文件上传控制器
        • 创建上传页面
      • 实现文件下载功能
        • 创建文件下载控制器
      • 安全性和最佳实践
        • 文件大小限制
        • 文件类型验证
        • 文件名和路径验证
        • 文件下载时的安全性
      • 测试与部署
        • 示例:编写单元测试
      • 部署
      • 结论

在这里插入图片描述

引言

文件上传和下载是Web应用程序中常见的需求。在现代应用中,用户需要上传各种类型的文件,如图片、文档、视频等,或者下载生成的报告和数据文件。SpringBoot通过其强大的生态系统和简化的配置,能够高效地实现文件上传和下载功能。本文将详细介绍如何使用SpringBoot实现这一功能,并讨论相关的安全性和最佳实践。

项目初始化

首先,我们需要创建一个SpringBoot项目。可以通过Spring Initializr快速生成一个项目,添加所需的依赖项。

添加依赖

pom.xml中添加以下依赖:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId>
</dependency>

配置文件存储位置

为了方便管理上传的文件,我们需要在项目中配置文件存储的位置。可以在application.properties文件中进行配置:

file.upload-dir=/tmp/uploads

这将文件上传目录设置为/tmp/uploads,你也可以根据需要更改为其他路径。

实现文件上传功能

创建文件上传控制器

创建一个控制器类,用于处理文件上传请求。

java">import org.springframework.beans.factory.annotation.Value;
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 org.springframework.web.servlet.mvc.support.RedirectAttributes;import java.io.File;
import java.io.IOException;@RestController
public class FileUploadController {@Value("${file.upload-dir}")private String uploadDir;@PostMapping("/upload")public String handleFileUpload(@RequestParam("file") MultipartFile file,RedirectAttributes redirectAttributes) {if (file.isEmpty()) {return "Please select a file to upload.";}try {File dest = new File(uploadDir + File.separator + file.getOriginalFilename());file.transferTo(dest);return "You successfully uploaded " + file.getOriginalFilename() + "!";} catch (IOException e) {e.printStackTrace();return "Failed to upload " + file.getOriginalFilename() + "!";}}
}
创建上传页面

使用Thymeleaf创建一个简单的文件上传页面。在src/main/resources/templates目录下创建一个upload.html文件:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head><title>File Upload</title>
</head>
<body>
<h1>Upload a File</h1>
<form method="POST" enctype="multipart/form-data" action="/upload"><input type="file" name="file"/><input type="submit" value="Upload"/>
</form>
</body>
</html>

实现文件下载功能

创建文件下载控制器

创建一个控制器类,用于处理文件下载请求。

java">import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;@RestController
public class FileDownloadController {@Value("${file.upload-dir}")private String uploadDir;@GetMapping("/download/{filename}")public ResponseEntity<Resource> downloadFile(@PathVariable String filename) {try {Path filePath = Paths.get(uploadDir).resolve(filename).normalize();Resource resource = new UrlResource(filePath.toUri());if (resource.exists()) {return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"").body(resource);} else {return ResponseEntity.notFound().build();}} catch (IOException e) {e.printStackTrace();return ResponseEntity.notFound().build();}}
}

安全性和最佳实践

文件大小限制

为了防止用户上传过大的文件,可以在application.properties中设置文件大小限制:

spring.servlet.multipart.max-file-size=2MB
spring.servlet.multipart.max-request-size=2MB
文件类型验证

为了防止上传恶意文件,可以在上传控制器中添加文件类型验证:

java">import org.springframework.web.bind.annotation.RequestMapping;@PostMapping("/upload")
public String handleFileUpload(@RequestParam("file") MultipartFile file,RedirectAttributes redirectAttributes) {if (file.isEmpty()) {return "Please select a file to upload.";}String contentType = file.getContentType();if (!isValidContentType(contentType)) {return "Invalid file type. Only PNG, JPEG, and PDF are allowed.";}try {File dest = new File(uploadDir + File.separator + file.getOriginalFilename());file.transferTo(dest);return "You successfully uploaded " + file.getOriginalFilename() + "!";} catch (IOException e) {e.printStackTrace();return "Failed to upload " + file.getOriginalFilename() + "!";}
}private boolean isValidContentType(String contentType) {return contentType.equals("image/png") ||contentType.equals("image/jpeg") ||contentType.equals("application/pdf");
}
文件名和路径验证

为了防止路径遍历攻击,需要验证上传文件的文件名和路径:

java">import org.springframework.web.util.UriUtils;@PostMapping("/upload")
public String handleFileUpload(@RequestParam("file") MultipartFile file,RedirectAttributes redirectAttributes) {if (file.isEmpty()) {return "Please select a file to upload.";}String fileName = UriUtils.encodePath(file.getOriginalFilename(), "UTF-8");Path destinationPath = Paths.get(uploadDir).resolve(fileName).normalize();if (!destinationPath.startsWith(Paths.get(uploadDir))) {return "Invalid file path.";}try {file.transferTo(destinationPath.toFile());return "You successfully uploaded " + file.getOriginalFilename() + "!";} catch (IOException e) {e.printStackTrace();return "Failed to upload " + file.getOriginalFilename() + "!";}
}
文件下载时的安全性

在处理文件下载请求时,也需要注意路径遍历攻击,并对文件路径进行验证:

java">@GetMapping("/download/{filename}")
public ResponseEntity<Resource> downloadFile(@PathVariable String filename) {try {String encodedFileName = UriUtils.encodePath(filename, "UTF-8");Path filePath = Paths.get(uploadDir).resolve(encodedFileName).normalize();if (!filePath.startsWith(Paths.get(uploadDir))) {return ResponseEntity.badRequest().body(null);}Resource resource = new UrlResource(filePath.toUri());if (resource.exists()) {return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"").body(resource);} else {return ResponseEntity.notFound().build();}} catch (IOException e) {e.printStackTrace();return ResponseEntity.notFound().build();}
}

测试与部署

在完成文件上传和下载功能的开发后,应该进行充分的测试,确保所有功能都能正常工作。可以使用JUnit和MockMVC进行单元测试和集成测试。

示例:编写单元测试
java">import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;@SpringBootTest
@AutoConfigureMockMvc
public class FileUploadTests {@Autowiredprivate MockMvc mockMvc;@Testpublic void testFileUpload() throws Exception {mockMvc.perform(multipart("/upload").file("file", "test content".getBytes())).andExpect(status().isOk());}
}

通过这种方式,可以确保应用的各个部分在开发过程中得到充分的测试,减少上线后的问题。

部署

SpringBoot应用可以打包成可执行的JAR文件,方便部署。通过mvn package命令,可以生成一个包含所有依赖的JAR文件。

mvn package
java -jar target/demo-0.0.1-SNAPSHOT.jar

这种打包方式使得SpringBoot应用的部署变得非常简单,不再需要复杂的服务器配置。

结论

通过本文的介绍,我们了解了如何使用SpringBoot实现文件上传和下载


http://www.ppmy.cn/server/49010.html

相关文章

微服务之远程调用

常见的远程调用方式 RPC&#xff1a;Remote Produce Call远程过程调用&#xff0c;类似的还有 。自定义数据格式&#xff0c;基于原生TCP通信&#xff0c;速度快&#xff0c;效率高。早期的webservice&#xff0c;现在热门的dubbo &#xff08;12不再维护、17年维护权交给apac…

360数字安全:2024年4月勒索软件流行态势分析报告

勒索软件传播至今&#xff0c;360 反勒索服务已累计接收到数万勒索软件感染求助。随着新型勒索软件的快速蔓延&#xff0c;企业数据泄露风险不断上升&#xff0c;勒索金额在数百万到近亿美元的勒索案件不断出现。勒索软件给企业和个人带来的影响范围越来越广&#xff0c;危害性…

Vue16-绑定class样式

一、vue绑定class样式 1-1、需求一&#xff1a;字符串写法 vue实现class样式绑定 1-2、需求二 点击div&#xff0c;随机切换样式。 math.random()&#xff1a;随机数的范围[0, 1) 1-3、需求三&#xff1a;数组写法 样式的追加 1-4、需求四 &#xff1a;对象写法 二、vue绑定…

Go语言设计与实现 学习笔记 第三章 数据结构(2)

删除 如果想要删除哈希中的元素&#xff0c;就需要使用Go语言中的delete关键字&#xff0c;这个关键字的唯一作用就是将某一个键对应的元素从哈希表中删除&#xff0c;无论该键对应的值是否存在&#xff0c;这个内建的函数不会返回任何结果。 在编译期间&#xff0c;delete关…

C# Winform 用户控件,扩展控件,自定义控件综合实例

Control类是Windows窗体控件的基类&#xff0c;它提供了在 Windows 窗体应用程序中进行可视显示所需的基础结构&#xff0c;可以通过继承来扩展熟悉的用户控件和现有控件的功能。本列介绍三种不同自定义控件以及怎么创建他们。 自定义控件分类 用户控件&#xff1a;基本控件的…

基于51单片机的智能水表

一.硬件方案 本设计主要以51单片机作为主控处理器的智能水表&#xff0c;该水表能够记录总的用水量和单次用水量&#xff0c;当用水量超出设定值时系统发出声光报警提醒&#xff0c;水量报警值能够通过按键进行自行设置&#xff0c;并且存储于AT24C02中&#xff0c;并且可以测…

C#面:详细阐述什么是 DTO

DTO&#xff08;Data Transfer Object&#xff09;是一种设计模式&#xff0c;用于在不同层之间传输数据。它的主要目的是在应用程序的不同部分之间传递数据&#xff0c;而不是直接传递实体对象。DTO通常是一个简单的POCO&#xff08;Plain Old CLR Object&#xff09;&#xf…

干部管理软件有哪些

随着信息技术的飞速发展&#xff0c;干部管理软件在各级党政机关、国企事业单位中扮演着越来越重要的角色。这些软件通过整合干部管理的各项业务流程&#xff0c;实现了干部信息的系统化、规范化和高效化管理。以下是几款主流的干部管理软件及其特点&#xff1a; 一、干部信息…