Spring Boot之文件上传、下载

前言

来啦老铁!

笔者学习Spring Boot有一段时间了,附上Spring Boot系列学习文章,欢迎取阅、赐教:

  1. 5分钟入手Spring Boot;
  2. Spring Boot数据库交互之Spring Data JPA;
  3. Spring Boot数据库交互之Mybatis;
  4. Spring Boot视图技术;
  5. Spring Boot之整合Swagger;
  6. Spring Boot之junit单元测试踩坑;
  7. 如何在Spring Boot中使用TestNG;
  8. Spring Boot之整合logback日志;
  9. Spring Boot之整合Spring Batch:批处理与任务调度;
  10. Spring Boot之整合Spring Security: 访问认证;
  11. Spring Boot之整合Spring Security: 授权管理;
  12. Spring Boot之多数据库源:极简方案;
  13. Spring Boot之使用MongoDB数据库源;
  14. Spring Boot之多线程、异步:@Async;
  15. Spring Boot之前后端分离(一):Vue前端;
  16. Spring Boot之前后端分离(二):后端、前后端集成;
  17. Spring Boot之前后端分离(三):登录、登出、页面认证;
  18. Spring Boot之面向切面编程:Spring AOP;
  19. Spring Boot之集成Redis(一):Redis初入门;
  20. Spring Boot之集成Redis(二):集成Redis;
  21. Spring Boot之集成Redis(三):Spring Cache + Redis;

Redis挖了好大一个坑,肝了好几天,Redis暂时就学到这吧,今天我们来学点轻松的!

最近换电脑,需要把旧电脑上的一些资料传到新电脑,很多人是将旧电脑的资料上传到云盘,然后新电脑再从云盘下载,这个过程本没有问题,我也经常这么干,但问题是云盘上传文件的速度跟蜗牛爬一样,于是有了今天这一说:

  • Spring Boot之文件上传、下载

项目代码已上传Git Hub仓库,欢迎取阅:

整体步骤

  1. 添加文件限制配置或编写文件限制配置类;
  2. 编写演示用文件上传API;
  3. 编写演示用文件下载API;
  4. 文件上传、下载演示;

1. 添加文件限制配置或编写文件限制配置类;

Spring Boot的默认单次上传文件的大小为10 MB,在没有额外干预的情况下,上传超过10 MB的文件,会有类似这样的报错:

org.apache.tomcat.util.http.fileupload.impl.FileSizeLimitExceededException: The field file exceeds its maximum permitted size of 1048576 bytes.
    at org.apache.tomcat.util.http.fileupload.impl.FileItemStreamImpl$1.raiseError(FileItemStreamImpl.java:114)
    at org.apache.tomcat.util.http.fileupload.util.LimitedInputStream.checkLimit(LimitedInputStream.java:76)
    at org.apache.tomcat.util.http.fileupload.util.LimitedInputStream.read(LimitedInputStream.java:135)
    at java.io.FilterInputStream.read(FilterInputStream.java:107)
    at org.apache.tomcat.util.http.fileupload.util.Streams.copy(Streams.java:98)
    at org.apache.tomcat.util.http.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:291)
    at org.apache.catalina.connector.Request.parseParts(Request.java:2869)
    at org.apache.catalina.connector.Request.getParts(Request.java:2771)
    at org.apache.catalina.connector.RequestFacade.getParts(RequestFacade.java:1098)

我们可以通过2种方式将这一限制扩大。

1). 添加文件限制配置方式;

这个方式很简单,比如我们想将文件限制放大到10 GB,只需要在application.properties文件中添加以下类似配置即可:

#单个文件大小限制
spring.servlet.multipart.max-file-size=10240MB
#单个请求,文件总大小限制
spring.servlet.multipart.max-request-size=10240MB

application.properties文件整体样子:

server.port=8080
#单个文件大小限制
spring.servlet.multipart.max-file-size=10240MB
#单个请求,文件大小限制
spring.servlet.multipart.max-request-size=10240MB
#默认文件上传功能,文件保存的根目录
file.upload.dir=E:\\Resource\\spring-boot-cloud\\
#默认文件下载功能,文件保存的根目录
file.download.dir=E:\\Resource\\spring-boot-cloud\\
2). 编写文件限制配置类方式;

这种方式也加单,新建config包,在包内创建一个MultipartConfig.java类(名字不限),类中写入以下代码:

package com.github.dylanz666.config;

import org.springframework.boot.web.servlet.MultipartConfigFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.unit.DataSize;

import javax.servlet.MultipartConfigElement;


/**
 * @author : dylanz
 * @since : 11/02/2020
 */

@Configuration
public class MultipartConfig {
    @Bean
    public MultipartConfigElement multipartConfigElement() {
        MultipartConfigFactory multipartConfigFactory = new MultipartConfigFactory();

        multipartConfigFactory.setMaxFileSize(DataSize.parse("10240MB"));
        multipartConfigFactory.setMaxRequestSize(DataSize.parse("10240MB"));

        return multipartConfigFactory.createMultipartConfig();
    }
}

2种方式效果一样,任君选择!

2. 编写演示用文件上传API;

package com.github.dylanz666.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;

/**
 * @author : dylanz
 * @since : 11/02/2020
 */
@RestController
@RequestMapping("/api")
public class FileUploadController {
    @Value(value = "${file.upload.dir}")
    private String rootPath;

    @GetMapping("/upload/ping")
    public String ping() {
        return "success";
    }

    @PostMapping("/file")
    public Boolean upload(@RequestParam("file") MultipartFile file) {
        try {
            String fileName = file.getOriginalFilename();
            assert fileName != null;
            System.out.println(fileName);

            File dest = new File(rootPath, fileName);
            file.transferTo(dest);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
}

3. 编写演示用文件下载API;

为了系统学习文件上传与下载,我又实现了一个文件下载的API。

新建FileDownloadController.java类,写入代码:

package com.github.dylanz666.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.Objects;

/**
 * @author : dylanz
 * @since : 11/08/2020
 */
@RestController
@RequestMapping("/api")
public class FileDownloadController {
    @Value(value = "${file.download.dir}")
    private String rootPath;

    private FileInputStream fis = null;
    private BufferedInputStream bis = null;

    @GetMapping("/download/ping")
    public String ping() {
        return "success";
    }

    @GetMapping("/file")
    public String download(@RequestParam String fileName) {
        try {
            File file = new File(rootPath, fileName);

            HttpServletResponse response = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getResponse();
            assert response != null;
            response.setContentType("application/force-download");
            response.setCharacterEncoding("UTF-8");
            response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(fileName, "UTF-8"));

            if (file.exists()) {
                byte[] buffer = new byte[1024];
                fis = new FileInputStream(file);
                bis = new BufferedInputStream(fis);
                OutputStream os = response.getOutputStream();

                int i = bis.read(buffer);
                while (i != -1) {
                    os.write(buffer, 0, i);
                    i = bis.read(buffer);
                }
            }
            return "success";
        } catch (Exception e) {
            e.printStackTrace();
            return "fail";
        } finally {
            try {
                bis.close();
                fis.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

4. 文件上传、下载演示;

1). 文件上传:

上传前:

上传前

上传:

上传 1
上传 2

上传后:

上传后

咱们来稍微解读一下:

(1). 由于我要快速实现上传接口,用于传文件,所以我没有做过多的验证和逻辑处理,关键代码只有3行:

String fileName = file.getOriginalFilename();

File dest = new File(rootPath + fileName);
file.transferTo(dest);

即API拿到传来的文件,拿其文件名,拼出服务器的文件路径,保存就完事了!

(2). 我们可以在application.properties自定义一个默认的上传文件保存根目录,然后用@Value注解引用进项目,如:

@Value(value = "${file.upload.dir}")
private String rootPath;

(3). 文件上传还是挺快的,经试验,2G的文件约600秒完成上传,平均3.4 MB/s,况且我们省去了下载的动作,相比于上传到云盘,再下载到新电脑的方式,简直是太快了!

(4). 上传的速度应该受我局域网设备(路由器)、局域网带宽等的限制,但即使这样,速度也是比云盘那种方式快多了,而且速度十分稳定!

2). 文件下载:

(文件下载的功能是我们自己学习用的,与本次解决换电脑文件传输慢的问题无关。)

由于我们写的是GET API,可在浏览器直接访问下载API,如:http://192.168.0.105:8080/api/file?fileName=Postman-win64-7.32.0-Setup.exe

文件下载

速度也是贼快哦!

至此,我们在Spring Boot项目中实现了文件的上传、下载,整个过程非常轻松,可谓丝滑,读者可自行扩展,如批量文件上传、下载等。

而经过此次的学习,我想我知道怎么做一个个人网盘了,你呢?

如果本文对您有帮助,麻烦点赞、关注!

谢谢!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343