当前位置: 首页 > news >正文

Spring Boot实现文件上传和下载

1.背景

项目中经常会有上传和下载的需求,这篇文章简述一下springboot项目中实现简单的上传和下载。

2.代码工程

实验目标

实现简单的文件上传和下载

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>springboot-demo</artifactId><groupId>com.et</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>file</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId></dependency><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpmime</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency></dependencies>
</project>

controller

Web项目中,文件的上传和下载服务也是基于HTTP请求的,文件上传由于需要向服务接口提交数据,可以使用POST的请求方式,而文件的下载只是获取数据,因此可以使用GET请求方式。  

package com.et.controller;import com.et.bean.FileInfo;
import com.et.service.FileUploadService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;import java.util.HashMap;
import java.util.List;
import java.util.Map;@RestController
public class HelloWorldController {@RequestMapping("/hello")public Map<String, Object> showHelloWorld(){Map<String, Object> map = new HashMap<>();map.put("msg", "HelloWorld");return map;}@Autowiredprivate FileUploadService fileUploadService;/*** upload** @param files* @return*/@PostMapping("/upload")public ResponseEntity<String> upload(@RequestParam("files") MultipartFile[] files) {fileUploadService.upload(files);return ResponseEntity.ok("File Upload Success");}/***  files** @return*/@GetMapping("/files")public ResponseEntity<List<FileInfo>> list() {return ResponseEntity.ok(fileUploadService.list());}/*** get file by name** @param fileName* @return*/@GetMapping("/files/{fileName:.+}")public ResponseEntity<Resource> getFile(@PathVariable("fileName") String fileName) {return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION,"attachment; filename=\"" + fileName + "\"").body(fileUploadService.getFile(fileName));}
}

service

创建好指定的文件存放路径文件夹后,上传逻辑只需要将接收到的文件数据赋值到指定路径后即可。

  • file.getInputStream(),接收文件参数的对应字节流
  • this.path.resolve(file.getOriginalFilename()),指定的path路径拼接接收文件的原始名称作为文件的路径信息
  • Files.copy(),复制文件的方法

文件的下载逻辑是根据指定的文件名称到文件资源文件夹中获取,如果存在则返回文件。

  • this.path.resolve(fileName),构建文件全路径
  • new UrlResource(file.toUri()),根据文件路径创建URL源
  • resource.exists() && resource.isReadable(),文件存在并且可读时返回
package com.et.service;import com.et.bean.FileInfo;
import org.springframework.core.io.Resource;
import org.springframework.web.multipart.MultipartFile;import java.util.List;public interface FileUploadService {void upload(MultipartFile[] files);List<FileInfo> list();Resource getFile(String fileName);
}
package com.et.service.impl;import com.et.bean.FileInfo;
import com.et.service.FileUploadService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;@Service
@Slf4j
public class FileUploadServiceImpl implements FileUploadService {@Value("${upload.path:/data/upload/}")private String filePath;private static final List<FileInfo> FILE_STORAGE = new CopyOnWriteArrayList<>();@Overridepublic void upload(MultipartFile[] files) {SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");for (MultipartFile file : files) {String fileName = file.getOriginalFilename();boolean match = FILE_STORAGE.stream().anyMatch(fileInfo -> fileInfo.getFileName().equals(fileName));if (match) {throw new RuntimeException("File [ " + fileName + " ] already exist");}String currentTime = simpleDateFormat.format(new Date());try (InputStream in = file.getInputStream();OutputStream out = Files.newOutputStream(Paths.get(filePath + fileName))) {FileCopyUtils.copy(in, out);} catch (IOException e) {log.error("File [{}] upload failed", fileName, e);throw new RuntimeException(e);}FileInfo fileInfo = new FileInfo().setFileName(fileName).setUploadTime(currentTime);FILE_STORAGE.add(fileInfo);}}@Overridepublic List<FileInfo> list() {return FILE_STORAGE;}@Overridepublic Resource getFile(String fileName) {FILE_STORAGE.stream().filter(info -> info.getFileName().equals(fileName)).findFirst().orElseThrow(() -> new RuntimeException("File [ " + fileName + " ] not exist"));File file = new File(filePath + fileName);return new FileSystemResource(file);}
}

application.properties

spring.servlet.multipart.max-file-size=150MB
spring.servlet.multipart.max-request-size=200MB
spring.servlet.multipart.file-size-threshold=100MB
upload.path=/Users/liuhaihua/tmp/

以上只是一些关键代码,所有代码请参见下面代码仓库

代码仓库

  • https://github.com/Harries/springboot-demo(File)

3.测试

  1. 启动Spring Boot应用
  2. 使用postman请求下载接口时,接口返回文件,postman会直接解析文件内容,如果无法正确解析则会显示乱码信息。如果在浏览器请求接口时,返回文件时浏览器会弹出下载文件的提示。

上传测试

upload

下载测试

download

4.引用

  • https://github.com/callicoder/spring-boot-file-upload-download-rest-api-example
  • Spring Boot实现文件上传和下载 | Harries Blog™

   

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 学生宿舍限电模块具体规格如何选择?
  • 线性代数 第三讲 线性相关无关 线性表示
  • 1、.Net UI框架:Avalonia UI - .Net宣传系列文章
  • 面试题总结(二) -- 面向对象篇(封装、继承、多态)
  • BaseCTF之web(week2)
  • [Linux] 操作系统 入门详解
  • element-ui单元格点击后进入编辑模式的功能
  • SpringBoot使用入门
  • 【安全漏洞】SpringBoot + SpringSecurity CORS跨域资源共享配置
  • Chrome 浏览器插件获取网页 window 对象(方案一)
  • Java 入门指南:Java NIO —— Buffer(缓冲区)
  • 【体检】程序人生之健康检查,全身体检与预防疫苗,五大传染病普筛,基因检测等
  • 你知道吗?Python现在这么火爆的真相!
  • RKNPU2项目实战【1】 ---- YOLOv5实时目标分类
  • sealos快速搭建k8s集群
  • 【个人向】《HTTP图解》阅后小结
  • co模块的前端实现
  • extjs4学习之配置
  • GraphQL学习过程应该是这样的
  • Java|序列化异常StreamCorruptedException的解决方法
  • javascript数组去重/查找/插入/删除
  • JS变量作用域
  • js操作时间(持续更新)
  • PHP 使用 Swoole - TaskWorker 实现异步操作 Mysql
  • SegmentFault 技术周刊 Vol.27 - Git 学习宝典:程序员走江湖必备
  • Traffic-Sign Detection and Classification in the Wild 论文笔记
  • Vue UI框架库开发介绍
  • 从 Android Sample ApiDemos 中学习 android.animation API 的用法
  • 对象管理器(defineProperty)学习笔记
  • 关于springcloud Gateway中的限流
  • 两列自适应布局方案整理
  • 算法-插入排序
  • 通过git安装npm私有模块
  • 微信小程序设置上一页数据
  • 为什么要用IPython/Jupyter?
  • 详解移动APP与web APP的区别
  • 自制字幕遮挡器
  • mysql面试题分组并合并列
  • 阿里云ACE认证学习知识点梳理
  • ​MPV,汽车产品里一个特殊品类的进化过程
  • ​七周四次课(5月9日)iptables filter表案例、iptables nat表应用
  • #1015 : KMP算法
  • #Linux(帮助手册)
  • (3)nginx 配置(nginx.conf)
  • (pytorch进阶之路)CLIP模型 实现图像多模态检索任务
  • (Redis使用系列) Springboot 实现Redis 同数据源动态切换db 八
  • (二)换源+apt-get基础配置+搜狗拼音
  • (二刷)代码随想录第15天|层序遍历 226.翻转二叉树 101.对称二叉树2
  • (附源码)计算机毕业设计SSM疫情社区管理系统
  • (四)Controller接口控制器详解(三)
  • (四)七种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
  • (学习日记)2024.04.04:UCOSIII第三十二节:计数信号量实验
  • (原創) 博客園正式支援VHDL語法著色功能 (SOC) (VHDL)
  • (转)大型网站架构演变和知识体系
  • *算法训练(leetcode)第四十七天 | 并查集理论基础、107. 寻找存在的路径