基于SpringBoot框架,如何实现文件的上传与下载查看
提要
本项目借鉴于spring-guides/gs-uploading-files: Uploading Files :: Learn how to build a Spring application that accepts multi-part file uploads. (github.com)SpringBoot官网学习文档关于如何下载文件一章提供的演示代码;
GitHub
本项目使用GitHub作为代码托管平台,友友们,点亮小星星是对博主莫大的支持哦!!!
演示环境
- idea集成开发工具
- JDK21
- Apache Maven 3.9.4
接口设计
URL: http://localhost/files/{filename}
method: GET
query: filename-文件名
function: 查看文件
URL: http://localhost/files/download/{filename}
method: GET
query: filename-文件名
function: 下载文件
URL: http://localhost/upload
method: GET
param: file-多文件对象
function: 上传文件
单元测试
分别使用MockMvc与TestRestTemplate测试工具类,模拟客户端发送HTTP请求,对项目接口与存储服务层进行了测试;
项目文件
具体实现
配置类
配置客户端上传到服务端的文件存储地址,博主是默认存放在存储静态文件的resources目录下;
@Value
注解可以获取properties文件中存储的配置信息;
package test.springboot.demo.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
/**
* 配置存储
**/
@Configuration
public class StorageConfigure {
@Value("${storage.path}")
private String location;
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
}
properties文件
存放配置的信息
spring.servlet.multipart.max-file-size=4MB
spring.servlet.multipart.max-request-size=4MB
storage.path=src/main/resources/localStorage
API层
package test.springboot.demo.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import test.springboot.demo.exception.StorageFileNotFoundException;
import test.springboot.demo.service.StorageService;
@Controller
public class FileUploadController {
private final StorageService storageService;
/**
* 采用构造函数来注入StorageService对象,方便进行单测
* @param storageService StorageService对象
**/
@Autowired
public FileUploadController(StorageService storageService) {
this.storageService = storageService;
}
// 与上面的构造函数一样,用于注入StorageService对象
// @Autowired
// private StorageService storageService;
/**
* 做代理,客户端可下载资源或查看资源
* @return 文件后缀
**/
@GetMapping(value = {
"/files/{filename:.+}", "/files/{download:.+}/{filename:.+}"})
@ResponseBody
public ResponseEntity<Resource> serveFile(@PathVariable(required = false) String download, @PathVariable String filename) {
// 获取文件数据
Resource file = storageService.loadAsResource(filename);
// 如果文件为空就返回响应404
if (file == null) {
return ResponseEntity.notFound().build();
}
// 创建响应实体,设置状态码为200
ResponseEntity.BodyBuilder req = ResponseEntity.status(HttpStatus.OK);
// 如果download不为空,则执行下载,添加消息头attachment
if (download!=null) {
req.header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"" + file.getFilename() + "\"");
}
// 设置默认文件类型为application/octet-stream,二进制流
String contentType = "application/octet-stream";
if (file.getFilename() != null) {
// 获得文件名后缀
String ext = getFileExtension(file.getFilename());
switch (ext) {
case "pdf":
contentType = "application/pdf";
break;
case "png", "gif", "jpg":
contentType = "image/" + ext;
break;
case "jpeg":
contentType = "image/jpeg";
break;
case "ofd", "zip":
contentType = "application/" + ext;
break;
case "xlsx":
contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
break;
}
}
// 返回封装好的响应实体
return req.contentType(MediaType.valueOf(contentType))
.body(file);
}
/**
* 获得文件名后缀
* @param fileName 文件名
* @return 文件后缀
**/
public String getFileExtension(String fileName) {
if (fileName.lastIndexOf(".") != -1 && fileName.lastIndexOf(".") != 0)
return fileName.substring(fileName.lastIndexOf(".") + 1);
else
return "";
}
/**
* 上传文件
* @return 上传是否成功
*/
@PostMapping("/upload")
@ResponseBody
public boolean handleFileUpload(@RequestParam("file") M