最全面的Spring教程(五)——文件上传与下载

news/2024/5/3 8:41:05/文章来源:https://blog.csdn.net/qq_42146402/article/details/128045997

前言

在这里插入图片描述

本文为 【SpringMVC教程】文件上传与下载 相关知识,具体将对使用MultipartResolver处理文件上传的步骤,两种文件下载方式(直接向response的输出流中写入对应的文件流、使用 ResponseEntity<byte[]>来向前端返回文件)等进行详尽介绍~

📌博主主页:小新要变强 的主页
👉Java全栈学习路线可参考:【Java全栈学习路线】最全的Java学习路线及知识清单,Java自学方向指引,内含最全Java全栈学习技术清单~
👉算法刷题路线可参考:算法刷题路线总结与相关资料分享,内含最详尽的算法刷题路线指南及相关资料分享~
👉Java微服务开源项目可参考:企业级Java微服务开源项目(开源框架,用于学习、毕设、公司项目、私活等,减少开发工作,让您只关注业务!)

↩️本文上接:最全面的SpringMVC教程(四)——Controller 与 RestFul


目录

文章标题

  • 前言
  • 目录
  • 一、文件上传
  • 二、文件下载
    • 1️⃣传统方式
    • 2️⃣使用ResponseEntity方式
  • 后记

在这里插入图片描述

文件上传是项目开发中最常见的功能之一 ,SpringMVC 可以很好的支持文件上传,但是SpringMVC上下文中默认没有装配MultipartResolver,因此默认情况下其不能处理文件上传工作。如果想使用Spring的文件上传功能,则需要在上下文中配置MultipartResolver。

前端表单要求:为了能上传文件,必须将表单的method设置为POST,并将enctype设置为multipart/form-data。只有在这样的情况下,浏览器才会把用户选择的文件以二进制数据发送给服务器。

<form action="" enctype="multipart/form-data" method="post"><input type="file" name="file"/><input type="submit">
</form>

表单中enctype属性的详细说明:

  • application/x-www=form-urlencoded:默认方式,只处理表单域中的 value 属性值,采用这种编码方式的表单会将表单域中的值处理成 URL 编码方式。
  • multipart/form-data:这种编码方式会以二进制流的方式来处理表单数据,这种编码方式会把文件域指定文件的内容也封装到请求参数中,不会对字符编码。
  • text/plain:除了把空格转换为 “+” 号外,其他字符都不做编码处理,这种方式适用直接通过表单发送邮件。

一旦设置了enctypemultipart/form-data,浏览器即会采用二进制流的方式来处理表单数据,而对于文件上传的处理则涉及在服务器端解析原始的HTTP响应。在2003年,Apache Software Foundation发布了开源的Commons FileUpload组件,其很快成为Servlet/JSP程序员上传文件的最佳选择。

  • Servlet3.0规范已经提供方法来处理文件上传,但这种上传需要在Servlet中完成。而Spring MVC则提供了更简单的封装。
  • Spring MVC为文件上传提供了直接的支持,这种支持是用即插即用的MultipartResolver实现的。
  • Spring MVC使用Apache Commons FileUpload技术实现了一个MultipartResolver实现类:CommonsMultipartResolver。因此,SpringMVC的文件上传还需要依赖Apache Commons FileUpload的组件。

一、文件上传

【MultipartResolver】用于处理文件上传。当收到请求时,DispatcherServlet 的 checkMultipart() 方法会调用 MultipartResolver 的 isMultipart() 方法判断请求中【是否包含文件】。如果请求数据中包含文件,则调用 MultipartResolver 的 resolveMultipart() 方法对请求的数据进行解析,然后将文件数据解析成 MultipartFile 并封装在 MultipartHttpServletRequest (继承了 HttpServletRequest) 对象中,最后传递给 Controller。

我们可以看到DispatcherServlet的核心方法中第一句就是如下的代码:

try {processedRequest = checkMultipart(request);multipartRequestParsed = (processedRequest != request);...

注意: MultipartResolver 默认不开启,需要手动开启。

文件上传对前端表单有如下要求:为了能上传文件,必须将表单的【method设置为POST】,并将enctype设置为【multipart/form-data】。只有在这样的情况下,浏览器才会把用户选择的文件以二进制数据发送给服务器。

对表单中的 enctype 属性的详细说明:

  • application/x-www-form-urlencoded:默认方式,只处理表单域中的 value 属性值,采用这种编码方式的表单会将表单域中的值处理成 URL 编码方式。
  • multipart/form-data:这种编码方式会以二进制流的方式来处理表单数据,这种编码方式会把文件域指定文件的内容也封装到请求参数中,不会对字符编码。
<form action="" enctype="multipart/form-data" method="post"><input type="file" name="file"/><input type="submit">
</form>

一旦设置了enctypemultipart/form-data,浏览器即会采用二进制流的方式来处理表单数据,而对于文件上传的处理则涉及在服务器端解析原始的HTTP响应。

🍀(1)导入这个【commons-fileupload】jar包,Maven会自动帮我们导入它的依赖包【commons-io】

<!--文件上传-->
<dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.3.3</version>
</dependency>

🍀(2)配置bean:multipartResolver

注意: 这个bena的id必须为:multipartResolver , 否则上传文件会报400的错误!

<!--文件上传配置-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"><!-- 请求的编码格式,必须和jSP的pageEncoding属性一致,以便正确读取表单的内容,默认为ISO-8859-1 --><property name="defaultEncoding" value="utf-8"/><!-- 上传文件大小上限,单位为字节(10485760=10M) --><property name="maxUploadSize" value="10485760"/><property name="maxInMemorySize" value="40960"/>
</bean>

CommonsMultipartFile 的常用方法:

  • String getOriginalFilename():获取上传文件的原名
  • InputStream getInputStream():获取文件流
  • void transferTo(File dest):将上传文件保存到一个目录文件中

🍀(3)编写前端页面

<form action="/upload" enctype="multipart/form-data" method="post"><input type="file" name="file"/><input type="submit" value="upload">
</form>

🍀(4)编写Controller类

package com.wang.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
@Controller
public class FileController {//@RequestParam("file") 将name=file控件得到的文件封装成CommonsMultipartFile 对象//批量上传CommonsMultipartFile则为数组即可@RequestMapping("/upload")public String fileUpload(@RequestParam("file") CommonsMultipartFile file , HttpServletRequest request) throws IOException {//获取文件名 : file.getOriginalFilename();String uploadFileName = file.getOriginalFilename();//如果文件名为空,直接回到首页!if ("".equals(uploadFileName)){return "redirect:/index.jsp";}System.out.println("上传文件名 : "+uploadFileName);//上传路径保存设置String path = request.getServletContext().getRealPath("/upload");//如果路径不存在,创建一个File realPath = new File(path);if (!realPath.exists()){realPath.mkdir();}System.out.println("上传文件保存地址:"+realPath);InputStream is = file.getInputStream(); //文件输入流OutputStream os = new FileOutputStream(new File(realPath,uploadFileName)); //文件输出流//读取写出int len=0;byte[] buffer = new byte[1024];while ((len=is.read(buffer))!=-1){os.write(buffer,0,len);os.flush();}os.close();is.close();return "redirect:/index.jsp";}
}

🍀(5)测试上传文件

🍀(6)采用file.Transto 来保存上传的文件

编写Controller类:

/** 采用file.Transto 来保存上传的文件*/
@RequestMapping("/upload2")
public String  fileUpload2(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {//上传路径保存设置String path = request.getServletContext().getRealPath("/upload");File realPath = new File(path);if (!realPath.exists()){realPath.mkdir();}//上传文件地址System.out.println("上传文件保存地址:"+realPath);//通过CommonsMultipartFile的方法直接写文件(注意这个时候)file.transferTo(new File(realPath +"/"+ file.getOriginalFilename()));return "redirect:/index.jsp";
}

小知识: 我们在文件上传可以考虑以下几点:

  • (1)文件的原始信息,或者叫文件的元数据是不是可以存在数据库,具体应该怎么做?
  • (2)文件的上传目录能不能写在配置文件当中,这个应该怎么做?
  • (3)文件上传到服务器后可不可以安装一定的规则分目录存储,比如日期?
  • (4)思考怎么使用阿里云的oss进行图片存储?

二、文件下载

  • 第一种可以直接向response的输出流中写入对应的文件流
  • 第二种可以使用 ResponseEntity<byte[]>来向前端返回文件

1️⃣传统方式

文件下载步骤:

  • (1)设置 response 响应头
  • (2)读取文件 — InputStream
  • (3)写出文件 — OutputStream
  • (4)执行操作
  • (5)关闭流 (先开后关)
@GetMapping("/download1")
@ResponseBody
public R download1(HttpServletResponse response){FileInputStream fileInputStream = null;ServletOutputStream outputStream = null;try {// 这个文件名是前端传给你的要下载的图片的id// 然后根据id去数据库查询出对应的文件的相关信息,包括url,文件名等String  fileName = "wang.jpg";//1、设置response 响应头,处理中文名字乱码问题response.reset(); //设置页面不缓存,清空bufferresponse.setCharacterEncoding("UTF-8"); //字符编码response.setContentType("multipart/form-data"); //二进制传输数据//设置响应头,就是当用户想把请求所得的内容存为一个文件的时候提供一个默认的文件名。//Content-Disposition属性有两种类型:inline 和 attachment //inline :将文件内容直接显示在页面 //attachment:弹出对话框让用户下载具体例子:response.setHeader("Content-Disposition","attachment;fileName="+ URLEncoder.encode(fileName, "UTF-8"));// 通过url获取文件File file = new File("D:/upload/"+fileName);//2、 读取文件--输入流fileInputStream = new FileInputStream(file);//3、 写出文件--输出流outputStream = response.getOutputStream();byte[] buffer = new byte[1024];int len;//4、执行写出操作while ((len = fileInputStream.read(buffer)) != -1){outputStream.write(buffer,0,len);outputStream.flush();}return R.success();} catch (IOException e) {e.printStackTrace();return R.fail();}finally {if( fileInputStream != null ){try {// 5、关闭输入流fileInputStream.close();} catch (IOException e) {e.printStackTrace();}}if( outputStream != null ){try {// 5、关闭输出流outputStream.close();} catch (IOException e) {e.printStackTrace();}}}
}

2️⃣使用ResponseEntity方式

@GetMapping("/download2")
public ResponseEntity<byte[]> download2(){try {String fileName = "wang.jpg";byte[] bytes = FileUtils.readFileToByteArray(new File("D:/upload/"+fileName));HttpHeaders headers=new HttpHeaders();// Content-Disposition就是当用户想把请求所得的内容存为一个文件的时候提供一个默认的文件名。headers.set("Content-Disposition","attachment;filename="+ URLEncoder.encode(fileName, "UTF-8"));headers.set("charsetEncoding","utf-8");headers.set("content-type","multipart/form-data");ResponseEntity<byte[]> entity=new ResponseEntity<>(bytes,headers, HttpStatus.OK);return entity;} catch (IOException e) {e.printStackTrace();return null;}
}

后记

在这里插入图片描述
👉Java全栈学习路线可参考:【Java全栈学习路线】最全的Java学习路线及知识清单,Java自学方向指引,内含最全Java全栈学习技术清单~
👉算法刷题路线可参考:算法刷题路线总结与相关资料分享,内含最详尽的算法刷题路线指南及相关资料分享~

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

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

相关文章

智慧城市运营中心建设方案(SCOC)智慧城市的心脏

一、大数据&#xff1a;智慧城市的基础与引擎 中国每天正以消失100个村庄的速度快速步入城镇化&#xff0c;未来10年内将有5亿以上的人涌入城市。这无疑会给城市的建设带来巨大的压力&#xff0c;城市资源有限&#xff0c;规模不可能无限扩张&#xff0c;城市在就业、教育、住房…

HashMap底层数据结构,扩容机制

HashMap的底层结构是数组链表 没有哈希冲突的元素放在数组里面&#xff0c; 哈希冲突的元素用链表串起来 初始数组长度是16&#xff0c;对应源码&#xff1a; static final int DEFAULT_INITIAL_CAPACITY1; 最大的容量为2的30次方&#xff0c;一个很大很大很大的数 还定义了…

多个JDK版本可以吗:JDK17、JDK19、JDK1.8轻松切换(无坑版)小白也可以看懂

多个版本JDK切换 多个JDK&#xff1a;JDK17、JDK19、JDK1.8轻松切换&#xff08;无坑版&#xff09;小白也可以看懂 提示&#xff1a;看了网上很多教程&#xff0c;5w观看、32w观看、几千观看的&#xff0c;多多少少带点坑&#xff0c;这里我就把踩过的坑都给抹了 文章目录多个…

【数据结构】二叉树的运算

********************************************************************************************************* 本文作者科大MF22某班Noah懒羊羊同学&#xff0c;为大家提供一个作业思路&#xff0c;请勿直接copy&#xff01;&#xff01;&#xff01;一起进步学习~ ******…

极值分析:分块极大值BLOCK-MAXIMA、阈值超额法、广义帕累托分布GPD拟合降雨数据时间序列...

全文链接&#xff1a;http://tecdat.cn/?p25348 你们可能知道&#xff0c;实际极值分析有两种常用方法&#xff1a;分块极大值Block-maxima、阈值超额法threshold excess&#xff08;点击文末“阅读原文”获取完整代码数据&#xff09;。今天&#xff0c;我们将分别介绍这两种…

【毕业设计】10-基于单片机的车站安检门_磁性霍尔传感器系统设计(原理图+源码+仿真工程+答辩论文)

【毕业设计】10-基于单片机的车站安检门/磁性霍尔传感器系统设计&#xff08;原理图源码仿真工程答辩论文&#xff09; 文章目录【毕业设计】10-基于单片机的车站安检门/磁性霍尔传感器系统设计&#xff08;原理图源码仿真工程答辩论文&#xff09;任务书设计说明书摘要设计框架…

【数据结构】Java实现数据结构的前置知识,时间复杂度空间复杂度,泛型类的讲解

文章目录数据结构时间复杂度、空间复杂度包装类、装箱与拆箱泛型擦除机制数据结构 当我们在成为一名程序员的这条道路上努力的时候&#xff0c;我们一定经常听到这个词数据结构。那么究竟什么是数据结构呢&#xff1f;数据结构顾名思义&#xff0c;就是数据结构&#xff0c;数…

【深度学习】详解 CLIP

目录 摘要 一、引言和激励性工作 二、方法 2.1 自然语言监督 2.2 创建一个足够大的数据集 2.3 选择一种有效的预训练方法 2.4 选择和放缩一个模型 2.5 训练 三、实验 3.1 零次迁移 3.1.1 激励 Github&#xff1a;GitHub - openai/CLIP: Contrastive Language-Image …

Android 导航之Navigation 组件的介绍与使用

1、介绍&#xff1a; 在以前的应用中&#xff0c;针对多导航模块的使用&#xff0c;常见的有tabhost或者FragmentTabHost&#xff0c;但是这些在使用的过程中&#xff0c;非常臃肿&#xff0c;包括加载和管理也不如人意。在AndroidX中&#xff0c;官方引入Navigation模块&#…

Spring | IOC技术之Bean的配置与实例化

&#x1f451; 博主简介&#xff1a;    &#x1f947; Java领域新星创作者    &#x1f947; 阿里云开发者社区专家博主、星级博主、技术博主 &#x1f91d; 交流社区&#xff1a;BoBooY&#xff08;优质编程学习笔记社区&#xff09; 文章目录Bean的基础配置1、id 与 cla…

Anaconda默认安装在C:\Users\xxx\.conda\envs中

目录 问题&#xff1a; 解决&#xff1a; 更改默认安装位置 移动已安装环境 问题&#xff1a; 解决&#xff1a; 更改默认安装位置 用记事本打开 C:\Users\zqk\.condarc 在最后插入 envs_dirs: - D://anzhuang//Anaconda3//envs 如若需更改pkgs&#xff0c;插入如下代…

OTA: Optimal Transport Assignment for Object Detection 原理与代码解读

paper&#xff1a;OTA: Optimal Transport Assignment for Object Detection code&#xff1a;https://github.com/Megvii-BaseDetection/OTA 背景 标签分配&#xff08;Label Assignment&#xff09;是目标检测中重要的一环&#xff0c;经典的标签分配策略采用预定义的规则…

Caffeine 源码、架构、原理(史上最全,10W字 超级长文)

文章很长&#xff0c;而且持续更新&#xff0c;建议收藏起来&#xff0c;慢慢读&#xff01;疯狂创客圈总目录 博客园版 为您奉上珍贵的学习资源 &#xff1a; 免费赠送 :《尼恩Java面试宝典》 持续更新 史上最全 面试必备 2000页 面试必备 大厂必备 涨薪必备 免费赠送 经典…

【剧前爆米花--爪哇岛寻宝】面向对象的三大特性——封装、继承以及多态的详细剖析(中——多态)。

作者&#xff1a;困了电视剧 专栏&#xff1a;《JavaSE语法与底层详解》 文章分布&#xff1a;这是一篇关于Java面向对象三大特性——多态的文章&#xff0c;在本篇文章中我会分享多态的一些基础语法以及类在继承时代码的底层逻辑和执行顺序。 目录 多态的定义及实现条件 多态…

【程序人生】4年创作纪念日,不忘初心,继续前行

&#x1f4eb;作者简介&#xff1a;小明java问道之路&#xff0c;专注于研究 Java/ Liunx内核/ C及汇编/计算机底层原理/源码&#xff0c;就职于大型金融公司后端高级工程师&#xff0c;擅长交易领域的高安全/可用/并发/性能的架构设计与演进、系统优化与稳定性建设。 &#x1…

CleanMyMac X2022苹果电脑专业清理Mac加速器软件

CleanMyMac X2023最新免费版苹果电脑专业清理软件&#xff0c;对于Mac电脑用户来说&#xff0c;Cleanmymac X是一款再熟悉不过的电脑清理软件&#xff0c;它是由苹果认证并对外承认的一款第三方清理软件&#xff0c;几乎有95%的Mac用户都会安装并使用&#xff0c;Cleanmymac X究…

从一泡尿的工夫说起

大家好&#xff0c;我是校长。今天聊点不一样的&#xff0c;昨天读书的一点深刻感悟。大家有没有想过这么一个问题&#xff1a;如果没有记录时间的工具被发明&#xff0c;没有时钟&#xff0c;我们现在的生活会怎么样&#xff1f;在那个时钟尚未出现的日子里&#xff0c;如果确…

人工智能-机器学习-深度学习-概述

文章目录一&#xff1a;人工智能需要的基础和涉及内容二&#xff1a;数学基础&#xff08;1&#xff09;线性代数&#xff08;2&#xff09;概率论&#xff08;3&#xff09;数理统计&#xff08;4&#xff09;最优化方法&#xff08;5&#xff09;信息论三&#xff1a;机器学习…

虹科活动 | SWCF 2022卫星通信与仿真测试线上研讨会倒计时,快来报名吧!

您是否在因线下论坛的地点限制而错失技术干货分享&#xff1f;您是否因时间安排而无法亲临现场与行业专家交流&#xff1f;虹科举办全新线上论坛SWCF&#xff0c;与行业专家一起为您带来最新热点话题讨论与技术干货分享&#xff01; 什么是SWCF 虹科每年将开展卫星与无线通信…

计算机毕业设计之java+ssm网络硬硬盘系统网站

项目介绍 网盘&#xff0c;又称网络U盘、网络硬盘&#xff0c;是一些网络公司推出的在线存储服务。向用户提供文件的存储、访问、备份、共享等文件管理功能&#xff0c;使用起来十分方便。不花钱的移动硬盘。用户可以把网盘看成一个放在网络上的硬盘或U盘&#xff0c;不管你是…