
背景
在上传大型文件时,一般采用的都是分片、断点续传等技术,这样不会导致因文件过大而造成系统超时或者过压等情况。
接下来我们进入教学
如果有帮助到您,麻烦请点击个收藏、赞,谢谢~

整个前端网页的效果图:

开发工具:idea ,开发语言:java ,框架:springboot
创建工具类:FileUtils
-
- import com.caozhen.common.constant.HttpStatusConstant;
- import org.springframework.stereotype.Component;
- import org.springframework.web.multipart.MultipartFile;
-
- import java.io.*;
-
-
- /**
- * @author caozhen
- * @ClassName FileUtils
- * @description: 文件上传
- * @date 2023年10月07日
- * @version: 1.0
- */
- @Component
- public class FileUtils {
- //文件路径,可以统一配置
- private static final String UPLOAD_DIR = "d:\\uploads";
-
- /***
- * 断点续传(上传文件)
- * @param file
- * @return
- */
- public ResultAjax resumeFile(MultipartFile file,
- int chunkNumber,
- int totalChunks,
- String identifier) {
- try {
- File uploadDir = new File(UPLOAD_DIR);
- if (!uploadDir.exists()) {
- uploadDir.mkdirs();
- }
-
- String fileName = identifier + "-chunk-" + chunkNumber;
- File chunkFile = new File(uploadDir, fileName);
-
- try (InputStream inputStream = file.getInputStream();
- FileOutputStream outputStream = new FileOutputStream(chunkFile)) {
- byte[] buffer = new byte[1024];
- int bytesRead;
- while ((bytesRead = inputStream.read(buffer)) != -1) {
- outputStream.write(buffer, 0, bytesRead);
- }
- }
-
- if (chunkNumber == totalChunks - 1) {
- File finalFile = new File(UPLOAD_DIR + File.separator + identifier);
- for (int i = 0; i < totalChunks; i++) {
- File part = new File(uploadDir, identifier + "-chunk-" + i);
- try (FileInputStream partStream = new FileInputStream(part);
- FileOutputStream finalStream = new FileOutputStream(finalFile, true)) {
- byte[] buffer = new byte[1024];
- int bytesRead;
- while ((bytesRead = partStream.read(buffer)) != -1) {
- finalStream.write(buffer, 0, bytesRead);
- }
- }
- part.delete();
- }
- uploadDir.delete();
- }
-
- return ResultAjax.ok("Chunk " + chunkNumber + " uploaded");
- } catch (IOException e) {
- e.printStackTrace();
- return ResultAjax.error(HttpStatusConstant.HTTP_CODE_500, "上传失败:" + e.getMessage());
- }
- }
- }
- @RestController
- @Slf4j
- @Api(tags = "系统服务")
- @RequestMapping("/sys/test/")
- public class SystemController {
-
- @Autowired
- private FileUtils fileUtils;
-
-
- @ApiOperation("测试文件断点续传-上传")
- @RequestMapping(value = "/upload", method = RequestMethod.POST)
- public ResultAjax fileUploads(@RequestParam("file") MultipartFile file,
- @RequestParam("chunkNumber") int chunkNumber,
- @RequestParam("totalChunks") int totalChunks,
- @RequestParam("identifier") String identifier) {
- return fileUtils.resumeFile(file,chunkNumber,totalChunks,identifier);
- }
-
- }
-
- import java.util.HashMap;
- import java.util.LinkedHashMap;
- import java.util.Map;
-
- /**
- * @author caozhen
- * @ClassName ResultAjax
- * @description: 全局封装统一返回实体类
- * @date 2023年07月26日
- * @version: 1.0
- */
- public class ResultAjax extends LinkedHashMap
{ - private static final long serialVersionUID = 1L;
-
- public ResultAjax() {
- put("success", true);
- put("code", HttpStatusConstant.HTTP_CODE_200);
- put("msg", "操作成功!");
- put("data", null);
- }
-
- public ResultAjax(Integer code) {
- put("success", true);
- put("code", code);
- put("msg", "操作成功!");
- put("data", null);
- }
-
- public ResultAjax(Integer code, String msg) {
- put("success", true);
- put("code", code);
- put("msg", msg);
- put("data", null);
- }
-
- public static ResultAjax error() {
- return error(HttpStatusConstant.HTTP_CODE_500, "未知异常,请联系管理员");
- }
-
- public static ResultAjax errorDebug(String message) {
- return error(HttpStatusConstant.HTTP_CODE_500, "未知异常 " + message + ",请联系管理员");
- }
-
- public static ResultAjax error(String msg) {
- return error(HttpStatusConstant.HTTP_CODE_500, msg);
- }
-
-
- public static ResultAjax error(int code, String msg) {
- ResultAjax r = new ResultAjax();
- r.put("success", false);
- r.put("code", code);
- r.put("msg", msg);
- return r;
- }
-
- public ResultAjax errorInfo(String msg) {
- this.put("errorMsg", msg);
- return this;
- }
-
- public static ResultAjax ok(Object data) {
- ResultAjax r = new ResultAjax();
- r.put("success", true);
- r.put("code", HttpStatusConstant.HTTP_CODE_200);
- r.put("msg", "操作成功!");
- r.put("data", data);
- return r;
- }
-
- public static ResultAjax ok(Map
map) { - ResultAjax r = new ResultAjax();
- r.putAll(map);
- r.put("data", null);
- return r;
- }
-
- public static ResultAjax ok(String msg, Integer code) {
- ResultAjax r = new ResultAjax();
- r.put("success", true);
- r.put("code", code);
- r.put("msg", msg);
- r.put("data", null);
- return r;
- }
-
- public static ResultAjax ok() {
- return new ResultAjax().put("msg", "操作成功!").put("data", null);
- }
-
- public static ResultAjax ok(Integer size) {
- return new ResultAjax().put("data", null);
- }
-
- @Override
- public ResultAjax put(String key, Object value) {
- super.put(key, value);
- return this;
- }
-
- /**
- * 添加返回结果数据
- *
- * @param key
- * @param value
- * @return
- */
- public ResultAjax putData(String key, Object value) {
- Map
map = (HashMap) this.get("data"); - map.put(key, value);
- return this;
- }
- }
- public class HttpStatusConstant {
- //目前常用的,200,500
- public final static Integer HTTP_CODE_200 = 200;
- public final static Integer HTTP_CODE_500 = 500;
- //拦截
- public final static Integer HTTP_CODE_403 = 403;
- public final static Integer HTTP_CODE_401 = 401;
- }
- html>
- <html>
- <head>
- <title>文件分片上传title>
- head>
- <body>
- <input type="file" id="fileInput">
- <button id="startUpload">开始上传button>
- <button id="pauseResumeUpload">暂停上传button>
- <progress id="progress" max="100" value="0">progress>
- <span id="progressText">0%span>
-
- <script>
- const fileInput = document.getElementById('fileInput');
- const startUpload = document.getElementById('startUpload');
- const pauseResumeUpload = document.getElementById('pauseResumeUpload');
- const progress = document.getElementById('progress');
- const progressText = document.getElementById('progressText');
- let file;
- let uploading = false;
- let currentChunk = 0;
- let uploadPaused = false;
- let xhr;
-
- fileInput.addEventListener('change', (event) => {
- file = event.target.files[0];
- });
-
- async function uploadFile() {
- const chunkSize = 1 * 1024 * 1024; // 1MB
- const totalChunks = Math.ceil(file.size / chunkSize);
-
- for (currentChunk; currentChunk < totalChunks; currentChunk++) {
- if (uploadPaused) {
- break;
- }
-
- const startByte = currentChunk * chunkSize;
- const endByte = Math.min(startByte + chunkSize, file.size);
- const chunk = file.slice(startByte, endByte);
-
- const formData = new FormData();
- formData.append('file', chunk);
- formData.append('chunkNumber', currentChunk);
- formData.append('totalChunks', totalChunks);
- formData.append('identifier', file.name);
-
- const response = await fetch('http://localhost:8000/system/sys/test/upload', {
- method: 'POST',
- body: formData,
- });
-
- if (response.status !== 200) {
- console.error('Error uploading chunk: ', response.statusText);
- break;
- }
-
- const percent = ((currentChunk + 1) / totalChunks) * 100;
- progress.value = percent;
- progressText.textContent = `${Math.round(percent)}%`;
- }
-
- if (currentChunk >= totalChunks) {
- alert('文件上传成功!');
- uploading = false;
- currentChunk = 0;
- progress.value = 100;
- progressText.textContent = '100%';
- }
- }
-
- startUpload.addEventListener('click', () => {
- if (file && !uploading) {
- uploading = true;
- uploadFile();
- }
- });
-
- pauseResumeUpload.addEventListener('click', () => {
- if (uploading) {
- if (!uploadPaused) {
- uploadPaused = true;
- pauseResumeUpload.textContent = '继续上传';
- } else {
- uploadPaused = false;
- pauseResumeUpload.textContent = '暂停上传';
- uploadFile();
- }
- }
- });
- script>
- body>
- html>

有什么问题可以在底下评论区留言,看到会在本文后追加回复!