文件上传和下载(原生JS + SpringBoot实现)

news2024/11/14 11:28:05

目录

概述

前端编写-上传表单和图片回显

 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】表单数据的编码类型enctypemultipart/form-data

【3】需要一个类型typefile的控件<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);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/392104.html

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

相关文章

vue移动端h5,文本溢出显示省略号,且展示‘更多’按钮

问题&#xff1a; 元素宽度100%&#xff0c;宽度会随着浏览器缩放而变化。元素内文本超过4行时显示省略号&#xff0c;同时展示‘更多’按钮&#xff0c;点击更多按钮展示全部文本。如下图所示 超出四行显示省略号(…)的代码 .content{overflow:hidden;text-overflow: elli…

【Spring】入门概述(一)

&#x1f697;Spring学习第一站~ &#x1f6a9;本文已收录至专栏&#xff1a;Spring家族学习之旅 &#x1f44d;希望您能有所收获 一.初识 Spring并不是单一的一个技术&#xff0c;而是一个大家族&#xff0c;发展到今天已经形成了一种开发的生态圈&#xff0c;Spring提供了若…

JavaScript(2)

一、事件 HTML事件是发生在hTML元素上的“事情”。比如&#xff1a;按钮被点击、鼠标移动到元素上等… 事件绑定 方式一&#xff1a;通过HTML标签中的事件属性进行绑定 <input type"button" value"点我" onclick"on()"><script>fun…

C++基础 | 从C到C++快速过渡

一、开发环境 c使用的编译器是g。 vim或者vscodeclionVS 二、C版本的Hello World /*** brief c版本helloworld示例* author Mculover666* date 2023/2/26*/#include <iostream> using namespace std;int main() {int a 1;double b 3.14;char c[] "str…

软件测试用例篇(4)

测试知识回顾: 我们想要根据需求来写测试用例&#xff0c;首先要保证的需求的合理性和正确性&#xff0c;首先要验证需求&#xff0c;需求合理&#xff0c;理解需求&#xff0c;细化需求&#xff0c;把大需求细化成小需求&#xff0c;根据每一个小需求提炼出功能点根据每一个功…

html+css 实现 熊猫样式

效果 html代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><meta http-equiv"X-UA-Compatible"…

【MySQL高级篇】第01章 Linux下MySQL的安装与使用

第01章 Linux下MySQL的安装与使用 1. 安装前说明 1.1 查看是否安装过MySQL 如果你是用rpm安装, 检查一下RPM PACKAGE&#xff1a; rpm -qa | grep -i mysql # -i 忽略大小写检查mysql service&#xff1a; systemctl status mysqld.service1.2 MySQL的卸载 1. 关闭 mysql …

工控机ARM工业边缘计算机搭建Node-Red环境

搭建Node-Red环境Node-RED是一个基于Node.js的开源可视化流程编程环境&#xff0c;可以轻松构建自定义应用程序&#xff0c;通过连接简单的节点来完成复杂的任务。Node-RED提供了一种简单的方法&#xff0c;可以快速连接到外部服务&#xff0c;从而实现物联网应用的开发。Node-…

乡村企业门户网站

技术&#xff1a;Java、JSP等摘要&#xff1a;随着时代的发展&#xff0c;电脑与Internet已经进入我们的生活。信息时代的来临&#xff0c;知识经济的扩张&#xff0c;网站已越来越靠近我们的生活。据CNNIC报告显示&#xff0c;中国上网用户有6800万。通过Internet来经营运作一…

寻找时空中的引力波:科学家控制量子运动至量子基态

据英国每日邮报报道&#xff0c;时空织布里的涟漪或可以揭示宇宙在140亿年前是如何产生的&#xff0c;然而寻找这些名为“引力波”的涟漪却一直难以捉摸。现在美国科学家们声称他们发现了改善用于检测宇宙大爆炸的引力波的探测器的方法。 ​宇宙大爆炸残留的引力波 美国加州理…

电脑文件软件搬家迁移十大工具

10 大适用于 Windows 的数据迁移软件。 数据迁移至关重要&#xff0c;几乎所有组织都依赖于此。如果您认为数据传输不是一件容易的事&#xff0c;那么数据迁移软件可以帮上忙。 1、奇客电脑迁移 将现有操作系统、软件、文件迁移到 新电脑的最佳方法之一是使用名为奇客电脑迁移…

SpringMvc快速启动

Spring快速启动 1、tomcat配置 仔细查看下图标记位置配置 添加Tomcat server时选择LocalApplcation server选择Http port与JMX port 2、Project Structure 打开FIle -> Project Structure&#xff0c; 确认WEB-INFO下是否添加了lib&#xff0c;并将.jar包加入lib包中 …

mysql 主从复制 双主双从

master4: 配置 ./etc/my.cnf #主服务器唯一Id server-id4 #启用二进制日志[必填] #log-bin自己mysql的路径/mysqlbin #主机&#xff0c;0:读写,1:只读 read-only0 #忽略不需要同步的数据库 #binlog-ignore-dbmysql #需要同步的数据库:数据库名 binlog-do-dbtest #作为从库…

糖化学类854262-01-4,Propargyl α-D-Mannopyranoside,炔丙基 α-D-吡喃甘露糖苷

外观以及性质&#xff1a;Propargyl α-D-Mannopyranoside一般为白色粉末状&#xff0c;糖化学类产品比较多&#xff0c;一般包括&#xff1a;葡萄糖衍生物、葡萄糖醛酸衍生物&#xff0c;氨基甘露糖衍生物、半乳糖衍生物、氨基半乳糖衍生物、核糖衍生物、阿拉伯糖衍生物、唾液…

童流感诊治最新共识,专家全面解读

流感高发季节已经到来&#xff0c;孩子们接种疫苗吗&#xff1f;流感是人类面临的主要公共健康问题之一&#xff0c;儿童是流感的高危人群和严重病例的高危人群。近日&#xff0c;中华医学会呼吸病学年会第22届全国呼吸病学学术会议在福建厦门召开。会上&#xff0c;首都医科大…

Vue(1)-vue核心

1.Vue核心 【课程链接】 目录1.Vue核心1.1.Vue介绍1.1.1.官网1.1.2.介绍与描述1.1.3.Vue 的特点1.1.4.与其它 JS 框架的关联1.1.5.Vue 周边库1.2.初识vue1.3.Vue模板1.4.数据绑定1.5.el和data的两种写法1.6.MVVM模型1.7.数据代理1.7.1.回顾Object.defineProperty方法1.7.2.理解…

C++单例模式实现

目录 1.提出的需求 ​​​​​​​2.如何定义一个类&#xff0c;使得这个类最多只能创建一个对象&#xff1f; ​​​​​​​3.代码 ​​​​​​​4.小结 C/CLinux服务器开发/后台架构师【零声教育】-学习视频教程-腾讯课堂 ​​​​​​​1.提出的需求 在架构设计时&am…

有什么比较好的bug管理工具?5款热门工具推荐

工具再优秀&#xff0c;适合自己才最重要。 为尽量讲透这个问题&#xff0c;本文的行文结构我先整理如下&#xff1a; 1、为什么需要bug管理工具&#xff1f; 2、好的bug管理工具的标准是什么&#xff1f; 3、好的bug管理工具推荐&#xff08;5款&#xff09; 4、如何挑选适合…

【SpringCloud】SpringCloud教程之Nacos实战(一)

目录Nacos是什么&#xff1f;一.Nacos下载二.安装Nacos三.Nacos原理四.Nacos快速入门五.Nacos服务多级存储模式六.Nacos根据集群设置负载均衡1.根据同集群优先访问2.根据权重配置负载均衡七.Nacos的环境隔离八.Nacos和Eureka的区别前提&#xff1a;以订单服务和用户服务为例&am…

HyperLPR3车牌识别-Android使用:SDK编译与部署

简介HyperLPR在2023年初已经更新到了v3的版本&#xff0c;该版本与先前的版本一样都是用于识别中文车牌的开源图像算法项目&#xff0c;最新的版本的源码可从github中提取&#xff1a;https://github.com/szad670401/HyperLPRAndroid SDK for HyperLPR3说明HyperLPR3的官方源码…