SpringBoot 文件上传(带进度条)与下载
一、文件上传
1. 上传文件大小限制的配置
现象:文件上传过大时报FileUploadBase$SizeLimitExceededException异常
Caused by: org.apache.tomcat.util.http.fileupload.FileUploadBase$SizeLimitExceededException: the request was rejected because its size (336738104) exceeds the configured maximum (10485760) at org.apache.tomcat.util.http.fileupload.FileUploadBase$FileItemIteratorImpl.<init>(FileUploadBase.java:805) at org.apache.tomcat.util.http.fileupload.FileUploadBase.getItemIterator(FileUploadBase.java:256) at org.apache.tomcat.util.http.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:280) at org.apache.catalina.connector.Request.parseParts(Request.java:2869) ... 31 more
原因:springboot内置tomact的的文件传输默认为1MB
@ConfigurationProperties( prefix = "spring.http.multipart", ignoreUnknownFields = false ) public class MultipartProperties { private boolean enabled = true; private String location; private String maxFileSize = "1MB"; private String maxRequestSize = "10MB"; private String fileSizeThreshold = "0"; private boolean resolveLazily = false; public MultipartProperties() { } ... }
解决方式:
A. 在application.properties文件中配置,注意MB是大写,也可以换成KB单位
spring.servlet.multipart.enabled=true spring.servlet.multipart.max-file-size=100MB spring.servlet.multipart.max-request-size=150MB
B. java代码配置,这个配置会覆盖配置文件(第一种)中属性的配置,还有若是不设置文件和请求大小,默认无穷大
@Bean public MultipartConfigElement multipartConfigElement() { MultipartConfigFactory factory = new MultipartConfigFactory(); // 文件上传大小 factory.setMaxFileSize("500MB"); // 请求上传大小 factory.setMaxRequestSize("500MB");
return factory.createMultipartConfig(); }
注意:全局异常捕捉,无法正确返回给前端提示。
二、上传进度条
1. pom.xml Maven依赖
<dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.4</version> </dependency>
2. 自定义文件上传监听器
package com.ruhuanxingyun.minio.listener; import com.ruhuanxingyun.minio.common.Constants; import org.apache.commons.fileupload.ProgressListener; import org.springframework.data.redis.core.StringRedisTemplate; import java.util.concurrent.TimeUnit; /** * @description: 文件上传监听器 * @author: ruphie * @date: Create in 2020/12/7 22:20 * @company: ruhuanxingyun */ public class FileUploadProgressListener implements ProgressListener { private String uuid; private StringRedisTemplate stringRedisTemplate; public FileUploadProgressListener(String uuid, StringRedisTemplate stringRedisTemplate) { this.uuid = uuid; this.stringRedisTemplate = stringRedisTemplate; } /** * 计算上传文件进度 * * @param pBytesRead 到目前为止读取文件的比特数 * @param pContentLength 文件总大小 * @param pItems 目前正在读取第几个文件 */ @Override public void update(long pBytesRead, long pContentLength, int pItems) { // 上传的文件长度、文件个数不能为0 if (pContentLength == 0 || pItems == 0) { return; } // 为避免性能问题,取每读取1M更新状态 // 百分比率 int percent = (int) (pBytesRead * 100.0 / pContentLength); String key = String.format("%s:%s", Constants.FILE_UPLOAD_PROGRESS, uuid); stringRedisTemplate.opsForValue().set(key, String.valueOf(percent), 5, TimeUnit.MINUTES); } }
3. 自定义文件上传解析器
package com.ruhuanxingyun.minio.config; import com.ruhuanxingyun.minio.listener.FileUploadProgressListener; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileUpload; import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Component; import org.springframework.web.multipart.MultipartException; import org.springframework.web.multipart.MultipartResolver; import org.springframework.web.multipart.commons.CommonsMultipartResolver; import javax.servlet.http.HttpServletRequest; import java.util.List; import java.util.UUID; /** * @description: 文件上传解析器 * @author: ruphie * @date: Create in 2020/12/7 22:14 * @company: ruhuanxingyun */ @Component public class CustomMultipartResolver extends CommonsMultipartResolver { @Autowired private StringRedisTemplate stringRedisTemplate; @Override protected MultipartParsingResult parseRequest(HttpServletRequest request) throws MultipartException { String encoding = this.determineEncoding(request); FileUpload fileUpload = this.prepareFileUpload(encoding); String uuid = UUID.randomUUID().toString(); fileUpload.setProgressListener(new FileUploadProgressListener(uuid, stringRedisTemplate)); try { List<FileItem> fileItems = ((ServletFileUpload) fileUpload).parseRequest(request); return this.parseFileItems(fileItems, encoding); } catch (FileUploadException e) { throw new MultipartException("Failed to parse multipart servlet request", e); } } @Bean public MultipartResolver multipartResolver() { return new CustomMultipartResolver(); } }
4. 获取上传进度
/** * 重置文件上传进度 * * @param uuid 唯一标识符 */ public void reset(String uuid) { String key = String.format("%s:%s", Constants.FILE_UPLOAD_PROGRESS, uuid); stringRedisTemplate.delete(key); } /** * 文件上传进度 * * @param uuid 唯一标识符 * @return 进度 */ public int progress(String uuid) { String key = String.format("%s:%s", Constants.FILE_UPLOAD_PROGRESS, uuid); String percent = stringRedisTemplate.opsForValue().get(key); if (StrUtil.isNotEmpty(percent)) { // 上传完全 if (StrUtil.equals("100", percent)) { stringRedisTemplate.delete(key); } return Integer.parseInt(percent); } return 0; }