文件上传和下载(原生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机试,独家整理 已参加机试人员的实战技巧文章目录 最近更新的博客使用说明本期…...

铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...

工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...
在四层代理中还原真实客户端ngx_stream_realip_module
一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡(如 HAProxy、AWS NLB、阿里 SLB)发起上游连接时,将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后,ngx_stream_realip_module 从中提取原始信息…...

2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...