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);
}


实体Model
public class MultipartFileParam {
// uid
private String uid;

//总分片数量
private int chunks;
//当前为第几块分片
private int chunk;

//文件名
private String name;
//分片对象
private MultipartFile file;
// MD5
private String md5;

public String getUid() {
return uid;
}

public void setUid(String uid) {
this.uid = uid;
}

public int getChunks() {
return chunks;
}

public void setChunks(int chunks) {
this.chunks = chunks;
}

public int getChunk() {
return chunk;
}

public void setChunk(int chunk) {
this.chunk = chunk;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public MultipartFile getFile() {
return file;
}

public void setFile(MultipartFile file) {
this.file = file;
}

public String getMd5() {
return md5;
}

public void setMd5(String md5) {
this.md5 = md5;
}

}
posted @ 2019-09-12 17:41  Ryan_Gao  阅读(1888)  评论(0编辑  收藏  举报