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

文章目录

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

在这里插入图片描述

引言

文件上传和下载是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,你也可以根据需要更改为其他路径。

实现文件上传功能

创建文件上传控制器

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

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>

实现文件下载功能

创建文件下载控制器

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

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
文件类型验证

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

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");
}
文件名和路径验证

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

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() + "!";}
}
文件下载时的安全性

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

@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进行单元测试和集成测试。

示例:编写单元测试
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.mzph.cn/pingmian/27746.shtml

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

相关文章

墨香戏韵,重塑经典

创意名称 墨香戏韵&#xff0c;重塑经典|基于AIGC对戏剧创新 创意概述 京剧作为中国传统戏曲之一&#xff0c;源远流长&#xff0c;承载了丰富的文化内涵和艺术特色。水墨画则是中国传统绘画的瑰宝&#xff0c;以其独特的墨色表达和极简的形式赢得了广泛的赞誉。我们的项目将…

docker-compose部署FastDFS分布式文件系统

文章目录 一、技术选型二、fastDFS组成部分三、docker-compose文件四、客户端nginx配置五、存储器spring Boot集成参考文献 一、技术选型 还有一个更好的google FS&#xff08;但是他不开源&#xff0c;我也没找到社区版一类的可以不要钱使用的&#xff09;。 最后考虑到我们存…

【字符串函数2】

5. strncpy 函数的使用和模拟实现 选择性拷贝 char * strncpy ( char * destination, const char * source, size_t num ); 1.拷贝num个字符从源字符串到目标空间。 2.如果源字符串的⻓度⼩于num&#xff0c;则拷⻉完源字符串之后&#xff0c;在⽬标的后边 追加0 &#…

语法04 C++ 标准输入语句

标准输入 使用格式&#xff1a;cin >> 输入的意思就是把一个值放到变量里面去&#xff0c;也就是变量的赋值&#xff0c;这个值是由我们自己输入的。 (注意:输入变量前要先定义&#xff0c;输入完之后要按Enter键。) 输入多个变量&#xff0c;与输出类似&#xff0c;…

unity数独游戏

using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI;public class MainMenuPanel : MonoBehaviour {public Button btnPlay; // 开始按钮public Slider sldDifficulty; // 难度滑动条private void Awake(){/…

springer 在线投稿编译踩坑

springer投稿&#xff0c;在线编译踩坑总结 注意&#xff1a; 有的期刊需要双栏&#xff0c;而预定义的模板中可能为单栏&#xff0c;需要增加iicol选项。 例如&#xff1a; \documentclass[sn-mathphys-num]{sn-jnl}% —>\documentclass[sn-mathphys-num, iicol]{sn-jnl}…

Matlab的Simulink系统仿真(simulink调用m函数)

这几天要用Simulink做一个小东西&#xff0c;所以在网上现学现卖&#xff0c;加油&#xff01; 起初的入门是看这篇文章MATLAB 之 Simulink 操作基础和系统仿真模型的建立_matlab仿真模型搭建-CSDN博客 写的很不错 后面我想在simulink中调用m文件 在 Simulink 中调用 MATLA…

远程问诊软件哪款好?选欣九康诊疗系统

近几年国家相继推出了支持发展“互联网医疗”的政策&#xff0c;如今随着相关政策的不断落实推进&#xff0c;市场上涌现出了一大批在线咨询、电子处方和远程问诊的医疗平台&#xff0c;而在面对种类如此繁多的医疗平台究竟选择哪款更好便成了医疗机构非常头疼的事情&#xff0…

数据中心布线管理:预标记线缆与移动扫描技术的融合

随着信息技术的飞速发展&#xff0c;数据中心布线管理面临着前所未有的挑战。传统的布线管理方式已无法满足现代数据中心高效、准确和可靠的需求。在这样一个背景下&#xff0c;预标记线缆与移动扫描技术的结合&#xff0c;为数据中心布线管理带来了革命性的解决方案。 布线管理…

港理工最新综述:基于LLM的text-to-SQL调查(方法实验数据全面梳理)1

【摘要】文本到SQL旨在将自然语言问题转换为可执行的SQL语句,这对用户提问理解、数据库模式理解和SQL生成都是一个长期存在的挑战。传统的文本到SQL系统包括人工工程和深度神经网络。随后,预训练语言模型(PLMs)被开发并用于文本到SQL任务,取得了可喜的成绩。随着现代数据库变得…

B站画质补完计划(3):智能修复让宝藏视频重焕新生

1 老片存在什么画质问题&#xff1f; B站作为一个拥有浓厚人文属性的平台社区&#xff0c;聚集了诸如《雍正王朝》、《三国演义》等经典影视剧集&#xff0c;同时也吸引了大量用户欣赏、品鉴这些人文经典 。但美中不足的是&#xff0c;由于拍摄年代久远、拍摄设备落后、数据多次…

神舟电脑文件误删怎么办?这些恢复方法助你轻松解决

神舟电脑文件误删怎么办&#xff1f;在信息爆炸的时代&#xff0c;电脑已经成为我们日常生活和工作中不可或缺的重要工具。然而&#xff0c;有时我们会因为一些不小心的操作&#xff0c;误删了电脑中的重要文件&#xff0c;尤其是在使用神舟电脑这类高性能设备时&#xff0c;文…

怎么做出用于收集信息的二维码?采集信息的表单二维码制作技巧

现在二维码在日常生活中的应用越来越广泛&#xff0c;经常被用来展示多种内容展示&#xff0c;比如视频、图片、文件、音频、文本等内容&#xff0c;都可以通过生成二维码的方式来为其他人提供相关信息的展示。二维码除了有展示内容的用途外&#xff0c;现在很多人也会生成表单…

短剧分销小程序:影视产业链中的新兴力量

一、引言 在数字化浪潮的推动下&#xff0c;影视产业正迎来一场深刻的变革。短剧分销小程序作为这场变革中的新兴力量&#xff0c;正以其独特的魅力和价值&#xff0c;逐渐在影视产业链中崭露头角。本文将探讨短剧分销小程序在影视产业链中的新兴地位、其带来的变革以及未来的…

【枚举】564. 寻找最近的回文数

本文涉及知识点 枚举 LeetCode564. 寻找最近的回文数 给定一个表示整数的字符串 n &#xff0c;返回与它最近的回文整数&#xff08;不包括自身&#xff09;。如果不止一个&#xff0c;返回较小的那个。 “最近的”定义为两个整数差的绝对值最小。 示例 1: 输入: n “123”…

【日记】常去的那家饭馆转让了……(399 字)

正文 晚上吃饭&#xff0c;常去的那家饭馆门市转让了&#xff0c;不做了。sad。 不久之前&#xff0c;临近下班了&#xff0c;我忘了报一个表给副行长&#xff0c;那时候系统已经进不去了&#xff0c;查不了数据。于是我随便转发了一张以前的日报表给他&#xff0c;日期都没改。…

长亭雷池部署

安雷池推荐环境 我这个网站的1804也就是18.04 Index of /ubuntu-releases/ (163.com) 然后照着ppt做就行自带ubunutu 我是默认安装不是简易安装 之前在自己的虚拟机docker上试过安装github上的雷池 现在重新安装了ubuntu 在我的ubuntu上安装一个雷池 这是长亭的学习计划 …

Elasticsearch 认证模拟题 - 19

一、题目 使用异步查询 task1 索引&#xff0c;并且 找到 miantable_name 字段值为 name8 的文档 1.1 考点 异步搜索 1.2 答案 POST task1/_async_search {"query": {"term": {"miantable_name": {"value": "name8"}}}…

excel中按多列进行匹配并对数量进行累加

公司的生产计划是按订单下发&#xff0c;但不同订单的不同产品中可能有用到相同的配件&#xff0c;按单1对1时&#xff0c;对计算机十分友好&#xff0c;但对于在配件库检料的工人来说就比较麻烦&#xff0c;上百条产品里可能会有多条都是相同的产品&#xff0c;首先考虑的办法…

Tuple 元组

文章目录 一、什么是元组 &#xff1f;二、元组的具体操作2.1 创建元组2.1.1 tuple() 创建元组函数和 list() 创建列表函数总结 2.2 元组的元素访问操作2.3 元组的元素计数操作2.4 zip 对象 一、什么是元组 &#xff1f; 列表属于可变序列,可以任意修改列表中的元素。 元组的…