spring boot如何实现切割分片上传

这篇文章主要介绍了spring boot如何实现切割分片上传,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

文件上传是web开发中经常会遇到的

springboot的默认配置为10MB,大于10M的是传不上服务器的,需要修改默认配置

但是如果修改支持大文件又会增加服务器的负担。

当文件大于一定程度时,不仅服务器会占用大量内存,而且http传输极可能会中断。

可以采用切割分片上传

html5提供的文件API中可以轻松的对文件进行分割切片,然后通过ajax异步处理向服务器传输数据,突破对大文件上传的限制,

同时异步处理在一定程度上也提高了文件上传的效率。

过程描述:

  • 将文件分割成N片
  • 处理分片,前台会多次调用上传接口,每次都会上传文件的一部分到服务端
  • N个分片都上传完成后,将N个文件合并为一个文件,并将N个分片文件删除

1.服务端

(1)添加依赖


   commons-fileupload
   commons-fileupload
   1.3.3

(2)UploadController

package com.example.demo.controller;

import com.example.demo.core.Result;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
@CrossOrigin
@Controller
@RequestMapping("/api/upload")
public class UploadController {
  @PostMapping("/part")
  @ResponseBody
  public Result bigFile(HttpServletRequest request, HttpServletResponse response, String guid, Integer chunk, MultipartFile file, Integer chunks) {
    try {
      String projectUrl = System.getProperty("user.dir").replaceAll("\\\\", "/");
      ;
      boolean isMultipart = ServletFileUpload.isMultipartContent(request);
      if (isMultipart) {
        if (chunk == null) chunk = 0;
        // 临时目录用来存放所有分片文件
        String tempFileDir = projectUrl + "/upload/" + guid;
        File parentFileDir = new File(tempFileDir);
        if (!parentFileDir.exists()) {
          parentFileDir.mkdirs();
        }
        // 分片处理时,前台会多次调用上传接口,每次都会上传文件的一部分到后台
        File tempPartFile = new File(parentFileDir, guid + "_" + chunk + ".part");
        FileUtils.copyInputStreamToFile(file.getInputStream(), tempPartFile);
      }

    } catch (Exception e) {
      return Result.failMessage(400,e.getMessage());
    }
    return Result.successMessage(200,"上次成功");
  }

  @RequestMapping("merge")
  @ResponseBody
  public Result mergeFile(String guid, String fileName) {
    // 得到 destTempFile 就是最终的文件
    String projectUrl = System.getProperty("user.dir").replaceAll("\\\\", "/");
    try {
      String sname = fileName.substring(fileName.lastIndexOf("."));
      //时间格式化格式
      Date currentTime = new Date();
      SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmssSSS");
      //获取当前时间并作为时间戳
      String timeStamp = simpleDateFormat.format(currentTime);
      //拼接新的文件名
      String newName = timeStamp + sname;
      simpleDateFormat = new SimpleDateFormat("yyyyMM");
      String path = projectUrl + "/upload/";
      String tmp = simpleDateFormat.format(currentTime);
      File parentFileDir = new File(path + guid);
      if (parentFileDir.isDirectory()) {
        File destTempFile = new File(path + tmp, newName);
        if (!destTempFile.exists()) {
          //先得到文件的上级目录,并创建上级目录,在创建文件
          destTempFile.getParentFile().mkdir();
          try {
            destTempFile.createNewFile();
          } catch (IOException e) {
            e.printStackTrace();
          }
        }
        for (int i = 0; i < parentFileDir.listFiles().length; i++) {
          File partFile = new File(parentFileDir, guid + "_" + i + ".part");
          FileOutputStream destTempfos = new FileOutputStream(destTempFile, true);
          //遍历"所有分片文件"到"最终文件"中
          FileUtils.copyFile(partFile, destTempfos);
          destTempfos.close();
        }
        // 删除临时目录中的分片文件
        FileUtils.deleteDirectory(parentFileDir);
        return Result.successMessage(200,"合并成功");
      }else{
        return Result.failMessage(400,"没找到目录");
      }

    } catch (Exception e) {
      return Result.failMessage(400,e.getMessage());
    }

  }

}

说明:

注解 @CrossOrigin 解决跨域问题

(3)Result

package com.example.demo.core;

import com.alibaba.fastjson.JSON;

/**
 * Created by Beibei on 19/02/22
 * API响应结果
 */
public class Result {
  private int code;
  private String message;
  private T data;

  public Result setCode(Integer code) {
    this.code = code;
    return this;
  }

  public int getCode() {
    return code;
  }

  public String getMessage() {
    return message;
  }

  public Result setMessage(String message) {
    this.message = message;
    return this;
  }

  public T getData() {
    return data;
  }

  public Result setData(T data) {
    this.data = data;
    return this;
  }

  @Override
  public String toString() {
    return JSON.toJSONString(this);
  }

  public static  Result fail(Integer code,T data) {
    Result ret = new Result();
    ret.setCode(code);
    ret.setData(data);
    return ret;
  }

  public static  Result failMessage(Integer code,String msg) {
    Result ret = new Result();
    ret.setCode(code);
    ret.setMessage(msg);
    return ret;
  }
  public static  Result successMessage(Integer code,String msg) {
    Result ret = new Result();
    ret.setCode(code);
    ret.setMessage(msg);
    return ret;
  }

  public static  Result success(Integer code,T data) {
    Result ret = new Result();
    ret.setCode(code);
    ret.setData(data);
    return ret;
  }

}

2.前端

(1)使用插件

webuploader,下载  https://github.com/fex-team/webuploader/releases




  
  
  
  


  
选择文件

spring boot如何实现切割分片上传_第1张图片

(2)不使用插件

直接用HTML5的File API



  
    
    
  
  
    




spring boot如何实现切割分片上传_第2张图片

3.优化 

springboot的默认配置为10MB,前端分片改为20M时,就会报错

org.apache.tomcat.util.http.fileupload.FileUploadBase$SizeLimitExceededException: the request was rejected because its size (10486839) exceeds the configured maximum (10485760)

解决方法:

在 src/main/resources 下的 application.properties里添加

spring.servlet.multipart.max-file-size=30MB
spring.servlet.multipart.max-request-size=35MB

说明:

设置的数值虽好比前端传过来的大,要不容易报错

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

你可能感兴趣的:(spring boot如何实现切割分片上传)