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;
    }

 

posted @ 2019-05-15 11:14  如幻行云  阅读(2791)  评论(0编辑  收藏  举报