Java Spring Boot 中集成文件上传和下载功能
在日常开发中,可能会遇到文件上传下载的需求,今天简单学习下,在项目开发中,如果遇到类似需求,该如何应对。
在 Spring Boot 项目中如果增加 文件上传下载 的功能,其实也挺简单,无非就是增加接口而已,但具体实现需要根据需求来定,通常我们的上传,可能会限制文件类型,限制文件大小,或者是限制文件数量,然后在将文件上传到指定服务器后,我们通常在数据库中也会存储一个用户文件的对应目录位置,便于后期请求处理。
当然一些可以通用处理的功能,我们应该将其在 拦截件 中实现,比如文件类型,文件大小,包括请求大小,万一用户上传个超大的文件,这对我们后台肯定不允许的,除非说你的后台就是一个网盘,不然通常的业务场景都要限制下这些因素。
话不多说,我们看看单个文件、多个文件上传,文件下载可以怎么实现吧。
单个文件上传
在编写接口时,我们需要限定在表单中的字段名,因为我们需要通过 Spring Boot 的注解来获取对应资源,在上传接口中,最好也对上传的文件做一些限制。
package com.example.springbootmybatisplusdemo.controller;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.nio.file.*;
@RestController
@RequestMapping("/file")
public class FileHandleController {
private static String UPLOAD_DIR = System.getProperty("user.dir") + File.separator + "uploads";
@PostMapping("/upload/single")
public String upload(@RequestParam("file") MultipartFile file) throws IOException {
System.out.println(String.format("File: %s is about to uploading...", file.getName()));
// handle upload file type, may handle in interceptor
String contentTyp = file.getContentType();;
switch (contentTyp) {
case "text/csv":
System.out.println("content-type:" + "text/csv");
break;
case "application/pdf":
System.out.println("content-type:" + "application/pdf");
break;
case "image/png":
System.out.println("content-type:" + "image/png");
break;
case "image/jpg":
System.out.println("content-type:" + "image/jpg");
break;
default:
System.out.println("content-type:" + contentTyp);
}
// handle file size, handle in interceptor
long size = file.getSize();
if (size > 5 * 1024 * 1024) {
return "size out of limit.";
}
if (file.getSize() == 0) {
return "empty file!";
}
String newFileName = save(file);
return newFileName;
}
private String save(MultipartFile file) throws IOException {
String newFileName = file.getOriginalFilename() + "-" + System.currentTimeMillis();
final Path filePath = Paths.get(UPLOAD_DIR, newFileName);
// method-1
Files.write(filePath, file.getBytes());
// method-2
// file.transferTo(new File(filePath.toString()));
System.out.println("file saved to: " + filePath);
return newFileName;
}
}
多个文件上传
多文件上传,其实和单个文件上传类似,我们不过是处理一个资源列表文件,其他和单个文件类似。
package com.example.springbootmybatisplusdemo.controller;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.nio.file.*;
@RestController
@RequestMapping("/file")
public class FileHandleController {
private static String UPLOAD_DIR = System.getProperty("user.dir") + File.separator + "uploads";
@PostMapping("/upload/multi")
public String upload(@RequestParam("files") MultipartFile[] files) throws IOException {
System.out.println(files.getClass().getName());
StringBuilder sb = new StringBuilder();
for (MultipartFile file: files) {
if (file.getSize() <= 0) {
continue;
}
System.out.println("file type: " + file.getContentType());
final String newFileName = save(file);
System.out.println("upload file: " + file.getName());
sb.append(newFileName);
sb.append(", ");
}
return sb.toString();
}
private String save(MultipartFile file) throws IOException {
String newFileName = file.getOriginalFilename() + "-" + System.currentTimeMillis();
final Path filePath = Paths.get(UPLOAD_DIR, newFileName);
// method-1
Files.write(filePath, file.getBytes());
// method-2
// file.transferTo(new File(filePath.toString()));
System.out.println("file saved to: " + filePath);
return newFileName;
}
}
文件下载
文件下载,根据提交的文件信息,在我们的资源服务器中查找是否有,然后读取,写入到 response 中,注意,我们需要在 header 中声明相关的配置信息。
package com.example.springbootmybatisplusdemo.controller;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.nio.file.*;
@RestController
@RequestMapping("/file")
public class FileHandleController {
private static String UPLOAD_DIR = System.getProperty("user.dir") + File.separator + "uploads";
@GetMapping("/download")
public boolean download(@RequestParam("fileName") String fileName, HttpServletResponse response) {
String filePath = UPLOAD_DIR + File.separator + fileName;
System.out.println(filePath);
Path path = Paths.get(filePath);
boolean flag = false;
// method-1
if (Files.exists(path) && Files.isReadable(path)) {
// read and copy
File file = new File(filePath);
response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
byte[] buf = new byte[1024];
BufferedInputStream bis = null;
OutputStream out = null;
try {
out = response.getOutputStream();
bis = new BufferedInputStream(new FileInputStream(file));
int i = bis.read(buf);
while (i != -1) {
out.write(buf, 0, buf.length);
out.flush();
i = bis.read(buf);
}
flag = true;
} catch (FileNotFoundException e) {
e.printStackTrace();
System.out.println("FileNotFoundException");
} catch (IOException e) {
e.printStackTrace();
System.out.println("IOException");
} finally {
if (bis != null) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
System.out.println("bis Close exception");
}
}
}
}
// method-2
/**
try {
response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
response.setContentType("application/octet-stream");
Files.copy(path, response.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
System.out.println("download file error");
}
*/
System.out.println("file download result: " + flag);
return flag;
}
}
参考: