文件上传和下载(原生JS + SpringBoot实现)
目录
概述
前端编写-上传表单和图片回显
HTML表单代码
发送请求逻辑
CSS代码
后端编写-文件上传接口
后端编写-文件下载接口
概述
在现代Web应用程序中,文件上传和下载是常见的功能。本博客将介绍如何使用原生JS和Spring Boot实现文件上传和下载的功能。
在其中会介绍到前端使用表单做文件上传时需要遵循的规则,并使用SpringBoot框架编写后端API接口来处理传入的文件,以及使用原生JS和SpringBoot框架实现文件下载功能。
测试:本篇博客主要使用图片的上传和回显作为重点测试介绍。
目的:实现类似头像上传功能效果。
整体功能逻辑:前端上传图片,后端接收到后存储到本地服务器并返回给前端存储的文件名,前端想要获取(下载)图片时,发送请求携带文件名,后端接收到后以流的方式响应给前端做展示。
前端编写-上传表单和图片回显
功能界面展示

选择并提交图片回显后展示

HTML表单代码
// 表单容器
<div id="container"><form id="myForm" method="post" enctype="multipart/form-data"><input type="file" name="file" id="file"><br><br><input type="submit" value="上传文件"></form>
</div>
<br>
<!-- 图片回显 -->
<div id="pictureEcho"></div>
代码说明
想要实现文件上传,表单书写时基本的3点要求:
【1】请求方式method需要为post
【2】表单数据的编码类型enctype为multipart/form-data
【3】需要一个类型type为file的控件<input>上传文件
发送请求逻辑
<script>// 获取表单节点let form = document.getElementById('myForm');// 获取图片回显容器节点let pictureEchoContainer = document.querySelector("#pictureEcho");// 监听表单的submit提交事件form.addEventListener('submit', function(event) {// submit事件触发时阻止默认事件,防止页面跳转刷新event.preventDefault();// 创建xhr对象,用于发送请求var xhr = new XMLHttpRequest();// 指定请求方式和请求路径xhr.open('POST', '/files/upload');// 使用formData对象处理表单数据var formData = new FormData(form);// 上传完成后的处理xhr.onload = function() { // 响应状态码为200表示请求成功if (xhr.status === 200) {// 调用图片回显的回调函数,将返回的随机UUID名称作为参数pictureShowCallback(xhr.responseText);}};// 发送HTTP请求并将数据发送给服务器xhr.send(formData);});// 自定义回调函数 function pictureShowCallback(pictureName){// 创建img节点let img = document.createElement("img")// 将img节点添加到div容器中 pictureEchoContainer.append(img)// 给img节点添加src属性img.src = "http://127.0.0.1:8080/files/download/" + pictureName;}
</script>
代码说明
具体步骤说明在代码示例中已有详解,主要过程为当点击了提交按钮,触发submit事件后,会向指定服务器发送请求,并且编写了获取服务器返回值的代码,当请求成功后调用自定义回调函数,在其中动态创建img节点,并向img节点中设置src属性为请求路径。当img节点有了src属性后,会向其src的值发送请求获取图片自动展示。
其中的xhr.onload为请求完成时调用的函数,在此用于接收返回值,获取上传后服务器给图片随机生成的UUID名称,下面做图片回显(文件下载)的时候就可以根据此UUID名称发送请求了。
CSS代码
#container{border: solid #253bbd 2px;border-radius: 5px;width: 190px;height: 90px;padding: 20px;background-color: #6a9cd3;
}img{position: absolute;width: 230px;height: 130px;top: 10px;left: 10px;border-radius: 5px;/*border: solid red;*/
}
后端编写-文件上传接口
当我们在前端编写完请求发送逻辑以后,我们就需要有一个后端接口来接收处理发送过来的请求数据。
/*** Date:2023/3/6* author:zmh* description:文件上传和下载相关接口**/
@RestController
@RequestMapping("/files")
public class FileUploadController {// 指定文件保存的根目录private final String UPLOAD_DIR = "D:\\tmp\\img\\";/*** 文件上传接口* @param file 前端传入的文件对象* @return 返回存在服务器的文件名称*/@PostMapping("/upload")public String fileUpload(@RequestParam("file") MultipartFile file){// 获取上传的图片文件后缀名String originalFilename = file.getOriginalFilename();String fileExtension = originalFilename.substring(originalFilename.lastIndexOf('.'));// 检查文件是否为空if (file.isEmpty()) {return "File is empty!";}// 检查文件名是否合法,避免目录遍历攻击String fileName = StringUtils.cleanPath(originalFilename);if (fileName.contains("..")) {return "Illegal name!";}try {// 给上传的图片随机生成一个名称,将之返回,// 用户就可以根据此名称下载图片,防止图片名称冲突。UUID uuid = UUID.randomUUID();String randomUUIDString = uuid.toString();// 将文件保存到指定目录文件File targetFile = new File(UPLOAD_DIR + randomUUIDString + fileExtension);// 将传入的图片转存到指定目录文件file.transferTo(targetFile);// 返回随机名称(带有后缀名)return randomUUIDString + fileExtension;} catch (IOException e) {e.printStackTrace();return "server error!";}}
代码说明
具体步骤详解在代码注释中说明,其中重点就是动态获取UUID和传入文件的后缀名进行拼接,拼接后作为转存文件名,将传入文件转存在本地服务器目录文件中。并将拼接后的文件名返回给前端,以后,前端就可以根据此随机名来向服务器请求文件,防止了上传文件名时冲突的问题。
后端编写-文件下载接口
为前端提供文件(图片)下载接口,当前端请求此接口时,携带路径参数(文件名)访问接口,接口将向前端响应
// 指定文件下载时服务器存储文件的根目录
private final String DOWNLOAD_DIR = "D:\\tmp\\img\\";
/*** 文件下载** @param fileName 文件名,其中的.+为正则表达式,表示可以匹配任意后缀的文件* @param response 响应*/
@GetMapping("/download/{fileName:.+}")
public void fileDownLoad(@PathVariable String fileName, HttpServletResponse response) {// 检查文件名是否合法,防止目录遍历攻击if (fileName.contains("..")) {// 文件名不合法,响应给前端状态400,表示错误请求response.setStatus(HttpServletResponse.SC_BAD_REQUEST);return;}try {// 获取输入流读取本地文件FileInputStream fileInputStream = new FileInputStream(new File(DOWNLOAD_DIR + fileName));// 获取输出流,用于向前端输出文件图片ServletOutputStream outputStream = response.getOutputStream();// 指定响应内容类型response.setContentType("image/jpg");// 遍历流输出操作int len = 0;byte[] bytes = new byte[1024];// 使用一个字节数组存容量为1024作为一组数据// 循环读取文件中数据,当读取到的数据不等于-1时代表依然有数据while((len = fileInputStream.read(bytes)) != -1){// 将存储在bytes数组中的数据写出outputStream.write(bytes, 0, len);// 手动刷洗输出流,不必等到存满在输出outputStream.flush();}// 关闭流资源fileInputStream.close();outputStream.close();} catch (Exception e) {throw new RuntimeException(e);}
}
相关文章:
文件上传和下载(原生JS + SpringBoot实现)
目录 概述 前端编写-上传表单和图片回显 HTML表单代码 发送请求逻辑 CSS代码 后端编写-文件上传接口 后端编写-文件下载接口 概述 在现代Web应用程序中,文件上传和下载是常见的功能。本博客将介绍如何使用原生JS和Spring Boot实现文件上传和下载的功能。 在其…...
【C语言学习笔记】:安全性
用const修饰变量或方法,从而告诉编译器这些都是不可变的,有助于编译器优化代码,并帮助开发人员了解函数是否有副作用。此外,使用const &可以防止编译器复制不必要的数据。John Carmack对const的评论[2]值得一读。 // Bad Ide…...
Linux - 磁盘存储管理 磁盘引入
# 我们要介绍下 磁盘管理, 那不妨先来看一张图来简单 引入 :这张图呢,是我们 Windows 上的磁盘管理的显示 。根据这幅图呢,提出一个问题 :>>> 这幅图磁盘管理所显示的内容,你能判断出 该电脑 有几…...
分割std::string成多个string
文章目录问题描述前置知识解决代码问题描述 假设我们有一个http服务器,此服务器接收客户端发来的http请求,假设请求如下 GET / HTTP/1.1我们怎么将这个Http请求分割成三份,分别存入不同的string中分别处理? 前置知识 首先std::string的本…...
3月多国更新进出口产品规定
【3月多国更新进出口产品规定】2023年3月多项外贸新规实施,涉及欧盟,伊拉克,泰国,孟加拉国,埃及等多国进出口产品限制及海关税则。1. 3月1日起给予埃塞俄比亚等三国98%税目产品零关税待遇中国国务院关税税则委员会17日…...
nacos相关面试题
Nacos是阿里巴巴开源的一款注册中心和配置中心,它能够实现服务的注册、发现和配置管理等功能。Nacos的实现原理主要分为以下几个部分:注册中心:Nacos作为注册中心,通过提供RESTful API的方式对外提供注册和发现服务。它使用基于Ra…...
Linux基础命令-groupmems管理组群的成员
Linux-usermod修改用户 Linux-useradd创建用户 Linux-userdel删除用户 Linux基础命令-chown修改文件属主 Linux基础命令-chmod修改文件权限 groupmems 命令介绍 先来看看这个命令的帮助信息是什么概念 NAME groupmems - administer members of a user’s primary group group…...
css系统化学习
元素的语义化 SEO:搜索引擎优化 根据搜索引擎展示的规律,语义化的元素更容易被展示获得更多浏览量 字符编码 css历史 内联样式(inline) style"内容全写在等号后面,双引号里面,多个之间用;隔开" 内部样式(internal) style写在head里面,在title下面,不是在body内, …...
AI的简单介绍
什么是AI? AI 是 Artificial Intelligent 的缩写,是我们通常意义上说的人工智能。 简单来说就是让机器能够模拟人类的思维能力,让它能够像人一样感知、思考甚至决策。 为什么要开发AI? 因为在过去,都是我们学习机器…...
【Linux】-- 进程间通讯
目录 进程间通讯概念的引入 意义(手段) 思维构建 进程间通信方式 管道 站在用户角度-浅度理解管道 匿名管道 pipe函数 站在文件描述符角度-深度理解管道 管道的特点总结 管道的拓展 单机版的负载均衡 匿名管道读写规则 命名管道 前言 原理…...
STM32模拟SPI时序控制双路16位数模转换(16bit DAC)芯片DAC8552电压输出
STM32模拟SPI时序控制双路16位数模转换(16bit DAC)芯片DAC8552电压输出 STM32部分芯片具有12位DAC输出能力,要实现16位及以上DAC输出需要外挂DAC转换ASIC。 DAC8552是双路16位DAC输出芯片,通过SPI三线总线进行配置控制输出。这里…...
基于intel x86+fpga智能驾驶舱和高级驾驶辅助系统硬件设计(二)
系统功能架构及各模块功能介绍 智能驾驶舱和高级驾驶辅助系统是一个车载智能终端嵌入式平台,系统是一个能够运行 虚拟化操作系统的软件和硬件的综合体。本文的车载主机包括硬件主控处理器、电源管理芯 片、存储设备、输入输出控制器、数字仪表系统系统、后座娱乐系统…...
oneblog_justauth_三方登录配置【Github】
文章目录oneblog添加第三方平台github中创建三方应用完善信息登录oneblog添加第三方平台 1.oneblog管理端,点击左侧菜单 网站管理——>社会化登录配置管理 ,添加一个社会化登录 2.编辑信息如下,选择github平台后复制redirectUri,然后去github获取cl…...
自行车轮胎充气泵PCBA方案
轮胎充气泵PCBA方案由多种元器件设计组合而成,PCBA是英文Printed Circuit Board Assembly 的简称,也就是说PCB空板经过SMT上件,或经过DIP插件的整个制程,简称PCBA。PCBA是一个电子产品功能实现的最原始的状态,未经过任…...
200 22222
101. blob.png 新到组织的项目经理被分配管理一个具有多名干系人的项目。项目经理希望确定哪些干系人是内部的,哪些干系人是外部的。若要了解干系人的角色,项目经理应该查阅哪一份文件? A. 干系人登记册 B. 干系人分析 C. 干系人管理计划 D.…...
<JVM上篇:内存与垃圾回收篇>13 - 垃圾回收器
笔记来源:尚硅谷 JVM 全套教程,百万播放,全网巅峰(宋红康详解 java 虚拟机) 文章目录13.1. GC 分类与性能指标13.1.1. 垃圾回收器概述13.1.2. 垃圾收集器分类13.1.3. 评估 GC 的性能指标13.2. 不同的垃圾回收器概述13.…...
广义状态平均法功率变换器建模分析
两种状态平均法在功率变换器建模的应用比较 [!info] Bibliography [1] 高朝晖, 林辉张晓斌 & 吴小华, “两种状态平均法在功率变换器建模的应用比较,” 计算机仿真, no. 241-244248, 2008. [!note] 状态空间平均法采用直流量近似(线性系统模型)&…...
基于Spring Boot的快递管理系统
文章目录 项目介绍主要功能截图:登录我要收件我要寄件个人信息我收到的我寄出的物流管理用户管理部分代码展示设计总结项目获取方式🍅 作者主页:Java韩立 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项…...
nerdctl不完全使用指南(开发者)
目录 背景 环境配置 1.编译golang可执行文件 2.快速构建镜像 背景 k8s在1.22版本放弃docker作为runtime后采用了containerd,以containerd作为runtime的k8s安装方法已经出现了很多开源集成工具或者解决方案,在此不做赘述。本篇只要是描述在docker被取…...
【独家】华为OD机试 - 分糖果(C 语言解题)
最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南)华为od机试,独家整理 已参加机试人员的实战技巧文章目录 最近更新的博客使用说明本期…...
挑战杯推荐项目
“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 - 个性化梦境…...
多模态2025:技术路线“神仙打架”,视频生成冲上云霄
文|魏琳华 编|王一粟 一场大会,聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中,汇集了学界、创业公司和大厂等三方的热门选手,关于多模态的集中讨论达到了前所未有的热度。其中,…...
C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...
使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台
🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...
html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...
基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...
JavaScript 数据类型详解
JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...
STM32HAL库USART源代码解析及应用
STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...
