NIO斷點續傳

斷點續傳一般在header中需要攜帶Content-Range

後端接收該header,正則校驗如下:

public static final String RANGE_PATTERN = "bytes \\d+-\\d+/\\d+";

上傳的時候,加一張臨時表,文件信息保存到臨時表,並生成一個UUID,上傳完成了再插入到主表,並返回前端一個文件的fileId

代碼如下:

@Override
	@Transactional(rollbackFor = Exception.class)
	public UploadResumeDTO uploadFileResume(MultipartFile file,
	                                        UploadFileResumeRequest uploadFileResumeRequest,
	                                        String range) {
		long start = System.currentTimeMillis();
		Long fileId = null;
		InputStream inputStream = null;
		FileInputStream fileInputStream;
		FileChannel inChannel = null;
		FileOutputStream outStream = null;
		FileChannel outChannel = null;
		long uploadSize = 0;
		long length = 0;
		// 解析Content-Range
		int startByte = 0;
		int endByte = 0;
		try {
			String bytes = range.replaceAll("bytes", "").trim();
			String[] split = bytes.split("-");
			startByte = Integer.parseInt(split[0]);
			String[] split1 = split[1].split("/");
			endByte = Integer.parseInt(split1[0]);
		} catch (Exception e) {
			log.error("header=====>Content-Range轉換失敗:{}", range);
		}

		// 文件上傳
		FileTemp fileTemp = new FileTemp();
		BeanUtils.copyProperties(uploadFileResumeRequest, fileTemp);
		File destFile = new File(config.getRootPath() + file.getOriginalFilename());
		try {
			if (!destFile.exists()) {
				destFile.createNewFile();
			}
			length = destFile.length();
			// 避免重複上傳文件
			if (uploadSize + length >= uploadFileResumeRequest.getFileSize()) {
				return UploadResumeDTO.builder()
						.uuid(uploadFileResumeRequest.getUuid())
						.fileSize(uploadSize + length)
						.build();
			}
			inputStream = file.getInputStream();
			fileInputStream = (FileInputStream) inputStream;
			inChannel = fileInputStream.getChannel();
			outStream = new FileOutputStream(destFile, true);
			outChannel = outStream.getChannel();
			// 第二個參數爲傳多少字節
			uploadSize = inChannel.transferTo(startByte, endByte - startByte, outChannel);

			log.debug("總上傳:{}", uploadSize);
			log.debug("文件目前大小:{}", uploadSize + length);
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (inputStream != null) {
					inputStream.close();
				}
				if (outStream != null) {
					outStream.close();
				}
				if (inChannel != null) {
					inChannel.close();
				}
				if (outChannel != null) {
					outChannel.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		List<FileTemp> tempList = getTempFile(uploadFileResumeRequest.getUuid());
		// 首次上傳
		if (CollectionUtils.isEmpty(tempList)) {
			log.info("不存在臨時文件:{}", uploadFileResumeRequest.getUuid());
			// 上傳完成
			if (uploadFileResumeRequest.getFileSize() == uploadSize + length) {
				// 首次就上傳完,直接插入到主表
				DeviceFileInfoVO deviceFileInfoVO = new DeviceFileInfoVO();
				BeanUtils.copyProperties(uploadFileResumeRequest, deviceFileInfoVO);
				deviceFileInfoVO.setSourceType(uploadFileResumeRequest.getSourceType().getCode());
				deviceFileInfoVO.setFileName(file.getOriginalFilename());
				deviceFileInfoVO.setFilePath(config.getRootPath());
				devMapper.insert(deviceFileInfoVO);
				fileId = deviceFileInfoVO.getFileId();
			} else {
				// 沒有上傳完成,則插入臨時表
				fileTemp.setFilePath(config.getRootPath());
				fileTemp.setFileName(file.getOriginalFilename());
				fileTemp.setFileSize(uploadSize + length);
				fileTempMapper.insert(fileTemp);
			}
		}
		// 非首次上傳
		if (CollectionUtils.isNotEmpty(tempList)) {
			// 非首次,臨時表已經存在記錄
			if (uploadFileResumeRequest.getFileSize() == uploadSize + length) {
				// 上傳完,直接插入到主表
				DeviceFileInfoVO deviceFileInfoVO = new DeviceFileInfoVO();
				BeanUtils.copyProperties(uploadFileResumeRequest, deviceFileInfoVO);
				deviceFileInfoVO.setSourceType(uploadFileResumeRequest.getSourceType().getCode());
				deviceFileInfoVO.setFileName(file.getOriginalFilename());
				deviceFileInfoVO.setFilePath(config.getRootPath());
				devMapper.insert(deviceFileInfoVO);
				fileId = deviceFileInfoVO.getFileId();
				fileTempMapper.deleteById(fileTemp);
			} else {
				fileTemp = tempList.get(0);
				fileTemp.setFileSize(uploadSize + length);
				fileTempMapper.updateById(fileTemp);
			}
		}
		log.info("耗時:{} ms", System.currentTimeMillis() - start);
		return UploadResumeDTO.builder()
				.uuid(uploadFileResumeRequest.getUuid())
				.fileSize(uploadSize + length)
				.fileId(fileId == null ? null : fileId.toString())
				.build();
	}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章