思路:前台上传文件分片到后台存储,并保存路径为数组,上传完毕后合并,使用ajax同步上传,后期再优化
后台代码:
package com.savethink.web.opera.controller.video;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import com.savethink.web.opera.common.ControllerResult;
import com.savethink.web.opera.common.StringUtil;
/**
* 视频上传
*
* @author SaveThink
*
*/
@Controller
@RequestMapping(value = "/videoUploadController")
public class VideoUploadController {
@Value("${upload.file.root}")
private String uploadRoot;
@Value("${upload.file.video}")
private String uploadVideo;
@Value("${upload.file.video.type}")
private String uploadVideoType;
// 分片上传
@RequestMapping(value = "/upload", method = RequestMethod.POST)
@ResponseBody
public ControllerResult upload(HttpServletRequest request) {
ControllerResult result = new ControllerResult();
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
// 获得文件:
MultipartFile file = multipartRequest.getFile("file");
int index = Integer.parseInt(multipartRequest.getParameter("index"));
File uploadFile = new File(getUploadVideoPath() + File.separator + "temp", index+".tmp");
if (!uploadFile.getParentFile().exists()) { // 判断文件父目录是否存在
uploadFile.getParentFile().mkdirs();
}
createFile(file, uploadFile);
File originalFilePath = new File(uploadFile.getParentFile().getPath().toString() + File.separator + file.getOriginalFilename());
result.msg = uploadFile.toPath().toString();
result.message = originalFilePath.toPath().toString();
return result;
}
// 合并所有文件
@RequestMapping(value = "/merge", method = RequestMethod.POST)
@ResponseBody
public ControllerResult merge(@RequestParam(value = "tempsFile[]") String[] tempsFile, HttpServletRequest request) {
ControllerResult result = new ControllerResult();
String originalFilePath = request.getParameter("originalFilePath");
boolean flag = mergeFiles(tempsFile, originalFilePath);
return result;
}
// 获取视频上传的路径
private String getUploadVideoPath() {
StringBuffer sb = new StringBuffer(uploadRoot);
sb.append(File.separator);
sb.append(uploadVideo);
return sb.toString();
}
// 转储文件
public static boolean createFile(MultipartFile file,File uploadFile) {
boolean flag = false;
try {
file.transferTo(uploadFile);
flag = true;
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return flag;
}
public static List<File> handleTempsPath(String filePath) {
File file = new File(filePath);
File[] fs = file.listFiles();
List<File> files = new ArrayList<>();
for(int i = 0; i < fs.length; i++) {
if(fs[i].isFile()) {
files.add(fs[i]);
System.out.println(fs[i].getName());
}
}
return files;
}
// 利用nio FileChannel合并多个文件
@SuppressWarnings("resource")
public static boolean mergeFiles(String[] fpaths, String resultPath) {
if (fpaths == null || fpaths.length < 1 || StringUtil.isEmpty(resultPath)) {
return false;
}
if (fpaths.length == 1) {
return new File(fpaths[0]).renameTo(new File(resultPath));
}
File[] files = new File[fpaths.length];
for (int i = 0; i < fpaths.length; i ++) {
files[i] = new File(fpaths[i]);
if (StringUtil.isEmpty(fpaths[i]) || !files[i].exists() || !files[i].isFile()) {
return false;
}
}
File resultFile = new File(resultPath);
try {
FileChannel resultFileChannel = new FileOutputStream(resultFile, true).getChannel();
for (int i = 0; i < fpaths.length; i ++) {
FileChannel blk = new FileInputStream(files[i]).getChannel();
resultFileChannel.transferFrom(blk, resultFileChannel.size(), blk.size());
blk.close();
}
resultFileChannel.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
}
for (int i = 0; i < fpaths.length; i ++) {
files[i].delete();
}
return true;
}
}
前台html代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>文件上传</title>
<style>
#test {
width: 200px;
height: 100px;
border: 1px solid green;
display: none;
}
#img {
width: 50px;
height: 50px;
display: none;
}
#upimg {
text-align: center;
font: 8px/10px '微软雅黑', '黑体', sans-serif;
width: 300px;
height: 10px;
border: 1px solid green;
}
#load {
width: 0%;
height: 100%;
background: green;
text-align: center;
}
</style>
</head>
<body>
<form enctype="multipart/form-data">
<div id="upimg">
<div id="load"></div>
</div>
<input type="file" name="file" id="videoFile" />
<input type="button" value="上传" onclick="upload();" />
<input type="submit" value="submit" />
</form>
<div id="test">测试是否DIV消失</div>
<script type="text/javascript" src="lib/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript">
var token = parent.window.document.getElementById("token").value;
// 发送请求
function upload(){
// 进度条
var progressBar=document.getElementById('load');
var num=document.getElementById('upimg');
var tempsFile=new Array();
var blob = document.getElementById("videoFile").files[0];
// 每片文件5M
var perPiece = 1024 * 1024 * 50;
var originalFilePath;
var start = 0,
end = 0,
index = 0,
totalPieces,
filesize = blob.size,
filename = blob.name;
// 计算文件切片总数
// totalPieces = Math.ceil(filesize / perPiece);
totalPieces = filesize%perPiece==0?filesize/perPiece:filesize/perPiece+1;
console.log("===================");
console.log("切片总数:"+totalPieces);
console.log("索引:"+index);
// 如果文件为空,则退出
if(!blob){
alert('请选择文件');
return;
}
// 上传文件
while(start < filesize) {
// 切片上传
end = start + perPiece;
if(end > filesize) {
// 一次性上传
end = filesize;
}
// 分割文件核心部分slice
var chunk = blob.slice(start, end);
var sliceIndex = blob.name + index;
console.log("=========sliceIndex==========:"+sliceIndex);
var formData = new FormData();
formData.append('token',token);
formData.append("file", chunk, filename);
formData.append("totalPieces", totalPieces);
formData.append("index", index);
$.ajax({
url: "videoUploadController/upload",
type: "POST",
async:false,
cache: false,
data: formData,
processData: false,
contentType: false,
}).done(function(res) {
tempsFile.push(res.msg);
originalFilePath = res.message;
// 进度条
pecent=100*(end)/filesize;
if(pecent>100){
pecent=100;
}
progressBar.style.width=pecent+'%';
progressBar.innerHTML = parseInt(pecent)+'%';
}).fail(function(res) {
alert('文件发送失败,请重新发送');
progressBar.style.width='0%';
});
start = end;
index ++;
}
merge(tempsFile, originalFilePath);
console.log("上传成功");
}
function merge(tempsFile, originalFilePath) {
$.ajax({
url:"videoUploadController/merge",
dataType:"json",
async:false,
data:{"token":token, "originalFilePath":originalFilePath, "tempsFile": tempsFile},
type:"POST",
beforeSend:function(){
//请求前的处理
},
success:function(req){
},
complete:function(){
//请求完成的处理
},
error:function(){
//请求出错处理
}
});
}
</script>
</body>
</html>