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

}
相关推荐
QQ_11543203119 分钟前
基于Java+SpringBoot+Mysql在线简单拍卖竞价拍卖竞拍系统功能设计与实现九
java·spring boot·mysql·毕业设计·毕业源码·竞拍系统·竞拍项目
2301_793086871 小时前
springboot+redis+lua实现分布式锁
spring boot·redis·lua
爱编程的小生1 小时前
SpringBoot Task
java·spring boot·后端
CoderJia程序员甲1 小时前
重学SpringBoot3-异步编程完全指南
java·spring boot·后端·异步编程
扬子鳄0081 小时前
Spring Boot自动配置机制
java·数据库·spring boot
岁岁岁平安2 小时前
springboot实战(19)(条件分页查询、PageHelper、MYBATIS动态SQL、mapper映射配置文件、自定义类封装分页查询数据集)
java·spring boot·后端·mybatis·动态sql·pagehelper·条件分页查询
GISer_Jing2 小时前
Vue3常见Composition API详解(适用Vue2学习进入Vue3学习)
前端·javascript·vue.js
计算机学姐2 小时前
基于SSM的宠物领养平台
java·vue.js·spring·maven·intellij-idea·mybatis·宠物
泰山小张只吃荷园2 小时前
期末Python复习-输入输出
java·前端·spring boot·python·spring cloud·docker·容器
工业互联网专业3 小时前
Python毕业设计选题:基于django+vue的期货交易模拟系统的设计与实现
vue.js·python·django·毕业设计·源码·课程设计