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

article/2025/8/23 23:51:49

前言

在这里插入图片描述

本文为 【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://chatgpt.dhexx.cn/article/6WefoHno.shtml

相关文章

最全面的SpringMVC教程(三)——跨域问题

前言 本文为 【SpringMVC教程】跨域问题 相关内容介绍。当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同时&#xff0c;就会产生跨域。那么究竟什么是跨域&#xff0c;跨域问题该如何解决&#xff0c;本文具体将对同源策略&#xff0c;什么是跨域&#xff0…

最全面的SpringMVC教程(一)——SpringMVC简介

前言 本文为SpringMVC相关教程&#xff0c;下边将对SpringMVC进行简单介绍&#xff0c;具体包含&#xff1a;对MVC架构的回顾&#xff0c;什么是SpringMVC&#xff0c;SpringMVC编程示例&#xff08;包含配置版示例、注解版示例&#xff09;&#xff0c;初识SpringMVC&#xff…

SpringMVC教程来喽!

目录 SpringMVC简介SpringMVC的搭建 SpringMVC简介 这里对SpringMVC进行一个简单介绍 springmvc是spring框架的一个模块&#xff0c;springmvc和spring无需通过中间整合层进行整合。springmvc是一个基于mvc的web框架。springmvc 表现层&#xff1a;方便前后端数据的传输Sprin…

搭建配置SpringMVC教程

1新建工程&#xff0c;在maven工程中选择create from archetype,选择webapp&#xff0c;注意有很数个webapp&#xff0c;要选择前缀有maven的 2.在pom.xml添加依赖 <dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc<…

SpringMVC教程(二)

什么是SpringMVC 概述 Spring MVC是Spring Framework的一部分&#xff0c;是基于Java实现MVC的轻量级Web框架。 查看官方文档&#xff1a;https://docs.spring.io/spring/docs/5.2.0.RELEASE/spring-framework-reference/web.html#spring-web 我们为什么要学习SpringMVC呢? …

最全面的SpringMVC教程(六)——WebSocket

前言 本文为 【SpringMVC教程】WebSocket 相关知识介绍&#xff0c;具体将对WebSocket进行简介&#xff0c;并通过实战案例对WebSocket的使用进行详尽介绍~ &#x1f4cc;博主主页&#xff1a;小新要变强 的主页 &#x1f449;Java全栈学习路线可参考&#xff1a;【Java全栈学…

SpringMVC教程(三)

SpringMVC&#xff1a;Hello,SpringMVC HelloSpringMVC 配置版 新建一个Moudle &#xff0c; 添加web的支持&#xff01;确定导入了SpringMVC 的依赖&#xff01; 配置web.xml &#xff0c; 注册DispatcherServlet <?xml version"1.0" encoding"UTF-8&quo…

史上最全最细的SpringMVC教程

SpringMVC是强大的Web开发框架&#xff0c;基于Spring。 课程从基础开始逐步讲解SpringMVC框架Web应用的相关技术点。涵盖了SpringMVC基础内容以及与Spring框架集成(如IoC容器、AOP等)等高级内容。 学习该课程后可以让我们能非常简单的设计出干净的Web层和薄薄的Web层。掌握强…

黑马程序员--SpringMVC详细教程

一、SpringMVC概述 SpringMVC 是一种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级 Web 框架&#xff0c;属于 SpringFrameWork 的后续产品&#xff0c;已经融合在 Spring Web Flow 中。 SpringMVC 已经成为目前最主流的MVC框架之一&#xff0c;并且随着Spring3.0 的发…

史上最全的SpringMVC教程,终于整理出来了

1. 为啥要学 SpringMVC&#xff1f; 1.1 SpringMVC 简介 在学习 SpringMVC 之前我们先看看在使用 Servlet 的时候我们是如何处理用户请求的&#xff1a; 配置web.xml <?xml version"1.0" encoding"UTF-8"?> <web-app xmlns"http://xml…

史上最全面最易懂的,Spring框架学习教程

Spring通过PlatformTransactionManager平台事务管理器接口对事务的管理进行高度抽象&#xff0c;但是该接口下具体的实现是由各个平台自己实现&#xff0c;Spring并不直接管理事务&#xff0c;而是提供了多种事务管理器&#xff0c;也就是对各个平台的事务管理进行封装&#xf…

Spring 入门教程

Spring 入门教程 1、参考资料 尚硅谷-Spring5框架最新版教程&#xff08;idea版&#xff09;雷丰阳spring、springmvc、mybatis、spring一站式学习 项目地址&#xff1a;Oneby / spring-learn 2、Spring 概述 2.1、Spring 框架概述 Spring 是轻量级的开源的 JavaEE 框架 Sp…

spring框架教程

Spring框架 一、spring简介 简介&#xff1a;spring框架是一个轻量级的控制反转和面向切面的容器框架&#xff0c;用来解决项目开发中的复杂度问题–解耦 轻量级&#xff1a;体积小&#xff0c;对代码没有侵入性&#xff08;代码侵入性&#xff1a;指的是业务代码中不会调用sp…

一文学会Spring,Spring最简单的入门教程(万字好文)

1.Spring概述 1.1 Spring框架是什么 ​ Spring是与2003年兴起的一个轻量级的Java开发框架&#xff0c;它是为了解决企业应用开发的复杂性而创建的。Spring的核心是控制反转(IOC)和面向切面编程(AOP)。Spring是可以在Java SE/EE中使用的轻量级开源框架。 ​ Spring的主要作用…

lcx 内网转发

把放置到已经控制的内网主机 执行 内网主机输入命令lcx.exe -slave 外网ip 外网端口 内网ip 内网端口lcx.exe -slave 30.1.85.55 2222 127.0.0.1 3389 外网主机输入命令lcx.exe -listen 2222 3388 打开 mstsc ip&#xff1a;3388

lcx使用

lcx使用 win7 192.168.5.101 win 10 192.168.0.31 kali 192.168.5.102 lcx 本机: lcx -listen 2222 3333 2222为转发端口&#xff0c;3333为本机任意未被占用的端口 肉鸡&#xff1a;lcx -slave 2.2.2.2 2222 127.0.0.1 3389 2.2.2.2 为本机IP,2222为转发端口&#xff0c;…

lcx实现端口转发

LCX转发实验一 环境&#xff1a;内网3389端口不对外开放&#xff0c;但是1234端口对外开放&#xff08;正向连接&#xff09; lcx .exe –tran 1234 127.0.0.1 3389过程&#xff1a;192.168.1.105: 1234 -> 3389 LCX转发实验二 环境&#xff1a;内网主机可以访问外网80端口…

端口转发lcx工具+nc反弹工具使用

一、lcx工具 lcx.exe是一个端口转发工具&#xff0c;有Windows版和Linux版两个版本&#xff0c;Windows版是lcx.exe,Linux版为portmap&#xff0c; Windows版使用方法如下&#xff1a; 1、 lcx 内网端口转发 本机IP:192.168.1.10 目标机IP&#xff1a;192.168.1.5 本机运行…

lcx的使用-内网穿透

lcx有两个功能映射(slave)和转发(tran) 简单看个列子&#xff1a; 映射(slave) 第一步&#xff1a; 我在攻击机上执行此命令 lcx -listen 3333 2222此命令表示我监听3333端口&#xff0c;并把3333端口映射到2222端口 第二步&#xff1a; 我在靶机上执行此命令&#xff1a; …

流量映射端口反弹(lcx,ew)

转载自西梅哥的有道云&#xff1a; https://note.youdao.com/ynoteshare1/index.html?ida6bf797cce0b6087cb78b44818dca69f&typenote 内网应用 一、端口转发工具&#xff1a; 1.LCX&#xff08;支持双系统&#xff09; A、window&#xff08;LCX&#xff09; 上传一些…