spring boot 大文件上传实现方式

Posted gaozs

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring boot 大文件上传实现方式相关的知识,希望对你有一定的参考价值。

控制器
/**
* 上传文件
*
* @param param
* @param request
* @return
* @throws Exception
*/
@ApiOperation(value = "大文件上传")
@PostMapping(value = "/fileUpload")
@ResponseBody
public Result<String> fileUpload(MultipartFileParam param, HttpServletRequest request)
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
String parentId = request.getParameter("parentId");
if (isMultipart)
logger.info("上传文件start。");
try
personKnowledgeService.uploadFileByMappedByteBuffer(param,parentId);
catch (IOException e)
e.printStackTrace();
logger.error("文件上传失败。", param.toString());
return JsonError("上传失败");

logger.info("上传文件end。");

return JsonSuccess("上传成功");




实现方法


/**
* 上传文件方法2
* 处理文件分块,基于MappedByteBuffer来实现文件的保存
*
* @param param
* @throws IOException
*/
@Override
public void uploadFileByMappedByteBuffer(MultipartFileParam param, String parentId) throws IOException

String basePath = System.getProperty("user.dir") + File.separator;
Date now = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
String nowDayStr = sdf.format(now);
String filePath = "knowledge" + File.separator + "upload" + File.separator + nowDayStr + File.separator;

String fileName = param.getName();
String uploadDirPath = basePath + filePath + param.getUid();
String tempFileName = fileName + "_tmp";
File tmpDir = new File(uploadDirPath);
File tmpFile = new File(uploadDirPath, tempFileName);
if (!tmpDir.exists())
tmpDir.mkdirs();


//添加记录
long CHUNK_SIZE = 5242880;//5M
String uid = param.getUid();
PersonKnowledge model = personKnowledgeRepository.findFirstByFileuid(uid);
if (model == null)
model = new PersonKnowledge();
model.setCreateTime(new Date());
model.setCreateId(SecurityUtils.getSubject().getCurrentUser().getId());
if (StringUtils.isEmpty(parentId))
parentId = "ROOT";

model.setParentId(parentId);
model.setAttchmentType(PersonKnowledgeType.文件.getId());
String suffixName = fileName.substring(fileName.lastIndexOf("."));
model.setName(fileName.substring(0, fileName.lastIndexOf("."))); // 新文件名
model.setAttachmentPath(uploadDirPath + File.separator + fileName); //文件路径
model.setSuffix(suffixName.toLowerCase().substring(1));
model.setFileuid(uid);
//获取文件大小
Long size = CHUNK_SIZE * param.getChunks();
String fileSizeString = "";
DecimalFormat df = new DecimalFormat("#.00");
if (size != null)
if (size < 1024)
fileSizeString = df.format((double) size) + "B";
model.setFileSize(fileSizeString);
else if (size < 1048576)
fileSizeString = df.format((double) size / 1024) + "K";
model.setFileSize(fileSizeString);
else if (size < 1073741824)
fileSizeString = df.format((double) size / 1048576) + "M";
model.setFileSize(fileSizeString);
else
fileSizeString = df.format((double) size / 1073741824) + "G";
model.setFileSize(fileSizeString);


personKnowledgeRepository.save(model);


RandomAccessFile tempRaf = new RandomAccessFile(tmpFile, "rw");
FileChannel fileChannel = tempRaf.getChannel();

//写入该分片数据

long offset = CHUNK_SIZE * param.getChunk();
byte[] fileData = param.getFile().getBytes();
MappedByteBuffer mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, offset, fileData.length);
mappedByteBuffer.put(fileData);
// 释放
FileMD5Util.freedMappedByteBuffer(mappedByteBuffer);
fileChannel.close();

boolean isOk = checkAndSetUploadProgress(param, uploadDirPath);
if (isOk)
boolean flag = renameFile(tmpFile, fileName);
System.out.println("upload complete !!" + flag + " name=" + fileName);



/**
* 检查并修改文件上传进度
*
* @param param
* @param uploadDirPath
* @return
* @throws IOException
*/
private boolean checkAndSetUploadProgress(MultipartFileParam param, String uploadDirPath) throws IOException
String fileName = param.getName();
File confFile = new File(uploadDirPath, fileName + ".conf");
RandomAccessFile accessConfFile = new RandomAccessFile(confFile, "rw");
//把该分段标记为 true 表示完成
System.out.println("set part " + param.getChunk() + " complete");
accessConfFile.setLength(param.getChunks());
accessConfFile.seek(param.getChunk());
accessConfFile.write(Byte.MAX_VALUE);

//completeList 检查是否全部完成,如果数组里是否全部都是(全部分片都成功上传)
byte[] completeList = FileUtils.readFileToByteArray(confFile);
byte isComplete = Byte.MAX_VALUE;
for (int i = 0; i < completeList.length && isComplete == Byte.MAX_VALUE; i++)
//与运算, 如果有部分没有完成则 isComplete 不是 Byte.MAX_VALUE
isComplete = (byte) (isComplete & completeList[i]);
System.out.println("check part " + i + " complete?:" + completeList[i]);


accessConfFile.close();
if (isComplete == Byte.MAX_VALUE)
//stringRedisTemplate.opsForHash().put(Constants.FILE_UPLOAD_STATUS, param.getMd5(), "true");
//stringRedisTemplate.opsForValue().set(Constants.FILE_MD5_KEY + param.getMd5(), uploadDirPath + "/" + fileName);
return true;
else
// if (!stringRedisTemplate.opsForHash().hasKey(Constants.FILE_UPLOAD_STATUS, param.getMd5()))
// stringRedisTemplate.opsForHash().put(Constants.FILE_UPLOAD_STATUS, param.getMd5(), "false");
//
// if (stringRedisTemplate.hasKey(Constants.FILE_MD5_KEY + param.getMd5()))
// stringRedisTemplate.opsForValue().set(Constants.FILE_MD5_KEY + param.getMd5(), uploadDirPath + "/" + fileName + ".conf");
//
return false;



/**
* 文件重命名
*
* @param toBeRenamed 将要修改名字的文件
* @param toFileNewName 新的名字
* @return
*/
public boolean renameFile(File toBeRenamed, String toFileNewName)
//检查要重命名的文件是否存在,是否是文件
if (!toBeRenamed.exists() || toBeRenamed.isDirectory())
//logger.info("File does not exist: " + toBeRenamed.getName());
return false;

String p = toBeRenamed.getParent();
File newFile = new File(p + File.separatorChar + toFileNewName);
//修改文件名
return toBeRenamed.renameTo(newFile);

以上是关于spring boot 大文件上传实现方式的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot 分片上传断点续传大文件上传秒传,应有尽有,建议收藏!!...

Spring Boot 分片上传断点续传大文件上传秒传,应有尽有,建议收藏!!

如何在 Spring Boot 中将大文件上传到 ftps 服务器?

如何实现 Spring REST 端点上传大文件? [复制]

Spring Boot + Vue 前后端分离,两种文件上传方式总结

Spring Boot + Vue 前后端分离,两种文件上传方式总结