【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.fileList[0];//文件

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.fileList[0].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", fileChunkList[reqNum].chunk);

formData.append("fileChunk", JSON.stringify(fileChunkList[reqNum]));

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));
    }

}
相关推荐
Mr Xu_18 小时前
告别冗长 switch-case:Vue 项目中基于映射表的优雅路由数据匹配方案
前端·javascript·vue.js
qq_2975746718 小时前
【实战教程】SpringBoot 实现多文件批量下载并打包为 ZIP 压缩包
java·spring boot·后端
前端摸鱼匠18 小时前
Vue 3 的toRefs保持响应性:讲解toRefs在解构响应式对象时的作用
前端·javascript·vue.js·前端框架·ecmascript
未来之窗软件服务20 小时前
未来之窗昭和仙君(六十五)Vue与跨地区多部门开发—东方仙盟练气
前端·javascript·vue.js·仙盟创梦ide·东方仙盟·昭和仙君
phltxy21 小时前
Vue 核心特性实战指南:指令、样式绑定、计算属性与侦听器
前端·javascript·vue.js
tb_first1 天前
LangChain4j简单入门
java·spring boot·langchain4j
Byron07071 天前
Vue 中使用 Tiptap 富文本编辑器的完整指南
前端·javascript·vue.js
Byron07071 天前
从 0 到 1 搭建 Vue 前端工程化体系:提效、提质、降本实战落地
前端·javascript·vue.js
zhengfei6111 天前
【AI平台】- 基于大模型的知识库与知识图谱智能体开发平台
vue.js·语言模型·langchain·知识图谱·多分类
徐小夕@趣谈前端1 天前
Web文档的“Office时刻“:jitword共建版2.0发布!让浏览器变成本地生产力
前端·数据结构·vue.js·算法·开源·编辑器·es6