目录前言逻辑前端后端RedisTemplate配置结语前言 众所周知,上传大文件是一件很麻烦的事情,假如一条路走到黑,直接一次性把文件上传上去,对于小文件是可以这样做,但是对于大文件
众所周知,上传大文件是一件很麻烦的事情,假如一条路走到黑,直接一次性把文件上传上去,对于小文件是可以这样做,但是对于大文件可能会出现网络问题,请求响应时长等等导致文件上传失败,那么这次来教大家如何用Vue+srpingboot项目上传大文件
需要做大文件上传应该考虑到如下逻辑:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>File Upload</title>
</head>
<body>
<input type="file" id="fileInput">
<button onclick="upload()">Upload</button>
<script>
function upload() {
let file = document.getElementById("fileInput").files[0];
let chunkSize = 5 * 1024 * 1024; // 切片大小为5MB
let totalChunks = Math.ceil(file.size / chunkSize); // 计算切片总数
let index = 0;
while (index < totalChunks) {
let chunk = file.slice(index * chunkSize, (index + 1) * chunkSize);
let fORMData = new FormData();
formData.append("file", chunk);
formData.append("index", index);
formData.append("totalChunks", totalChunks);
// 发送Ajax请求上传切片
$.ajax({
url: "/uploadChunk",
type: "POST",
data: formData,
processData: false,
contentType: false,
success: function () {
if (++index >= totalChunks) {
// 所有切片上传完成,通知服务端合并文件
$.post("/mergeFile", {fileName: file.name}, function () {
alert("Upload complete!");
})
}
}
});
}
}
</script>
</body>
</html>
controller层:
@RestController
public class FileController {
@Value("${file.upload-path}")
private String uploadPath;
@PostMapping("/uploadChunk")
public void uploadChunk(@RequestParam("file") MultipartFile file,
@RequestParam("index") int index,
@RequestParam("totalChunks") int totalChunks) throws IOException {
// 以文件名+切片索引号为文件名保存切片文件
String fileName = file.getOriginalFilename() + "." + index;
Path tempFile = Paths.get(uploadPath, fileName);
Files.write(tempFile, file.getBytes());
// 记录上传状态
String uploadFlag = UUID.randomUUID().toString();
redisTemplate.opsForList().set("upload:" + fileName, index, uploadFlag);
// 如果所有切片已上传,则通知合并文件
if (isAllChunksUploaded(fileName, totalChunks)) {
sendMergeRequest(fileName, totalChunks);
}
}
@PostMapping("/mergeFile")
public void mergeFile(String fileName) throws IOException {
// 所有切片均已成功上传,进行文件合并
List<File> chunkFiles = new ArrayList<>();
for (int i = 0; i < getTotalChunks(fileName); i++) {
String chunkFileName = fileName + "." + i;
Path tempFile = Paths.get(uploadPath, chunkFileName);
chunkFiles.add(tempFile.toFile());
}
Path destFile = Paths.get(uploadPath, fileName);
try (OutputStream out = Files.newOutputStream(destFile);
SequenceInputStream seqIn = new SequenceInputStream(Collections.enumeration(chunkFiles));
BufferedInputStream bufIn = new BufferedInputStream(seqIn)) {
byte[] buffer = new byte[1024];
int len;
while ((len = bufIn.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
}
// 清理临时文件和上传状态记录
for (int i = 0; i < getTotalChunks(fileName); i++) {
String chunkFileName = fileName + "." + i;
Path tempFile = Paths.get(uploadPath, chunkFileName);
Files.deleteIfExists(tempFile);
redisTemplate.delete("upload:" + chunkFileName);
}
}
private int getTotalChunks(String fileName) {
// 根据文件名获取总切片数
return Objects.requireNonNull(Paths.get(uploadPath, fileName).toFile().listFiles()).length;
}
private boolean isAllChunksUploaded(String fileName, int totalChunks) {
// 判断所有切片是否已都上传完成
List<String> uploadFlags = redisTemplate.opsForList().range("upload:" + fileName, 0, -1);
return uploadFlags != null && uploadFlags.size() == totalChunks;
}
private void sendMergeRequest(String fileName, int totalChunks) {
// 发送合并文件请求
new Thread(() -> {
try {
URL url = new URL("http://localhost:8080/mergeFile");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
OutputStream out = conn.getOutputStream();
String query = "fileName=" + fileName;
out.write(query.getBytes());
out.flush();
out.close();
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
while (br.readLine() != null) ;
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
@Autowired
private RedisTemplate<String, Object> redisTemplate;
}
其中,file.upload-path为文件上传的保存路径,可以在application.properties或application.yml中进行配置。同时需要添加RedisTemplate的Bean以便记录上传状态。
如果需要使用RedisTemplate,需要引入下方的包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
同时在yml配置redis的信息
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.database=0
然后在自己的类中这样使用
@Component
public class myClass {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
public void set(String key, Object value) {
redisTemplate.opsForValue().set(key, value);
}
public Object get(String key) {
return redisTemplate.opsForValue().get(key);
}
}
注意事项
到此这篇关于vue+SpringBoot上传大文件的实现示例的文章就介绍到这了,更多相关vue springboot上传大文件内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!
--结束END--
本文标题: vue+springboot上传大文件的实现示例
本文链接: https://www.lsjlt.com/news/211110.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
下载Word文档到电脑,方便收藏和打印~
2024-01-12
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0