SpringMVC Day 08 : 文件上传下载

前言

文件上传和下载是 Web 开发中的重要环节,但它们往往不那么容易实现。幸运的是,Spring MVC 提供了一套简单而又强大的解决方案,让我们可以专注于业务逻辑,而不必过多关注底层的文件处理细节。

在本篇博客中,我们将学习如何利用 Spring MVC 实现文件上传和下载功能。首先,我们将了解文件上传的过程以及必要的配置。随后,我们将介绍如何在控制器中处理上传的文件,并对其进行存储或处理。最后,我们将学习如何实现文件下载的功能,使用户能够方便地获取指定的文件。

 一、前期准备

1、新建项目,结构如下

2、导入依赖
    <dependencies><!-- springmvc 依赖,会将spring的核心包一并添加进来 --><!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.3.23</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.30</version></dependency><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.4.5</version></dependency><!-- 上传组件 --><dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.3.1</version></dependency></dependencies>

 使用Apache Commons FileUpload库的上传组件,你可以轻松地处理HTTP请求中的文件上传部分。它提供了一些方便的类和方法,使文件上传变得简单和可靠。

 3、配置 web.xml 
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><servlet><servlet-name>dispatcher</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>dispatcher</servlet-name><url-pattern>/</url-pattern></servlet-mapping>
</web-app>

用于配置 Servlet 的映射和加载。在 Spring MVC 中,它用于配置 DispatcherServlet 的初始化和请求映射。

具体来说,这段配置的作用如下:

  1. 定义了一个名为 "dispatcher" 的 Servlet,并指定了 org.springframework.web.servlet.DispatcherServlet 作为其处理类。
  2. 设置了 load-on-startup 属性为 1,表示在应用启动时就加载该 Servlet。
  3. 使用 <servlet-mapping> 元素将 "dispatcher" Servlet 映射到所有的请求路径上(即 <url-pattern>/</url-pattern>),意味着所有的请求都会经过该 Servlet 进行处理。

 这段配置的作用是将所有的请求交给 DispatcherServlet 处理,并让它成为应用的核心控制器。DispatcherServlet 将根据请求的 URL 和其他配置信息,将请求分发给相应的处理器方法进行处理,然后返回响应结果。


4、编写 ResultVO 类
@Data
public class ResultVO<T> {private Integer code = HttpStatus.OK.value();private String message;private T data;}

这段代码定义了一个名为ResultVO的泛型类。它使用了Lombok注解@Data,该注解用于自动生成类的常用方法,如构造函数、Getter和Setter等。

这个ResultVO类有以下几个字段:

  • code:表示响应的状态码,默认值为HttpStatus.OK.value(),即200。
  • message:表示响应的消息,可以是任意字符串。
  • data:表示响应的数据,使用了泛型T,可以是任意类型。

通过使用@Data注解,Lombok将会自动生成以下方法:

  • 无参构造函数:用于创建ResultVO对象。
  • 全参构造函数:用于根据提供的参数创建ResultVO对象。
  • Getter和Setter方法:用于获取和设置codemessagedata字段的值。
  • equalshashCode方法:用于比较两个ResultVO对象的相等性。
  • toString方法:用于返回ResultVO对象的字符串表示。

通过使用这个通用的ResultVO类,你可以在应用程序中统一封装响应结果,包括状态码、消息和数据。它可以帮助你更方便地构建和处理API的响应,并且具有灵活性和可扩展性,适用于各种不同类型的响应数据。

5、编写 ProductVO 类
/*** @Date 2023-10-24* @Author qiu* 商品 VO 对象,用于保存页面提交的数据* 后续将这个 vo 拷贝到 entity 中*/
@Data
public class ProductVO {/*** 商品名称*/private String productName;/*** 商品图片*/private MultipartFile[] file;}

 这段代码定义了一个名为ProductVO的类,用于保存页面提交的商品数据。它使用了Lombok注解@Data,该注解用于自动生成类的常用方法。

ProductVO类有以下几个字段:

  • productName:表示商品名称,使用了private访问修饰符,类型为字符串。
  • file:表示商品图片,使用了private访问修饰符,类型为MultipartFile[],即文件数组。

通过使用@Data注解,Lombok将会自动生成以下方法:

  • 无参构造函数:用于创建ProductVO对象。
  • 全参构造函数:用于根据提供的参数创建ProductVO对象。
  • Getter和Setter方法:用于获取和设置productNamefile字段的值。
  • equalshashCode方法:用于比较两个ProductVO对象的相等性。
  • toString方法:用于返回ProductVO对象的字符串表示。

ProductVO类主要用于接收前端页面提交的商品数据。在后续的操作中,可以将这个ProductVO对象的数据拷贝到实体类(entity)中进行进一步处理和持久化。

其中,MultipartFile是Spring框架提供的一个接口,用于处理文件上传。MultipartFile[]表示多个文件的数组,可以用于接收前端上传的多个商品图片文件。

通过使用这个ProductVO类,你可以方便地接收和保存页面提交的商品数据,其中包括商品名称和商品图片。这样可以更好地组织和管理商品相关的信息,并将其传递给后续的业务逻辑处理。

二、 实现文件上传

1、文件上传

@RestController
@Slf4j
public class ProductContoroler {/*** 添加商品,同时带有上传的附件* @param productVO* @return*/@PostMapping("/add")public ResultVO add(ProductVO productVO) throws IOException {ResultVO resultVO = new ResultVO();// 获取上传的路径(绝对路径)String uploadPath = "d://file/";// 拼接完整的上传路径
//        uploadPath += filename;log.info(uploadPath);// 根据路径构建一个上传的文件对象File uploadFile = new File(uploadPath);// 判断路径中的文件夹是否存在,不存在则创建if (!uploadFile.exists()) {// 将文件夹创建出来uploadFile.mkdirs();}// 获取上传的文件名MultipartFile[] file = productVO.getFile();for (MultipartFile multipartFile : file) {// 获取文件名String filename = multipartFile.getOriginalFilename();// 执行上传Path path = FileSystems.getDefault().getPath(uploadFile.getAbsolutePath(),filename);multipartFile.transferTo(path);}return resultVO;}}

add的方法,使用了@PostMapping("/add")注解,表示当接收到POST请求时,会调用这个方法来处理。

该方法的参数是一个ProductVO对象,用于接收前端提交的商品数据。

方法内部首先创建了一个ResultVO对象,用于封装响应结果。

然后,指定了一个上传文件的路径uploadPath(这里设置为"d://file/")。

接着,通过日志记录工具log,将uploadPath输出到日志中,方便查看。

uploadPath路径下创建一个文件夹uploadFile,如果该文件夹不存在的话。

接下来,从productVO对象中获取上传的商品图片文件数组file

然后,使用循环遍历file数组,对每个文件进行处理。

对于每个文件,首先获取其原始文件名filename

然后,使用FileSystems.getDefault().getPath()方法构建一个文件路径path,指定了文件的保存位置。

最后,调用multipartFile.transferTo()方法将文件保存到指定路径path

最后,返回resultVO对象作为响应结果。

这个add方法实现了接收商品信息以及商品图片的上传功能。它将商品图片保存到指定路径,并返回一个结果对象作为响应。

2、编写 xml 完成配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttps://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 扫描 --><context:component-scan base-package="edu.nf.ch08"/><!-- mvc注解驱动--><mvc:annotation-driven/><!-- 静态资源处理器--><mvc:default-servlet-handler/><!-- 装配上传附件解析器--><bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"><!-- 限制文件上传的总大小(单位:字节),不配置此属性默认不限制 --><property name="maxUploadSize" value="104857600"/><!-- 设置文件上传的默认编码--><property name="defaultEncoding" value="utf-8"/></bean></beans>

 在该配置文件中,首先声明了XML命名空间xmlns,以及XML命名空间的映射关系xsi:schemaLocation。这些声明用于引入和定义XML模式(XSD)。

然后,使用<context:component-scan>指定要扫描的基础包,以便自动注册Spring的组件。

接下来,通过<mvc:annotation-driven/>启用Spring MVC的注解驱动,以支持处理器映射和处理器适配器。

使用<mvc:default-servlet-handler/>配置静态资源处理器,以便将静态资源(如CSS、JavaScript等)映射到默认的Servlet上。

通过<bean>配置上传附件解析器,这里使用的是CommonsMultipartResolver,用于处理文件上传功能。可以通过设置maxUploadSize属性限制文件上传的总大小,并设置defaultEncoding属性指定文件上传的默认编码。

3、编写页面实现上传
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="js/JQuery文件.txt.js"></script>
</head>
<body><form id="f1" enctype="multipart/form-data">Name:<input type="text" name="productName"/><br>Image:<input type="file" name="file" multiple/><br><input type="button" value="提交"/><br></form><script>$(function () {$(':button').on('click',function () {// 构建 formData 对象let formData = new FormData($('#f1')[0]);$.ajax({url:'../add',type:'post',data:formData,processData:false, // 告诉 jquery 不要处理发送的数据类型contentType:false, // 告诉 jquery 不要设置请求头的 contentTypesuccess:function ( result ) {if ( result.code === 200 ){alert("上传成功");} else {alert("上传失败");}}})})})
</script></body>
</html>

 在页面中,定义了一个带有id为"f1"的form元素,使用了enctype="multipart/form-data"属性来支持文件上传。

在表单中,有两个输入字段:

  • Name:一个文本输入框,用于输入商品名称,其name属性为"productName"。
  • Image:一个文件选择框,用于选择商品图片,其name属性为"file",并且设置了multiple属性,表示可以选择多个图片文件。

接着,定义了一个JavaScript脚本,在页面加载完成后执行。

脚本中,通过选择器$(':button')选中所有按钮元素,并绑定了一个点击事件处理函数。当按钮被点击时,会执行该函数。

在函数内部,首先创建一个FormData对象formData,并将表单f1的数据添加到formData中。

然后,使用jQuery的ajax方法,发送一个POST请求到服务器的"../add"路径。

请求的数据为formData,同时设置了processData为false,告诉jQuery不要处理发送的数据类型;contentType也设置为false,告诉jQuery不要设置请求头的contentType。

在请求成功后的回调函数中,根据服务器返回的结果result,判断上传是否成功。如果返回的code为200,则弹出上传成功的提示框;否则,弹出上传失败的提示框。

该HTML页面实现了一个简单的图片上传功能,通过选择商品名称和图片文件,点击提交按钮后,将数据发送到服务器进行处理,并根据返回的结果给出相应的提示。

4、运行效果
1)单个文件
 2)多个文件

 三、实现文件下载

1、文件下载
  /*** 文件下载* @param fileName* @return*/@GetMapping("/download/{fileName}")public ResponseEntity<InputStreamResource> download(@PathVariable("fileName") String fileName) throws Exception {// 文件下载目录(也就是上传路径)String downloadPath = "d://file/" + fileName;// 构建一个文件输入流读取服务器上的文件FileInputStream fis = new FileInputStream(downloadPath);// 设置响应头,告诉浏览器响应流程HttpHeaders headers = new HttpHeaders();// 对文件名进行编码,防止响应头中出现乱码fileName = URLEncoder.encode(fileName,"UTF-8");// 设置头信息,将响应内容处理的方式设置为附件下载headers.setContentDispositionFormData("attachment",fileName);// 设置响应类型为流类型headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);// 创建 InputStreamResource 对象封装输入流,用于读取服务器文件InputStreamResource isr = new InputStreamResource(fis);// 创建 ResponseEntity 对象(封装 InputStreamResource,响应头,以及响应状态码)ResponseEntity<InputStreamResource> entity = new ResponseEntity<>(isr, headers,HttpStatus.CREATED);return entity;}

这段代码实现了一个文件下载的功能。具体来说,当访问URL为"/download/{fileName}"时,该方法会被执行。

方法接收一个文件名参数fileName,并根据该文件名构建文件下载路径downloadPath。

然后,通过FileInputStream读取指定路径上的文件。

接下来,创建一个HttpHeaders对象,用于设置响应头信息。

在响应头中,使用URLEncoder对文件名进行编码,以防止出现乱码。

然后,设置响应内容处理方式为附件下载,并将响应类型设置为流类型。

接着,使用InputStreamResource对象封装文件输入流,以便于读取服务器上的文件。

最后,创建一个ResponseEntity对象,将封装好的InputStreamResource、响应头和响应状态码封装到其中,并将其返回给客户端进行下载。

2、运行效果 

 四、总结

本次案例只是简单的文件上传和下载,都是上传在本地,那可不可以上传到远程的服务器上呢?也是可以的,后面会出一个案例讲解怎么上传文件到远程服务器 minion 上。

五、gitee 案例

地址:ch08 · qiuqiu/SpringMVC - 码云 - 开源中国 (gitee.com)

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

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

相关文章

UE5——网络——RPC

RPC&#xff08;这个是官方文档的资料&#xff09; 要将一个函数声明为 RPC&#xff0c;您只需将 Server、Client 或 NetMulticast 关键字添加到 UFUNCTION 声明。 例如&#xff0c;若要将某个函数声明为一个要在服务器上调用、但需要在客户端上执行的 RPC&#xff0c;您可以…

在Maven中发布项目到Nexus私有服务器

一、测试环境 Sonatype Nexus 3.61.0-02 Maven 3.9.2 二、环境配置 2.1找到maven的配置文件 2.2添加私有仓库账户密码 <servers><server><id>nexus</id><username>admin</username><password>admin</password></server&…

【Linux】Linux+Nginx部署项目(负载均衡动静分离)

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于Linux的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一.Nginx负载均衡 1.什么是负载均衡 2.实…

网站如何改成HTTPS访问

在今天的互联网环境中&#xff0c;将网站更改成HTTPS访问已经成为了一种标准做法。HTTPS不仅有助于提高网站的安全性&#xff0c;还可以提高搜索引擎排名&#xff0c;并增强用户信任。因此&#xff0c;转换为HTTPS是一个重要的举措&#xff0c;无论您拥有个人博客、电子商务网站…

年度评选开启,边缘力量驱动科技未来!

随着人工智能技术的快速发展&#xff0c;边缘计算作为一种新兴技术&#xff0c;正逐渐成为实现智能制造、智慧城市、自动驾驶等领域的关键技术之一。边缘计算能够在靠近数据源的地方进行数据处理和分析&#xff0c;从而提高数据的实时性和可靠性&#xff0c;同时降低网络带宽和…

【Linux】jdk Tomcat MySql的安装及Linux后端接口部署

一&#xff0c;jdk安装 1.1 上传安装包到服务器 打开MobaXterm通过Linux地址连接到Linux并登入Linux&#xff0c;再将主机中的配置文件复制到MobaXterm 使用命令查看&#xff1a;ll 1.2 解压对应的安装包 解压jdk 解压命令&#xff1a;tar -xvf jdk 加键盘中Tab键即可…

【LVS实战】02 搭建一个LVS-NAT模式实验

一、网络结构 用虚拟机搭建如下的几台机器&#xff0c;并配置如下的ip 关于虚拟机网卡和网络的配置&#xff0c;可以参考 iptables章节&#xff0c;05节&#xff1a;网络转发实验 主机A模拟外网的机器 B为负载均衡的机器 C和D为 RealServer 二、C和D主机的网关设置 C和D机…

ROS学习笔记(4):ROS架构和通讯机制

前提 前4篇文章以及帮助大家快速入门ROS了&#xff0c;而从第5篇开始我们会更加注重知识积累。同时我强烈建议配合B站大学的视频一起服用。 1.ROS架构三层次&#xff1a; 1.基于Linux系统的OS层&#xff1b; 2.实现ROS核心通信机制以及众多机器人开发库的中间层&#xff1b…

Redis的四种部署方案

这篇文章介绍Reids最为常见的四种部署模式&#xff0c;其实Reids和数据库的集群模式差不多&#xff0c;可以分为 Redis单机模式部署、Redis主从模式部署、Redis哨兵模式部署、Cluster集群模式部署&#xff0c;其他的部署方式基本都是围绕以下几种方式在进行调整到适应的生产环境…

40 深度学习(四):卷积神经网络|深度可分离卷积|colab和kaggle的基础使用

文章目录 卷积神经网络为什么要卷积卷积的具体流程池化tensorflow代码 深度可分离卷积原理介绍计算量对比代码参数计算例子 colab 和 kagglecolabkaggle如何在colab上使用kaggle的数据 卷积神经网络 卷积神经网络的基本结构 1&#xff1a; (卷积层(可选)池化层) * N全连接层 *…

网络安全应急响应工具(系统痕迹采集)-FireKylin

文章目录 网络安全应急响应工具(系统痕迹采集)-FireKylin1.FireKylin介绍【v1.4.0】 2021-12-20【v1.0.1】 2021-08-09 2.客户端界面Agent支持的操作系统FireKylinAgent界面使用方式比较传统方式与FireKylin比较无法可达目标的场景应用对比 3.使用教程设置语言Agent配置&#x…

离散傅里叶变换中的能量守恒公式(帕斯瓦尔定理)及其程序举例验证

离散傅里叶变换中的能量守恒公式&#xff08;帕斯瓦尔定理&#xff09;及其程序举例验证 一、 离散傅里叶变换中的能量守恒公式 离散傅里叶变换中的能量守恒公式&#xff1a; ∑ n 0 N − 1 ∣ x [ n ] ∣ 2 1 N ∑ k 0 N − 1 ∣ X [ k ] ∣ 2 (1) \sum\limits_{n 0}^{N…

【C++】医学影像信息管理系统源码

狭义的医学影像信息系统是指基于医学影像存储和通信系统的管理系统&#xff0c;从技术上解决了影像处理技术。临床信息系统是指支持医院医务人员临床活动&#xff0c;收集和处理患者临床医疗信息的信息管理系统。放射科信息系统是指放射科挂号、分诊、影像诊断报告、信息查询、…

pycharm 断点调试python Flask

以flask框架为例&#xff0c;其启动命令为 python app.py runserver 后面需要拼接runserver 点击开始断点 参考&#xff1a;https://www.cnblogs.com/bigtreei/p/14742015.html

vue-cli5.0.x优雅降级,配置项目兼容旧版浏览器

兼容低版本谷歌浏览器 vue-cli5.0.x脚手架下的&#xff0c;如何降低项目版本以适用于底版本的浏览器。 直接使用默认配置打包部署出来的项目再40&#xff0c;60、70版本的谷歌浏览器跑不起来&#xff0c;蓝屏或者浏览器白屏一般这种情况都需要通过Babel去做转换&#xff0c;我…

什么?前端又出新轮子了?ofa.js

不需要打包的 MVVM JavaScript 框架 无需繁琐学习&#xff0c;无需 npm、nodejs、webpack&#xff0c;即刻上手 <script src"https://cdn.jsdelivr.net/gh/kirakiray/ofa.js/dist/ofa.min.js"></script>官方文档 取代 jQuery 在许多小型项目中&#x…

【机器学习合集】模型设计之注意力机制动态网络 ->(个人学习记录笔记)

文章目录 注意力机制1. 注意力机制及其应用1.1 注意力机制的定义1.2 注意力机制的典型应用 2. 注意力模型设计2.1 空间注意力机制2.2 空间注意力模型2.3 通道注意力机制2.4 空间与通道注意力机制2.5 自注意力机制2.5 级联attention 动态网络1. 动态网络的定义2. 基于丢弃策略的…

Debian或Ubuntu静态交叉编译arm和aarch64

Debian或Ubuntu静态交叉编译arm和aarch64 介绍术语ARM架构前置条件从源代码编译一个简单的C程序configure和make交叉编译关于静态链接和依赖关系使用 musl libc 实现与 configure 和 make 进行交叉编译 ARM 正在获得越来越多的关注&#xff0c;并且越来越受欢迎。直接在这些基于…

深度学习_3 数据操作之线代,微分

线代基础 标量 只有一个元素的张量。可以通过 x torch.tensor(3.0) 方式创建。 向量 由多个标量组成的列表&#xff08;一维张量&#xff09;。比如 x torch.arange(4) 就是创建了一个1*4的向量。可以通过下标获取特定元素&#xff08;x[3]&#xff09;&#xff0c;可以通…

Web3时代:探索DAO的未来之路

Web3 的兴起不仅代表着技术进步&#xff0c;更是对人类协作、创新和价值塑造方式的一次重大思考。在 Web3 时代&#xff0c;社区不再仅仅是共同兴趣的聚集点&#xff0c;而变成了一个价值交流和创新的平台。 去中心化&#xff1a;超越技术的革命 去中心化不仅仅是 Web3 的技术…