上传文件慢,SpringBoot分片上传文件
Posted killer-leon
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了上传文件慢,SpringBoot分片上传文件相关的知识,希望对你有一定的参考价值。
Java上传文件慢,大文件上传卡顿,请求超时怎么办?
话不多说直接上代码,代码复制过去可以直接使用
第一步:创建后端代码
package cn.leon.demo.rest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.FileOutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;
/**
* 分片上传文件相关接口
*
* @author leon
* @date 2021/03/19 17:40:06
*/
@Slf4j
@RequestMapping("/chunk-upload")
@RestController
public class UploadFileController
/**
* 文件上传路径,配置文件配置或者这里写死也行
* ##fileUploadPath
* file.upload.path=/Users/leon/Desktop
**/
@Value("$file.upload.path")
private String fileUploadPath;
/**
* 分片上传小文件
*
* @param clientId 客户端ID,每个客户端每次上传时生成,保持唯一
* @param chunkId 分片ID,从0开始累加,每次上保持传唯一
* @param chunks 分片总数
* @param file
* @return java.lang.String
* @author leon
* @date 2021/04/07 17:16:59
*/
@CrossOrigin
@PostMapping("/part")
public Result bigFile(
MultipartFile file,
@RequestParam(name = "clientId", required = true) String clientId,
@RequestParam(name = "chunks", required = true) Integer chunks,
@RequestParam(name = "chunkId", required = true) Integer chunkId) throws Exception
log.info("开始上传分片文件,客户端ID:,总分片数:,分片ID:", clientId, chunks, chunkId);
// 文件存放目录:临时目录用来存放所有分片文件
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd/");
String dateStr = sdf.format(new Date());
//临时文件目录
String tempFileDir = fileUploadPath + File.separator + dateStr + clientId;
File parentFileDir = new File(tempFileDir);
if (!parentFileDir.exists())
parentFileDir.mkdirs();
// 分片处理时,前台会多次调用上传接口,每次都会上传文件的一部分到后台
File tempPartFile = new File(parentFileDir, clientId + "_" + chunkId + ".part");
FileUtils.copyInputStreamToFile(file.getInputStream(), tempPartFile);
log.info("分片文件上传成功,分片ID:", chunkId);
return "ok";
/**
* 上传分片文件完成后合并成一个大文件
*
* @param clientId 客户端ID,每次上传时生成和分片上传时参数保持一致
* @param fileName 原文件名
* @return java.lang.String 返回最终保存文件路径
* @author leon
* @date 2021/04/07 17:13:46
*/
@CrossOrigin
@PostMapping("/merge")
public String mergeFile(
@RequestParam(name = "clientId", required = true) String clientId,
@RequestParam(name = "fileName", required = true) String fileName) throws Exception
log.info("开始合并文件,客户端ID:,文件名:", clientId, fileName);
// 文件存放目录
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd/");
String dateStr = sdf.format(new Date());
//最终文件上传目录
String fileSavePath = fileUploadPath + File.separator + dateStr;
//临时文件目录
String tmpFileSavePath = fileSavePath + clientId;
//最终文件上传文件名
String newFileName = UUID.randomUUID().toString();
if (fileName.indexOf(".") != -1)
newFileName += fileName.substring(fileName.lastIndexOf("."));
//创建父文件夹
File parentFileDir = new File(tmpFileSavePath);
if (parentFileDir.isDirectory())
File destNewFile = new File(fileSavePath, newFileName);
if (!destNewFile.exists())
//先得到文件的上级目录,并创建上级目录,再创建文件
destNewFile.getParentFile().mkdir();
destNewFile.createNewFile();
//遍历"所有分片文件"到"最终文件"中,此处一定要按照顺序合并文件,不然会导致文件合并错乱不可用
for (int i=0;i<parentFileDir.listFiles().length;i++)
FileOutputStream destNewFileFos = new FileOutputStream(destNewFile, true);
FileUtils.copyFile(new File(parentFileDir, clientId + "_" + i + ".part"), destNewFileFos);
destNewFileFos.close();
// 删除临时目录中的分片文件
FileUtils.deleteDirectory(parentFileDir);
log.info("合并文件完成,客户端ID:,文件名:", clientId, fileName);
return fileSavePath + newFileName;
第二步:创建前端代码测试
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>分片上传文件测试</title>
<script src="http://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
</head>
<body>
<div id="uploader">
<div class="btns">
<input id="file" name="file" type="file"/>
<br>
<br>
<button id="startBtn">
开始上传
</button>
</br>
</br>
</div>
<div id="output">
</div>
</div>
</body>
<script type="text/javascript">
var status = 0;//上传状态
var startDate;
var page =
init: function()
$("#startBtn").click($.proxy(this.upload, this));
,
upload: function()
startDate = (new Date()).getTime();
console.log("开始上传文件......");
status = 0;
var clientId = this.generateClientId();
var file = $("#file")[0].files[0], //文件对象
fileName = file.name, //文件名
size = file.size; //总大小
var shardSize = 1024 * 1024, //以1MB为一个分片
// var shardSize = 500 * 1024, //以500kb为一个分片
shardCount = Math.ceil(size / shardSize); //总片数
console.log("每个分片文件1MB,总分片数:"+shardCount);
// console.log("每个分片文件500kb,总分片数:"+shardCount);
for(var i = 0;i < shardCount;++i)
//计算每一片的起始与结束位置
var start = i * shardSize,
end = Math.min(size, start + shardSize);
var partFile = file.slice(start,end);
this.partUpload(clientId,partFile,fileName,shardCount,i);
console.log("第"+i+"个分片文件上传成功");
var endDate = (new Date()).getTime();
console.log("所有分片文件上传请求发送成功,总耗时:"+(endDate-startDate)+"毫秒");
,
partUpload:function(clientId,partFile,fileName,chunks,chunkId)
//构造一个表单,FormData是HTML5新增的
var now = this;
var form = new FormData();
form.append("clientId", clientId);
form.append("file", partFile); //slice方法用于切出文件的一部分
form.append("fileName", fileName);
form.append("chunks", chunks); //总片数
form.append("chunkId", chunkId); //当前是第几片
//Ajax提交
$.ajax(
url: "http://localhost:8080/chunk-upload/part",
type: "POST",
data: form,
async: true, //异步
processData: false, //很重要,告诉jquery不要对form进行处理
contentType: false, //很重要,指定为false才能形成正确的Content-Type
success: function(data)
status++;
if(data.code == 0)
$("#output").html(status+ " / " + chunks);
else
alert('出现异常:'+data.message);
if(status==chunks)
var endDate = (new Date()).getTime();
console.log("所有分片文件上传成功,总耗时:"+(endDate-startDate)+"毫秒")
now.mergeFile(clientId,fileName);
);
,
mergeFile:function(clientId,fileName)
var formMerge = new FormData();
formMerge.append("clientId", clientId);
formMerge.append("fileName", fileName);
$.ajax(
url: "http://localhost:8080/chunk-upload/merge",
type: "POST",
data: formMerge,
processData: false, //很重要,告诉jquery不要对form进行处理
contentType: false, //很重要,指定为false才能形成正确的Content-Types
success: function(data)
if(data.code == 0)
var endDate = (new Date()).getTime();
console.log("上传文件成功,总耗时:"+(endDate-startDate)+"毫秒");
alert('上传成功!');
else
alert('出现异常:'+data.message);
);
,
generateClientId:function()
var counter = 0;
var clientId = (+new Date()).toString( 32 ),
i = 0;
for ( ; i < 5; i++ )
clientId += Math.floor( Math.random() * 65535 ).toString( 32 );
return clientId + (counter++).toString( 32 );
;
$(function()
page.init();
);
</script>
</html>
以上是关于上传文件慢,SpringBoot分片上传文件的主要内容,如果未能解决你的问题,请参考以下文章