SpringBoot 整合 apache fileupload 轻松实现文件上传与下载(通用版)
01、背景介绍
在上篇文章中,我们介绍在 Spring Boot 中利用 MultipartFile 对象实现文件上传的案例。
其实在 Java Web 项目,还有另一个可以实现文件上传的常用工具库:apache fileupload。
如果要将以前的文件上传代码无缝切换到 Spring Boot 工程中,如何处理呢?
今天通过这篇文章,我们一起来了解一下实现方式。
02、方案实践
在此,我们以Thymeleaf
页面模板引擎为例,简单介绍利用 apache fileupload 工具实现文件上传的功能。
2.1、添加相关依赖包
首先创建一个基础的 Spring Boot 项目,并引入相关的依赖包。
<!--apache fileupload 文件上传组件-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.5</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.7</version>
</dependency>
2.2、添加相关配置参数
默认情况下,Spring Boot 会自动装配文件上传相关功能的配置信息,为了避免被 spring mvc 接管,在此需要将其关闭。
在application.properties
配置文件中添加如下配置信息即可。
# 表示是否开启文件上传支持,默认为 true
spring.servlet.multipart.enabled=false
2.3、文件上传示例
环境搭建完成之后,在src/main/resources/templates
目录下,创建一个简单的多文件上传页面apacheUpload.html
,内容如下:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8" />
<title>apache文件上传demo</title>
</head>
<body>
<h1>多文件上传页面</h1>
<form method="post" action="/apacheFileUpload" enctype="multipart/form-data">
文件1:<input type="file" name="files"><br>
文件2:<input type="file" name="files"><br>
表单1:<input type="text" name="name"><br>
<hr>
<input type="submit" value="提交">
</form>
</body>
</html>
对应文件上传的Controller
类,示例如下:
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.IOUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
@Controller
public class ApacheFileController {
/**
* 定义文件上传的目录
*/
private static String FILE_DIR = "/Users/demo/file";
/**
* 访问 upload3 路径时,跳转到apacheUpload.html页面
* @return
*/
@GetMapping("/upload3")
public String index() {
return "apacheUpload";
}
/**
* 上传文件,支持多文件/表单上传
* @param request
* @throws Exception
*/
@PostMapping("/apacheFileUpload")
@ResponseBody
public String fileUpload(HttpServletRequest request) throws Exception {
// 判断上传的文件是普通的表单还是带文件的表单
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if(!isMultipart){
// 终止方法运行,说明这是一个普通的表单,直接返回
return "Upload file fail";
}
// 1.创建DiskFileItemFactory对象,处理文件上传路径或者大小限制的
DiskFileItemFactory factory = getDiskFileItemFactory();
// 2.获取ServletFileUpload
ServletFileUpload upload = getServletFileUpload(factory);
// 3.处理上传的文件
List<FileItem> fileItems = upload.parseRequest(request);
for (FileItem fileItem : fileItems) {
// 判断上传的文件是普通的表单还是带文件的表单
if (fileItem.isFormField()) {
String name = fileItem.getFieldName();
String value = fileItem.getString("UTF-8"); // 处理乱码
System.out.println(name + ": " + value);
} else {
// 处理文件
String filePath = FILE_DIR + "/" + fileItem.getName();
try(InputStream inputStream = fileItem.getInputStream();
OutputStream outputStream = new FileOutputStream(filePath)) {
// 拷贝文件流
IOUtils.copy(inputStream, outputStream);
}
// 清除临时文件
fileItem.delete();
System.out.println("上传成功,文件名:" + fileItem.getName());
}
}
return "Upload file success";
}
/**
* 创建DiskFileItemFactory对象
* @return
*/
private DiskFileItemFactory getDiskFileItemFactory() {
DiskFileItemFactory factory = new DiskFileItemFactory();
// 设置一个缓冲区大小, 当文件大于这个缓冲区大小的时候, 就会放到临时磁盘目录,防止内存崩溃
factory.setSizeThreshold(1024 * 1024);
// 设置临时磁盘目录, 接收上传的 File
factory.setRepository(new File(FILE_DIR + "/cache"));
return factory;
}
/**
* 获取ServletFileUpload
* @param factory
* @return
*/
private ServletFileUpload getServletFileUpload(DiskFileItemFactory factory) {
ServletFileUpload upload = new ServletFileUpload(factory);
// 监听上传进度
upload.setProgressListener(new ProgressListener() {
@Override
public void update(long pBytesRead, long pContentLength, int pItems) {
System.out.println("总大小:" + pContentLength + ",已上传:" + pBytesRead);
}
});
// 处理乱码问题
upload.setHeaderEncoding("UTF-8");
// 设置单个文件的最大值,-1:表示无限制
upload.setFileSizeMax(-1L);
return upload;
}
}
启动服务后,访问http://localhost:8080/upload3
,可以看到如下界面:
选择文件并填写相关参数,点击“提交”,在服务器指定存储上传文件的目录下,可以看到上传的文件信息。
在服务控制台,还可以看到上传的进度信息。
#### 2.4、文件下载示例
文件下载功能,应用场景也特别多,通常以 restful 方式访问服务端并获取资源,这个在之前的文章中有所介绍,本次介绍一下,通用实现示例如下:
@Controller
public class DownloadController {
private static final String SRC_PATH = "/Users/demo/file";
/**
* 通过文件名获取文件并以流的形式返回给客户端
* @param filename
* @param response
*/
@GetMapping("/download/{filename:.+}")
public void download(@PathVariable String filename, HttpServletResponse response) throws Exception {
File file = new File(SRC_PATH +'/'+ filename);
if(!file.exists()){
throw new RuntimeException("下载文件不存在");
}
response.reset();
response.setContentType("application/octet-stream");
response.setCharacterEncoding("UTF-8");
response.setContentLength((int) file.length());
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
// 使用缓存流,边读边写
try(BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file))) {
OutputStream os = response.getOutputStream();
byte[] buff = new byte[1024];
int i;
while ((i = bis.read(buff)) != -1) {
os.write(buff, 0, i);
os.flush();
}
} catch (IOException e) {
throw new RuntimeException("下载文件失败");
}
}
}
启动服务后,在浏览器中访问上传的文件名,例如地址http://localhost:8080/download/opencv-demo.jar
,文件将以流的形式下载到本地。
其中URLEncoder.encode(filename, "UTF-8")
用意在于,防止下载中文文件名乱码。
03、小结
本文主要围绕在 Spring Boot 中无缝集成 apache fileupload 工具实现文件的上传功能相关示例介绍,如果有描述不对的地方,欢迎大家留言指出。
最后。