方案
前端对文件进行分片,对每个分片按序上传,上传前先发送一个请求,检查上传的文件是否已经存在,如果存在,目前大小是多少,前端根据已经存在的大小,继续上传文件即可
前端js代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>断点续传示例</title>
</head>
<body>
<input type="file" id="fileInput"/>
<button onclick="startUpload()">开始上传</button>
<script>
async function startUpload() {
const fileInput = document.getElementById('fileInput');
const file = fileInput.files[0];
if (!file) {
alert("请选择文件");
return;
}
const filename = file.name;
let start = await checkFile(filename);
uploadFile(file, start);
}
// 查看文件是否存在,如果存在返回当前文件大小
async function checkFile(filename) {
const response = await fetch(`http://localhost:8585/check?filename=${filename}`);
const start = await response.json();
return start;
}
// 上传文件
async function uploadFile(file, start) {
const chunkSize = 1024 * 1024; // 每个分片1MB
const total = Math.ceil((file.size - start) / chunkSize);
for (let i = 0; i < total; i++) {
const chunkStart = start + i * chunkSize;
const chunkEnd = Math.min(chunkStart + chunkSize, file.size);
const chunk = file.slice(chunkStart, chunkEnd);
const formData = new FormData();
formData.append('file', chunk);
formData.append('start', chunkStart);
formData.append('fileName', file.name);
const response = await fetch('http://localhost:8585/upload', {
method: 'POST',
body: formData
});
const result = await response.text();
if (response.ok) {
console.log(`分片 ${i + 1}/${total} 上传成功`);
} else {
console.error(`分片 ${i + 1}/${total} 上传失败: ${result}`);
break;
}
}
}
</script>
</body>
</html>
后端java
@CrossOrigin(origins = "*")
@RestController
public class Demo {
private static final String UPLOAD_DIR = "E:\\Code\\springboot\\src\\main\\java\\cn\\ccb\\file";
/**
* 上传文件到指定位置
*
* @param file 上传的文件
* @param start 文件开始上传的位置
* @return ResponseEntity<String> 上传结果
*/
@PostMapping("/upload")
public ResponseEntity<String> resumeUpload(@RequestParam("file") MultipartFile file,
@RequestParam("start") long start,
@RequestParam("fileName") String fileName) {
try {
File directory = new File(UPLOAD_DIR);
if (!directory.exists()) {
directory.mkdirs();
}
File targetFile = new File(UPLOAD_DIR + fileName);
RandomAccessFile randomAccessFile = new RandomAccessFile(targetFile, "rw");
FileChannel channel = randomAccessFile.getChannel();
channel.position(start);
channel.transferFrom(file.getResource().readableChannel(), start, file.getSize());
channel.close();
randomAccessFile.close();
return ResponseEntity.ok("上传成功");
} catch (Exception e) {
System.out.println("上传失败: "+e.getMessage());
return ResponseEntity.status(500).body("上传失败");
}
}
/**
* 查看文件是否存在,如果存在返回文件大小
*/
@GetMapping("/check")
public ResponseEntity<Long> checkFile(@RequestParam("filename") String filename) {
File file = new File(UPLOAD_DIR + filename);
if (file.exists()) {
return ResponseEntity.ok(file.length());
} else {
return ResponseEntity.ok(0L);
}
}
}