SpringMVC上传下载文件解读

知识点

文件上传(File Upload):

  1. 创建一个控制器方法,使用 MultipartFile 参数来接收上传的文件。
  2. 在 Spring 配置文件中配置一个 MultipartResolver,常用的实现类是 CommonsMultipartResolver。
  3. 在 MultipartResolver 的配置中设置最大允许上传文件的大小。
  4. 在控制器方法中,使用 MultipartFile 的方法获取上传文件的信息,如文件名、大小、内容等。
  5. 使用 MultipartFile 的 transferTo() 方法将上传的文件保存到指定位置。

文件下载(File Download):

  1. 创建一个控制器方法,返回类型为 ResponseEntity<byte[]>,表示要下载的文件。
  2. 使用 HttpHeaders 类设置响应的头信息,包括文件名、文件类型等。
  3. 使用 Java IO 或其他工具类读取要下载的文件,并将内容设置到 ResponseEntity<byte[]> 中的字节数组中。
  4. 将包含文件内容和响应头信息的 ResponseEntity<byte[]> 对象作为控制器方法的返回值。

实现步骤

首先,在前端需要定义一个HTML表单来实现上传文件的功能:

<form action="upload" method="post" enctype="multipart/form-data">
    <input type="file" name="file"/>
    <button type="submit">上传文件</button>
</form>

注意,表单的enctype属性必须设置为multipart/form-data,否则无法上传文件。

接下来,在后端需要编写控制器方法来处理上传文件的请求:

@Controller
public class FileController {

    @RequestMapping(value = "/upload", method = RequestMethod.POST)
    public String upload(@RequestParam("file") MultipartFile file) throws IOException {
        // 获取上传文件的名称
        String fileName = file.getOriginalFilename();
        // 文件保存路径
        String filePath = "path/to/save/" + fileName;
        // 将文件保存到磁盘上
        file.transferTo(new File(filePath));
        return "redirect:/success.html";
    }
}

在上述代码中,@RequestParam("file")注解表示获取名为file的上传文件。MultipartFile类是Spring提供的文件上传类,可以通过该类的方法获取上传文件的名称、大小等属性,并将文件保存到磁盘上。

在后端下载文件时,我们需要编写一个控制器方法来返回文件的字节数组:

@Controller
public class FileController {

    @RequestMapping("/download")
    public ResponseEntity<byte[]> download() throws IOException {
        // 获取要下载的文件路径
        String filePath = "path/to/download/file";
        // 读取文件内容到字节数组中
        byte[] bytes = Files.readAllBytes(Paths.get(filePath));
        // 构造响应头部信息,包括下载文件名和文件类型
        HttpHeaders headers = new HttpHeaders();
        headers.setContentDispositionFormData("attachment", "filename.txt");
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        // 返回字节数组和响应头部信息
        return new ResponseEntity<>(bytes, headers, HttpStatus.OK);
    }
}

在上述代码中,通过Files.readAllBytes()方法将文件内容读取到字节数组中,并使用ResponseEntity<byte[]>类封装字节数组和响应头部信息,最终返回给客户端进行下载。

在前端需要定义一个下载链接,用于触发下载文件的操作:

<a href="download">下载</a>

当用户点击该链接时,浏览器会发送一个请求到服务器,调用上述控制器方法来返回文件内容。浏览器会根据响应头部信息,自动弹出保存文件的对话框,让用户选择保存文件的位置。

可直接使用的Demo示例

@Controller
public class FileController {
    /**
     * 文件上传
     */
    @RequestMapping("fileload")
    public String fileLoad(MultipartFile[] files,
                             HttpServletRequest request) throws Exception {
        //设置上传的文件所存放的路径
        String path = request.getServletContext().getRealPath("/") + "files/";
        ObjectMapper mapper = new ObjectMapper();
        if (files != null && files.length > 0) {
            //循环获取上传的文件
            for (MultipartFile file : files) {
                //获取上传文件的名称
                String filename = file.getOriginalFilename();
                ArrayList<Resource> list = new ArrayList<>();
                //读取files.json文件中的文件名称
                String json = JSONFileUtils.readFile(path + "/files.json");
                if (json.length() != 0) {
                    //将files.json的内容转为集合
                    list = mapper.readValue(json,
                            new TypeReference<List<Resource>>() {
                            });
                    for (Resource resource : list) {
                        //如果上传的文件在files.json文件中有同名文件,将当前上传的文件重命名,以避免重名
                        if (filename.equals(resource.getName())) {
                            String[] split = filename.split("\\.");
                            filename = split[0] + "(1)." + split[1];
                        }
                    }
                }
                // 文件保存的全路径
                String filePath = path + filename;
                // 保存上传的文件
                file.transferTo(new File(filePath));
                list.add(new Resource(filename));
                json = mapper.writeValueAsString(list); //将集合中转换成json
                //将上传文件的名称保存在files.json文件中
                JSONFileUtils.writeFile(json, path + "/files.json");
            }
            request.setAttribute("msg", "(上传成功)");
            return "forward:fileload.jsp";
        }
        request.setAttribute("msg", "(上传失败)");
        return "forward:fileload.jsp";
    }

    @ResponseBody
    @RequestMapping(value = "/getFilesName",
            produces = "text/html;charset=utf-8")
    public String getFilesName(HttpServletRequest request,
                               HttpServletResponse response) throws Exception {
        String path = request.getServletContext().
                getRealPath("/") + "files/files.json";
        String json = JSONFileUtils.readFile(path);
        return json;
    }

    /**
     * 根据浏览器的不同进行编码设置,返回编码后的文件名
     */
    public String getFileName(HttpServletRequest request,
                              String filename) throws Exception {
        BASE64Encoder base64Encoder = new BASE64Encoder();
        String agent = request.getHeader("User-Agent");
        if (agent.contains("Firefox")) {
            // 火狐浏览器
            filename = "=?UTF-8?B?" + new String
                    (base64Encoder.encode(filename.getBytes("UTF-8"))) + "?=";
        } else {
            // IE及其他浏览器
            filename = URLEncoder.encode(filename, "UTF-8");
        }
        return filename;
    }

    /**
     * 文件下载
     */
    @RequestMapping("/download")
    public ResponseEntity<byte[]> fileDownload(HttpServletRequest request,
                                               String filename) throws Exception {
        System.out.println("123");
        System.out.println(filename);
        filename = java.net.URLDecoder.decode(filename, "utf-8");
        System.out.println(filename);
        // 指定要下载的文件所在路径
        String path = request.getServletContext().getRealPath("/files/");

        // 创建该文件对象
        System.out.println(filename);
        File file = new File(path + File.separator + filename);
        // 设置响应头
        HttpHeaders headers = new HttpHeaders();
        filename = this.getFileName(request, filename);
        // 通知浏览器以下载的方式打开文件
        headers.setContentDispositionFormData("attachment", filename);
        // 定义以流的形式下载返回文件数据
        System.out.println(filename);
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        // 使用Sring MVC框架的ResponseEntity对象封装返回下载数据
        return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),
                headers, HttpStatus.OK);
    }


}

文件上传功能:

文件上传方法名为 fileLoad,通过 @RequestMapping 注解指定了请求地址为 "fileload"。该方法使用了 Spring 框架提供的 MultipartFile 类型来接收上传的文件,同时通过 HttpServletRequest 对象获取当前请求的上下文路径,并在该路径下创建一个名为 "files" 的文件夹用于保存上传的文件。该方法还使用了 Jackson 库中的 ObjectMapper 类将集合对象转化为 JSON 格式字符串,并通过封装好的 JSONFileUtils 工具类写入到 files.json 文件中保存。

文件下载功能:

文件下载方法名为 fileDownload,通过 @RequestMapping 注解指定了请求地址为 "download"。该方法通过 HttpServletRequest 对象获取当前请求的上下文路径,然后构造一个文件对象,通过 ResponseEntity 类型封装该文件返回给客户端进行下载。在该方法中还有一个 getFileName 方法,用于在不同浏览器中对文件名进行编码处理,避免出现乱码问题。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>文件上传和下载</title>
    <script src="${ pageContext.request.contextPath }/js/jquery-3.6.0.js" type="text/javascript"></script>
</head>
<body>
<table border="1">
    <tr>
        <td width="200" align="center">文件上传${msg}</td>
        <td width="300" align="center">下载列表</td>
    </tr>
    <tr>
        <td height="100">
            <form action="${pageContext.request.contextPath}/fileload"
                  method="post" enctype="multipart/form-data">
                <input type="file" name="files" multiple="multiple"><br/>
                <input type="reset" value="清空"/>
                <input type="submit" value="提交"/>
            </form>
        </td>
        <td id="files"></td>
    </tr>
</table>
</body>
<script>
    $(document).ready(function () {
        var url = "${pageContext.request.contextPath }/getFilesName";
        $.get(url, function (files) {
            var files = eval('(' + files + ')');

            for (var i = 0; i < files.length; i++) {
                result=files[i].name
                files[i].name=encodeURI(files[i].name);
                files[i].name=encodeURI(files[i].name);
                $("#files").append("<li>" +
                    "<a href=${pageContext.request.contextPath }" + "" +
                    "\\" + "download?filename=" + files[i].name + ">" +
                    result + "</a></li>");
            }
        })
    })
</script>
</html>

页面包含一个表格,其中第一行为文件上传的部分,第二行为文件下载列表的部分。在文件上传的部分,用户可以选择要上传的文件,并通过提交按钮将文件上传到服务器。在文件下载列表的部分,页面通过 AJAX 异步请求获取服务器端返回的文件列表数据,并使用 jQuery 库对数据进行处理和展示。

<script> 标签中的 JavaScript 代码中,首先通过 $.get() 方法发送 GET 请求获取服务器返回的文件列表数据,然后遍历文件列表,将每个文件的名称作为链接展示在页面上。点击链接时,会跳转到下载功能的地址,并将文件名作为参数传递给下载功能。需要注意的是,为了避免文件名中的特殊字符引起的问题,JavaScript 代码中使用了 encodeURI() 方法对文件名进行编码处理。

演示具体:

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

PyTorch官网demo解读——第一个神经网络(1)

神经网络如此神奇&#xff0c;feel the magic 今天分享一下学习PyTorch官网demo的心得&#xff0c;原来实现一个神经网络可以如此简单/简洁/高效&#xff0c;同时也感慨PyTorch如此强大。 这个demo的目的是训练一个识别手写数字的模型&#xff01; 先上源码&#xff1a; fr…

crmeb v5新增一个功能的完整示例记录

首先&#xff0c;需求 工作中的二开需求是这样的&#xff0c;修改首页的装修&#xff0c;并新增回收报价的功能 开始动手 第一步&#xff0c;我们要到后面的管理界面&#xff0c;去装修中修改首面的展示 首页的页面配置好之后&#xff0c;就要在 前端的展示程序中 配置相…

105基于matlab的阶次分析算法

基于matlab的阶次分析算法&#xff0c;用于变转速机械故障特征提取&#xff0c;可运行&#xff0c;包含寻找脉冲时刻&#xff0c;等角度时刻。数据可更换自己的&#xff0c;程序已调通&#xff0c;可直接运行。 105阶次分析变转速信号处理 (xiaohongshu.com)

二十七、读写文件

二十七、读写文件 27.1 文件类QFile #include <QCoreApplication>#include<QFile> #include<QDebug>int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);QFile file("D:/main.txt");if(!file.open(QIODevice::WriteOnly | QIODe…

Arrays.asList()方法:陷阱与解决之道

在Java编程中&#xff0c;Arrays类提供了一系列用于操作数组的实用方法。其中&#xff0c;​Arrays.asList()​方法是一个常用的方法&#xff0c;用于快速将数组转换为List集合。然而&#xff0c;这个方法存在一些潜在的陷阱&#xff0c;可能导致出现意外的行为。本文将介绍​A…

数据可视化---柱状图

import matplotlib.pyplot as plt import numpy as npdef plot_bar_chart(data, labels, colorsNone, title"Bar Chart", xlabel"X-Axis", ylabel"Y-Axis"):"""绘制柱状图&#xff0c;并在柱子上显示数量和比例。:param data: 包…

【C++11特性篇】C++11中新增的initializer_list——初始化的小利器(2)

前言 大家好吖&#xff0c;欢迎来到 YY 滴C11系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; 目录 一.探究std::initializer_list是什么…

OceanBase 4.2.1社区版 最小资源需求安装方式

OceanBase 4.2.1社区版 最小资源需求安装方式 资源需求 资源需求分析 observer Memory 控制参数&#xff1a; memory_limit_percentage 默认80% memory_limit 直接设定observer Memory 大小 System memory 可设为1G 租户内存:sys租户内存设为1G&#xff0c;OCP需要的租户oc…

Mac brew install youtube-dl 【 youtube 下载工具:youtube-dl 安装】

文章目录 1. 简介2. 预备3. 安装4. 命令5. 测试 1. 简介 youtube-dl - 从youtube.com或其他视频平台下载视频 https://github.com/ytdl-org/youtube-dl 2. 预备 安装并配置 git安装 brew 3. 安装 MacBook-Pro ~ % brew install youtube-dl Warning: youtube-dl has been …

【Java系列】详解多线程(三)—— 线程安全(上篇)

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【Java系列专栏】【JaveEE学习专栏】 本专栏旨在分享学习Java的一点学习心得&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 一…

基于EasyExcel的数据导入导出

前言&#xff1a; 代码复制粘贴即可用&#xff0c;主要包含的功能有Excel模板下载、基于Excel数据导入、Excel数据导出。 根据实际情况修改一些细节即可&#xff0c;最后有结果展示&#xff0c;可以先看下结果&#xff0c;是否是您想要的。 台上一分钟&#xff0c;台下60秒&a…

OSG中几何体的绘制(二)

5. 几何体操作 在本章的前言中就讲到&#xff0c;场景都是由基本的绘图基元构成的&#xff0c;基本的绘图基元构成简单的几何体,简单的几何体构成复杂的几何体&#xff0c;复杂的几何体最终构造成复杂的场景。当多个几何体组合时&#xff0c;可能存在多种降低场景渲染效率的原因…

SQL进阶理论篇(七):B+树的查询及存储机制

文章目录 简介数据库中的存储结构数据库中的页结构从数据页来看B树的查询过程总结参考文献 简介 我们之前已经了解过数据库的B树索引和Hash索引&#xff0c;这些索引信息以及数据记录都是保存在文件里的&#xff0c;确切的说是存储在页结构中。 本节&#xff0c;从我们将了解…

【LeetCode刷题】-- 161.相隔为1的编辑距离

161.相隔为1的编辑距离 方法&#xff1a;一次遍历 首先&#xff0c;我们要确认字符串的长度不会相差太远。如果长度差了2个或更多字符&#xff0c;那么 s 和 t 就不可能是一次编辑之差的字符串。 接下来&#xff0c;我们假设 s 的长度总是短于或等于 t 的长度。如果不是这样&…

cesium 自定义贴图,shadertoy移植教程。

1.前言 cesium中提供了一些高级的api&#xff0c;可以自己写一些shader来制作炫酷的效果。 ShaderToy 是一个可以在线编写、测试和分享图形渲染着色器的网站。它提供了一个图形化的编辑器&#xff0c;可以让用户编写基于 WebGL 的 GLSL 着色器代码&#xff0c;并实时预览渲染结…

大数据存储技术(3)—— HBase分布式数据库

目录 一、HBase简介 &#xff08;一&#xff09;概念 &#xff08;二&#xff09;特点 &#xff08;三&#xff09;HBase架构 二、HBase原理 &#xff08;一&#xff09;读流程 &#xff08;二&#xff09;写流程 &#xff08;三&#xff09;数据 flush 过程 &#xf…

配置802.1x认证

实验目的&#xff1a; 某公司拥有两个部门&#xff0c;市场部和人事部门&#xff0c;市场部和人事部的IP地址分别为10.1.11.0/24、10.1.21.0/24两个IP网段。市场部属于vlan11&#xff0c;人事部属于vlan21。现在需要在SW2上配置802.1x认证&#xff0c;实现终端用于只有认证成功…

BKP 备份寄存器 RTC 实时时钟-stm32入门

这一章节我们要讲的主要内容是 RTC 实时时钟&#xff0c;对应手册&#xff0c;是第 16 章的位置。 实时时钟这个东西&#xff0c;本质上是一个定时器&#xff0c;但是这个定时器&#xff0c;是专门用来产生年月日时分秒&#xff0c;这种日期和时间信息的。所以学会了 STM32 的…

Flink系列之:SQL提示

Flink系列之&#xff1a;SQL提示 一、动态表选项二、语法三、例子四、查询提示五、句法六、加入提示七、播送八、随机散列九、随机合并十、嵌套循环十一、LOOKUP十二、进一步说明十三、故障排除十四、连接提示中的冲突案例十五、什么是查询块 SQL 提示可以与 SQL 语句一起使用来…

【卡塔尔世界杯数据可视化与新闻展示】

卡塔尔世界杯数据可视化与新闻展示 前言数据获取与处理可视化页面搭建功能实现新闻信息显示详情查看登录注册评论信息管理 创新点结语 前言 随着卡塔尔世界杯的临近&#xff0c;对于足球爱好者来说&#xff0c;对比赛的数据分析和新闻报道将成为关注的焦点。本文将介绍如何使用…