SpringMVC Day 08 : 文件上传下载

news2024/11/19 17:33:31

前言

文件上传和下载是 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/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        https://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 不要设置请求头的 contentType
                success: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.coloradmin.cn/o/1155124.html

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

相关文章

32、github的使用小技巧

如何在github中阅读项目代码 如果要完整阅读项目代码&#xff0c; 可能要在文件间来回跳转&#xff0c;就非常麻烦。所以我们往往会把项目代码下载到本地&#xff0c;用更强大的编辑器来阅读。 在github中&#xff0c;可以这样操作&#xff1a; 登录 GitHub 后&#xff0c;直…

Android手机实时投屏利器scrcpy图文详解教程

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl scrcpy简介 scrcpy是免费开源的投屏软件&#xff0c;它支持将安卓手机屏幕投放在 Windows、macOS、GNU/Linux 上&#xff0c;并可直接借助鼠标在投屏窗口中进行交互和录制。…

QCustomPlot图像刷新原理

借用官方的这张图分析。 主要关注QCPLayer 和QCPLayout&#xff0c;几乎所有的元素都是放置同一张布局中的&#xff0c;布局是核心要素&#xff0c;不同的元素可能不在同一张layer ,即不在同一层&#xff0c;不在同一层的元素的区别就是上层的元素会挡住下层的元素&#xff0c…

Xposed hook 抖音首页标签隐藏

Xposed hook 抖音首页标签隐藏 本篇文章主要使用xposed hook arraylist,来实现 抖音首页部分标签条目隐藏。 直接上代码&#xff1a; //隐藏首页tab XposedHelpers.findAndHookMethod(ArrayList.class, "add", Object.class, new XC_MethodHook() {Overrideprotect…

基于Docker安装Minikube

Minikube简介 Minikube是1款mini的Kubernetes集群&#xff0c;适合在本机上搭建Kubernetes环境进行测试。 Minikube的安装依赖于虚拟机或容器环境&#xff0c;类似于Kubernetes集群的安装依赖于公有云或私有云等。二者关系如下图所示&#xff1a; Minikube & dockerhttps…

MySQL创建数据库和创建数据表

二、创建数据库 1. 连接 MySQL 输入 mysql -u root -p 命令&#xff0c;回车&#xff0c;然后输入 MySQL 的密码(不要忘记了密码)&#xff0c;再回车&#xff0c;就连接上 MySQL 了。 mysql -u root -p 最初&#xff0c;都是使用 root 用户登录&#xff0c;工作中如果一直用…

uniapp开发微信小程序uview里的u-upload组件上传图片点击没反应,开发者工具点击正常,正式上手机上点击没反应

项目场景&#xff1a; 用uniapp开发的微信小程序&#xff0c;uview插件ui&#xff0c;u-upload上传文件&#xff0c;上传头像等方法&#xff0c;早就审核发布过的突然反应上传图片&#xff0c;文件啥的点击没反应 问题描述 原因分析&#xff1a; 根据查资料得知可能是因为小程…

第05章_排序与分

第05章_排序与分页 讲师&#xff1a;尚硅谷-宋红康&#xff08;江湖人称&#xff1a;康师傅&#xff09; 官网&#xff1a;http://www.atguigu.com 1. 排序数据 1.1 排序规则 使用 ORDER BY 子句排序 ASC&#xff08;ascend&#xff09;: 升序DESC&#xff08;descend&…

乘法器:如何像搭乐高一样搭电路(下)?

目录 背景 顺序乘法的实现过程 并行加速方法 电路并行 小结 背景 和学习小学数学一样&#xff0c;学完了加法之后&#xff0c;我们自然而然就要来学习乘法。既然是退回到小学&#xff0c;我们就把问题搞得简单一点&#xff0c;先来看两个 4 位数的乘法。这里的 4 位数&am…

前后端分离vue+springboot家庭理财账单财务管理系统

项目介绍&#xff1a; 该系统能够管理家庭收入支出&#xff0c;并且能直观得表现收支状态。主要功能包括用户管理、收支管理、财务管理、统计收支情况等功能。 技术栈&#xff1a; 后端&#xff1a; SpringBoot&#xff0c;Sa-Token&#xff0c;MyBatis-Plus&#xff0c;MyB…

WS-*标准是什么,有什么作用

WS-*标准是一组基于SOAP协议的Web服务规范&#xff0c;目的是提供一种在分布式环境中实现可互操作的端到端服务的方式。这些标准通常由不同的组织和公司提出&#xff0c;并得到了业界广泛的支持和应用。WS-*标准涵盖了从消息传输、安全性、事务处理到服务描述等多个方面。 主要…

成集云 | 企业微信费用报销集成金蝶EAS | 解决方案

源系统成集云目标系统 ​ 编辑 方案介绍 企业微信是一款通讯与办公工具&#xff0c;具有与微信一致的沟通体验&#xff0c;丰富的OA应用&#xff0c;和连接微信生态的能力&#xff0c;可帮助企业连接内部、连接生态伙伴、连接消费者。 金蝶EAS是金蝶软件的一款产品&#xff…

蓝桥杯动态规划-第五弹 最大子数组和 买卖股票最佳时机IV 第N个泰波那契数 环形数组

目录 一、最大子数组和 二、买卖股票最佳时机IV 三、第N个泰波那契数 四、环形数组 一、最大子数组和 1.状态表示 dp[i]:到第i数字&#xff0c;所有的最大和。 2.状态转移方程 dp[i]max(dp[i-1]p[i]&#xff0c;p[i])(加入这个点是0&#xff09; 我们来想一下&#xff0c;这…

C++ 面向对象 学习 优秀教程

油管看视频 沉浸式翻译插件&#xff0c;实现中文字幕&#xff01; 文章目录 Object Oriented Programming (OOP) in C Course Object Oriented Programming (OOP) in C Course https://www.youtube.com/watch?vwN0x9eZLix4 博主&#xff1a;https://www.youtube.com/CodeBeau…

手把手教你如何实现TNAS与云盘之间的无缝同步技巧

嘿&#xff0c;铁粉们&#xff01; 云盘的下载速度总是让我们抓耳挠腮 数据安全隐私问题让人担心不已 但在购入NAS之前 众多数据存放在云盘里 同时也想把NAS的数据备份在云盘里 实现备份321法则&#xff1f; 不用烦恼 铁威马来帮忙 无需其他多余操作 只要下载CloudSyn…

小米电视播放win10视频 win10共享问题

解决的方法就是安装SMB1.0协议 重启就OK了

redis的分布式锁

分布式锁是一种用在分布式系统中实现同步和互斥访问的机制。 1、分布式锁概念 满足分布式系统或者集群模式下&#xff0c;多进程可见并且互斥的锁。 分布式锁的核心思想就是让分布式集群中的节点都适用同一把锁&#xff0c;只要大家使用的是同一把锁&#xff0c;就能锁住线程…

小程序如何导入配送账号

为了提高配送效率和用户体验&#xff0c;可以导入配送账号&#xff08;包括电子面单快递物流账号、同城外卖配送账号&#xff09;到小程序中。导入后&#xff0c;可以实现一键发货&#xff0c;无需手动回填单号。而且在小程序中可以查看到物流状态&#xff0c;对于同城配送&…

CVE-2017-12149漏洞复现

目录 一、hunter上搜索web.title”锐捷网络”或者搜索web.icon”9c21df9129aeec032df8ac15c84e050d”&#xff0c;搜索相关资产。 二、一个一个点击查看&#xff0c;若出现以下界面就是锐捷的EW1200G路由器。 三、随便输入一个密码&#xff0c;发现是登不进去的。 四、此时…

操作系统:内存管理(二)虚拟内存管理

一战成硕 3.2 虚拟内存管理3.2.1 虚拟内存的基本概念3.2.2 请求分页管理方式3.2.3 页框分配3.2.4 页面置换算法3.2.5 抖动和工作集 3.2 虚拟内存管理 3.2.1 虚拟内存的基本概念 3.2.2 请求分页管理方式 页表机制 缺页中断机制 地址变换机构 3.2.3 页框分配 驻留集大小 内…