Spring boot 实现大文件分片,断点续传

依赖

   <!--thymeleaf配置-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
                <!--       hutool 开发工具包-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.21</version>
        </dependency>

        <!--        json数据格式相关依赖-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.80</version>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

Hmlt

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div>
    <input type="file" id="pick" value="选择文件"/>
    <input type="submit" id="submit" value="上传文件"/>
</div>
<script th:src="@{/js/jquery.min.js}"></script>
<script>

    $(function () {
        let file;
        let elementById = window.document.getElementById("pick");
        elementById.addEventListener('change', function () {
            //传递参数
            file = elementById.files[0]

        })

        let submit = window.document.getElementById("submit");
        submit.addEventListener('click', function () {
            let maxSize = 2 * 1024 * 1024;// 默认分片大小 2M
            let index = 0;// 默认从第0片开始
            let size = file.size;
            let ceil = Math.ceil(size / maxSize);// 计算总分片
            let exname = file.name.substr(file.name.lastIndexOf("."))
            let chunks = [];

            if (ceil > 50) {
                //防止总切片数过多
                ceil = 50
                maxSize = size / ceil;
            }
            while (index < ceil) {
                chunks.push({
                    file: file.slice(index * maxSize, (index + 1) * maxSize),
                    filename: "chunk_" + index + exname,
                    chunk: index
                })
                index++;
            }
            var i = 1;
            chunks.forEach(f => {
                let formdata = new FormData();
                formdata.append("file", f.file);
                formdata.append("filename", f.filename)
                $.ajax({
                    url: "/file/uploadBigFile",  //上传地址
                    headers: {
                        "Authorization": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImlkIjpudWxsLCJleHAiOjE2NTU4Nzc2NjMsImlhdCI6MTY1NTI3Mjg2MywidXNlcm5hbWUiOiJhZG1pbiJ9.qI7tGsvZ4rVcZXni1X20-ouaZOr5veItZdTc63K6ZwI"
                    },
                    type: "post",
                    data: formdata,  // 传入实例化的formData对象,此对象包含了要上传的文件
                    contentType: false, // 在请求服务器的时候,数据有非字符串格式的内容(文件是二进制)
                    processData: false,  // formData对象不需要转换成参数字符串,
                    success: function (data) {
                        if (i === ceil) {
                            console.log("合并文件")
                            $.ajax({
                                url: "/file/mergeBigFile",  //上传地址
                                headers: {
                                    "Authorization": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImlkIjpudWxsLCJleHAiOjE2NTU4Nzc2NjMsImlhdCI6MTY1NTI3Mjg2MywidXNlcm5hbWUiOiJhZG1pbiJ9.qI7tGsvZ4rVcZXni1X20-ouaZOr5veItZdTc63K6ZwI"
                                },
                                type: "get",
                                data: {
                                    "chunks": ceil,
                                    "exname": exname
                                },  // 传入实例化的formData对象,此对象包含了要上传的文件
                                success: function (data) {
                                    console.log(data)
                                }
                            })
                        }
                        i++;

                    }
                })
            })


        })


    })


</script>
</body>
</html>

控制层


	/**
	 * 大文件分片,断点续传
 	 */

	@PostMapping("/uploadBigFile")
	public ResponseData<String> uploadBigFile(@RequestParam("file") MultipartFile file,@RequestParam("filename") String filename) {
		return fileService.uploadBigFile(file,filename);
	}


	/**
	 * 合并文件
	 */

	@GetMapping("/mergeBigFile")
	public ResponseData<String> mergeBigFile(@RequestParam("chunks")Integer chunks,String exname) {
		return fileService.mergeBigFile(chunks,exname);
	}

实现层


	@Override
	public ResponseData<String> uploadBigFile(MultipartFile file, String filename) {

		try {
			String path = upload + "/" + filename;
			File fileUploadPath = new File(path);
			if (!fileUploadPath.exists()) {
				fileUploadPath.createNewFile();
				file.transferTo(fileUploadPath);
			}

			return ResponseData.success("上传成功", "");
		} catch (IOException e) {
			e.printStackTrace();
		}

		return ResponseData.failure("上传文件失败");
	}
	/**
	 * 文件合并
	 */
	@Override
	public ResponseData<String> mergeBigFile(Integer chunks,String exname) {

			RandomAccessFile raf = null;
			try {
				//申明随机读取文件RandomAccessFile
				File file = new File(upload+"/"+IdUtil.createId()+exname);
				if (!file.exists()) {
					file.createNewFile();
				}
				raf = new RandomAccessFile(file, "rw");
				//开始合并文件,对应切片的二进制文件
				for (int i = 0; i < chunks; i++) {
					File file1 = new File(upload + "/chunk_" + i + exname);
					//读取切片文件
					RandomAccessFile reader = new RandomAccessFile(file1, "r");
					byte[] b = new byte[1024];
					int n = 0;
					//先读后写
					while ((n = reader.read(b)) != -1) {
						raf.write(b, 0, n);
					}
					reader.close();
					if (file1.exists()) {
						file1.delete();
					}
				}

			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				try {
					raf.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}

		return ResponseData.success("文件上传成功");
	}

IdUtil

@Component
public class IdUtil {
   private static Snowflake snowflake=null;
    public static String createId () {
        if(StrUtil.isBlankIfStr (snowflake)){
            snowflake = cn.hutool.core.util.IdUtil.getSnowflake (1, 1);
        }
        return snowflake.nextId ()+"";
    }



}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

缘不易

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值