前段时间做了个网盘,所以添加了一个大文件上传接口,这里记录一下
直接给出代码:
前端页面:
大文件上传接口
选择文件
上传所用时间:
0s
后端代码:
先在application.yml中添加配置:
spring:
http:
encoding:
force: true
charset: utf-8
multipart:
max-file-size: 100MB
max-request-size: 100MB
package com.hm.pan.controller;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.commons.io.FileUtils;
import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.hm.pan.annotation.CheckLogin;
import com.hm.pan.model.FileInfo;
import com.hm.pan.model.ResultObj;
import com.hm.pan.model.User;
import com.hm.pan.model.UserFile;
import com.hm.pan.service.FileUploadService;
import com.hm.pan.service.UserFileService;
@RestController
@RequestMapping("bigFile")
@CheckLogin
public class BigFileUploadController {
@Resource
private FileUploadService fileUploadService;
@Resource
private UserFileService userFileService;
@Value("${upload-path}")
private String uploadPath;
// 通过MD5查找文件信息,如果有的话,就不用上传文件,只要向用户文件里插入文件信息就行
@GetMapping("findResourceFileExistsByMd5")
public Object findMd5(String md5value, String fileName, String caozuoPath, HttpSession session)
throws Exception {
Timestamp uploadTime = new Timestamp(System.currentTimeMillis());
UserFile oneFileByPath2 = userFileService.getOneFileByPath(caozuoPath);// 通过前端传过来的操作路径找到该用户文件对象
Long fatherId2 = oneFileByPath2.getUserfileId();
// log.info("================"+md5);
User user = (User) session.getAttribute("user"); // 通过session拿到前端用户信息
// log.info("-----------------"+user);
Long userId = user.getUserId(); // 获取前端传过来的用户id
// log.info("+++++++++++++++++"+userId);
String newName = getName(fileName);
Object filemd5 = fileUploadService.findMd5(md5value);
// 如果数据里有MD5,就不用上传,但是用户文件需要插入。
if (filemd5 != null) {
Object fileInfo = fileUploadService.findByNameFatherId(fileName, fatherId2);
if (fileInfo != null) {
fileUploadService.insertUserFile(uploadTime, newName, md5value, fatherId2, userId);
} else {
fileUploadService.insertUserFile(uploadTime, fileName, md5value, fatherId2, userId);
}
return new ResultObj(200, fileInfo);
} else {
return new ResultObj(400, filemd5);
}
}
//这里通过文件编号guid和分片数chunk来检查分片文件,其实严格一点还需要检查分片文件的偏移位置和文件大小,以防止分片文件上传失败的情况,这里表示一下就行,需要自己改改
@GetMapping("findResourceChunkExists")
public ResultObj findResourceChunkExists(String guid,Integer chunk){
// 临时目录用来存放所有分片文件
String tempFileDir = uploadPath+ "/bigFileTemp/" + guid;
File parentFileDir = new File(tempFileDir);
File tempPartFile = new File(parentFileDir, guid + "_" + chunk + ".part");
if(tempPartFile.exists()) {
return new ResultObj(200, "存在");
}else {
return new ResultObj(404, "不存在");
}
}
// 如果前面的MD5没有找到文件信息的话,就会返回一个400到前端,前端再根据判断,把文件给上传。
@PostMapping("saveFileInfo")
public ResultObj aa(String guid, String md5value, Long fileSize, String fileName,
String caozuoPath, HttpSession session, HttpServletRequest req) throws Exception {
Timestamp uploadTime = new Timestamp(System.currentTimeMillis());
System.out.println("saveFileInfo:");
System.out.println("------------guid:"+guid);
System.out.println("------------md5value:"+md5value);
System.out.println("------------fileSize:"+fileSize);
System.out.println("------------fileName:"+fileName);
System.out.println("------------caozuoPath:"+caozuoPath);
String newName = getName(fileName);
// 将文件存到指定项目文件下,没有的话就创建
// File realpath = ResourceUtils.getFile("");
// String realpath = req.getServletContext().getRealPath("/upload");
// String filePath = realpath+fileName;
File dest = mergeFile(guid, fileName);
// log.info("<<<<<<<<<<<<<<<< "+file2.getAbsolutePath());
FileInfo fileInfo = new FileInfo();
fileInfo.setFilePath(dest.getPath()); // 获取文件的相对路径
fileInfo.setFileMd5(md5value);
fileInfo.setFileSize(fileSize);
User user = (User) session.getAttribute("user"); // 通过session拿到前端用户信息
// log.info("-----------------"+user);
Long userId = user.getUserId(); // 获取前端传过来的用户id
// log.info("+++++++++++++++++"+userId);
Object fileinfo = fileUploadService.insertFileInfo(fileInfo);
UserFile oneFileByPath = userFileService.getOneFileByPath(caozuoPath); // 通过操作路径找到fatherId
if (oneFileByPath != null && fileinfo != null) {
Long fatherId = oneFileByPath.getUserfileId();
Object findByName = fileUploadService.findByNameFatherId(fileName, fatherId);
if (findByName != null) {
fileUploadService.insertUserFile(uploadTime, newName, md5value, fatherId, userId);
} else {
fileUploadService.insertUserFile(uploadTime, fileName, md5value, fatherId, userId);
}
return new ResultObj(200, fileinfo);
}
return new ResultObj(400, fileinfo);
}
// 获取不同的文件名
public String getName(String fileName) {
// 解决文件名重名,以时间戳+随机数
// 获得当前时间
SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
// 转换为字符串
String formDate = format.format(new Date());
// 随机生成文件编号
int random = new Random().nextInt(1000);
String[] split = fileName.split("\\.");
// 1.2.3.4.cc
// mm
StringBuffer sb = new StringBuffer(split[0]);
for (int i = 1; i < split.length - 1; i++) {
sb.append('.').append(split[i]);
}
sb.append('_').append(formDate).append(random);
if (fileName.indexOf(".") != -1) {
sb.append('.').append(split[split.length - 1]);
}
String name = sb.toString();
return name;
}
/**
* 上传文件
* @param request
* @param response
* @param guid
* @param chunk
* @param file
* @param chunks
*/
@RequestMapping("upload")
public void bigFile(HttpServletRequest request, HttpServletResponse response,String guid,Integer chunk, MultipartFile file,Integer chunks){
try {
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if (isMultipart) {
// 临时目录用来存放所有分片文件
String tempFileDir = uploadPath+ "/bigFileTemp/" + 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) {
e.printStackTrace();
}
}
/**
* 合并文件
* @param guid
* @param fileName
* @throws Exception
*/
public File mergeFile(String guid,String fileName){
// 得到 destTempFile 就是最终的文件
try {
File parentFileDir = new File(uploadPath+ "/bigFileTemp/" + guid);
if(parentFileDir.isDirectory()){
// File destTempFile = new File(uploadPath+ "/bigFileTemp/merge/", fileName);
SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd");
// 转换为字符串
String formDate = format.format(new Date());
File destTempFile = new File(uploadPath+"/"+formDate, fileName);
System.out.println(destTempFile.getPath());
if(!destTempFile.exists()){
//先得到文件的上级目录,并创建上级目录,在创建文件,
destTempFile.getParentFile().mkdirs();
try {
//创建文件
destTempFile.createNewFile(); //上级目录没有创建,这里会报错
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println(parentFileDir.listFiles().length);
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 destTempFile;
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
return null;
}
}