【vue + springboot】切片+断点上传 + 秒传

需要了解透彻请参考:如何实现大文件上传、断点续传、切片上传_断点上传-CSDN博客

说明

切片:根据指定的大小对文件进行切块上传。

断点上传:每次上传完成一个切片后端保存信息,前端每次上传都判断所上传的文件是否存在,存在后端则返回信息,前端再根据信息进行调整继续上传。

秒传:如果文件已经在后端中存在,直接返回上传成功。可以节磁盘,提高用户体验,这里我用的是文件名来判断,不推荐,一般使用hash或者算法来为文件取一个唯一标识。

前端

axiosFun.sj

没有安装axios就在命令行安装:npm install axios

import axios from 'axios';

const req = (method, url, params) => {

return axios({

method: method,

url: url,

data: params,

headers: {

'Content-Type': 'multipart/form-data',

},

traditional: true,

}).then(res => res.data);

};

const jsonReq = (method, url) => {

return axios({

method: method,

url: url,

traditional: true,

}).then(res => res.data);

};

export { req, jsonReq };

request.js

import { req, jsonReq } from "./axiosFun";

export const upload = (params) => req('post', '/test/upload', params)

export const getUploadFile = (params) => jsonReq('get', '/test/getUploadFile/' + params)

type.js

class FileChunk {

constructor(chunk, fileName, start, end, total) {

// 切片对象

this.chunk = chunk;

// 文件名称

this.fileName = fileName;

// 切片起始位置

this.start = start;

// 切片结束位置

this.end = end;

// 文件总大小

this.total = total;

}

}

export default FileChunk;

HelloWorld.vue

<template>

<el-upload class="upload-demo" ref="upload" action="https://jsonplaceholder.typicode.com/posts/" :file-list="fileList"

:on-change="selectFile" :auto-upload="false" :limit="max_fileNum" :on-exceed="onExceed">

<el-button slot="trigger" size="small" type="primary">选取文件</el-button>

<el-button style="margin-left: 10px;" size="small" type="success" @click="submitUpload">上传到服务器</el-button>

</el-upload>

</template>

<script>

import FileChunk from './type.js';

import { upload, getUploadFile } from './request.js';

export default {

name: 'FileChunk',

data() {

return {

fileList: \[\],

max_fileNum: 1,

fileChunkSize: 10240

};

},

methods: {

createFileChunkList(start, end_) {

let fileChunkList = \[\];//文件块list

let file = this.fileList0;//文件

let cur = null;//文件切割当前位置

let end = null;//文件切割结尾位置

//断点续传

if (start != null && end_ != null) {

let temp = start + this.fileChunkSize;

if (temp < file.size) {

cur = temp;

}

end = cur + this.fileChunkSize

if (end >= file.size) {

end = file.size

}

//从头开始切片上传

} else {

cur = 0;

end = this.fileChunkSize

}

//当前文件小于切块文件,直接返回

if (file.size < this.fileChunkSize) {

return fileChunkList.push(new FileChunk(file, file.name, cur, file.size));

} else {

//断点续传已切到最后一块

if (end == file.size) {

let blob = new Blob(file).slice(cur, end);

const fileChunk = new FileChunk(blob, file.name, cur, end, file.size);

fileChunkList.push(fileChunk);

}

//切片

while (end < file.size) {

let blob = new Blob(file).slice(cur, end);

const fileChunk = new FileChunk(blob, file.name, cur, end, file.size);

fileChunkList.push(fileChunk);

let temp = cur + this.fileChunkSize;

if (temp < file.size) {

cur = temp;

}

end = cur + this.fileChunkSize

if (end >= file.size) {

end = file.size

}

}

}

//返回切片list

return fileChunkList;

},

//上传

submitUpload() {

let fileChunkList = null;

//判断是否是断点上传的文件

getUploadFile(this.fileList0.name).then(res => {

if (res.data == null) {//文件不存在,直接传

fileChunkList = this.createFileChunkList(null, null);

} else if (res.data.end == res.data.total) {//该文件已经存在了 -> 秒传

this.$message.success("上传成功")

return;

} else {//断点,文件续传

fileChunkList = this.createFileChunkList(res.data.start, res.data.end);

}

let reqNum = 0;//请求次数

let errCount = 3;//只允许错误三次

while (reqNum < fileChunkList.length && errCount > 0) {

const formData = new FormData();

formData.append("file", fileChunkListreqNum.chunk);

formData.append("fileChunk", JSON.stringify(fileChunkListreqNum));

upload(

formData

).then(res => {

if (res) {

reqNum += 1;

} else {

errCount -= 1;

}

this.$message.success(res.data.msg)

});

}

})

},

selectFile(file) {

this.fileList.push(file.raw)

},

onExceed() {

this.$message.error("一次只能上传一个文件");

}

}

}

</script>./type.js

后端

操作数据库所需要的实体类、接口、mapper参考type.js创建一个表格,代码生成即可

返回值直接拷贝:CSDN

复制代码
package com.example.demo.controller;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.demo.domain.FileChunk;
import com.example.demo.res.R;
import com.example.demo.service.FilechunkService;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.RandomAccessFile;

@RestController
@RequestMapping("/test")
@AllArgsConstructor
public class FileUploadController {

    private static final String UPLOAD_DIR = "D:\\luo\\code\\demo3\\src\\main\\resources\\files\\";
    private final FilechunkService filechunkService;

    @PostMapping("/upload")
    public R uploadFileChunk(@RequestParam("file") MultipartFile file, @RequestParam("fileChunk") String fileChunk) {
        FileChunk f = JSONUtil.toBean(fileChunk, FileChunk.class);
        String fullPath = UPLOAD_DIR + f.getFileName();
        // 模块写入对应的位置,rw表示读写模式
        try (RandomAccessFile rf = new RandomAccessFile(fullPath,
                "rw")) {
            rf.seek(f.getStart());
            rf.write(file.getBytes());
        } catch (Exception e) {
            return R.fail(e.getMessage());
        }
        //存储信息,一般存放在redis中,并设置在一定的时间内删除
        f.setId(1L);
        filechunkService.updateById(f);
        return R.success("上传成功");
    }

    @GetMapping("/getUploadFile/{name}")
    public R followUpload(@PathVariable("name") String name) {
        //查询数据库的信息,继续上传
        QueryWrapper<FileChunk> wrapper = new QueryWrapper<>();
        wrapper.eq("file_name", name);
        return R.data(filechunkService.getOne(wrapper));
    }

}
相关推荐
ZhengEnCi5 小时前
Q02-Vue-React-index.html完全指南
vue.js·react.js·html
晴虹6 小时前
vue3-scroll-more:横向滚动条-元素或页签过多滚动显示处理的组件
前端·vue.js
Forever7_6 小时前
尤雨溪转发:Vue-tui 0.1 发布!Vue 终于杀进终端!
vue.js
dkbnull6 小时前
Vue 虚拟 DOM Diff 算法与 key 机制原理
vue.js
前端切图崽_小郭21 小时前
虚拟滚动:静态 vs 动态的核心差异与实现?
vue.js
白鲸开源1 天前
Apache SeaTunnel Zeta Engine 的 Basic Auth 是怎么工作的?
java·vue.js·github
卤蛋fg61 天前
vue 甘特图 vxe-gantt 的使用(四):周视图的渲染
vue.js
卤蛋fg61 天前
vue 甘特图 vxe-gantt 的使用(三):月视图的渲染
vue.js
卤蛋fg61 天前
vue 甘特图 vxe-gantt 的使用(一):年视图的渲染
vue.js
前端开发爱好者1 天前
支持 110 种文件预览!兼容 Vue、React、Svelte!
前端·javascript·vue.js