亲测好用,这里就直接上代码了,代码有详细的解释。

0. 建表语句

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;-- ----------------------------
-- Table structure for file_info
-- ----------------------------
DROP TABLE IF EXISTS `file_info`;
CREATE TABLE `file_info`  (`id` char(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'id',`file_path` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '相对路径',`file_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '文件名',`suffix` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '后缀',`file_size` int(11) NULL DEFAULT NULL COMMENT '大小|字节B',`file_use` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用途|枚举[FileUseEnum]:COURSE(\'C\', \'讲师\'), TEACHER(\'T\', \'课程\')',`created_at` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',`updated_at` datetime(0) NULL DEFAULT NULL COMMENT '修改时间',`shard_index` int(11) NULL DEFAULT NULL COMMENT '已上传分片',`shard_total` int(11) NULL DEFAULT NULL COMMENT '分片总数',`shard_size` int(11) NULL DEFAULT NULL COMMENT '分片大小|B',`file_key` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '文件标识',`vod` char(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'vod|阿里云vod',PRIMARY KEY (`id`) USING BTREE,UNIQUE INDEX `path_unique`(`file_path`) USING BTREE,UNIQUE INDEX `key_unique`(`file_key`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '文件' ROW_FORMAT = Dynamic;SET FOREIGN_KEY_CHECKS = 1;

1. vue代码

<template><div><el-card class="box-card"><el-row><el-col :span="6"><el-uploadclass="upload-vhr"action="no"list-type="text"ref="uploadFile"accept="no":auto-upload="false":on-exceed="handleExceed":http-request="customUpload":on-change="handleChange":on-remove="handleRemove":limit="1":file-list="fileList"><el-input placeholder="请输入内容" v-model="fileName"><template slot="append"><el-button type="primary" icon="el-icon-folder-opened">选择文件</el-button></template></el-input><!--<div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div>--></el-upload></el-col><el-col :span="6"><el-button type="primary" icon="el-icon-folder-opened" @click="submitUpload">提交</el-button></el-col></el-row></el-card></div>
</template><script>
import {hex_md5} from "@/utils/md5.js";export default {name: "EmpAdv",/*props: {afterUpload: {type: Function,default: null},},*/data() {return {file: "",fileList: [],fileName: "",url: {upload: "/file/upload",check: "/file/check"}};},methods: {submitUpload() {if (this.fileList == '') {this.$message.warning("请选择需要上传的文件!")} else {// 调用文件上传的钩子函数this.$refs.uploadFile.submit();this.fileList = []}},//自定义上传文件钩子,发送上传文件请求customUpload() {let file = this.file;let key = hex_md5(file.name + file.size + file.type);let suffix = file.name.substr(file.name.lastIndexOf(".") + 1).toLowerCase();// 文件分片let shardSize = 20 * 1024 * 1024; // 以20M为一个分片let shardIndex = 1; //分片索引, 1表示第一个分片let size = file.size;let shardTotal = Math.ceil(size / shardSize);let param = {"shardIndex": shardIndex,"shardSize": shardSize,"shardTotal": shardTotal,"fileUse": "C","fileName": file.name,"suffix": suffix,"fileSize": size,"fileKey": key}this.check(param);},/*** 检查文件状态,是否已上传过?传到第几个分片?*/check(param) {this.getRequest(this.url.check, {"fileKey": param.fileKey}).then(resp => {if (resp && resp.status) {let obj = resp.data;if (!obj) {param.shardIndex = 1;console.log("没有找到文件记录,从分片1开始上传");this.upload(param);} else if (obj.shardIndex === obj.shardTotal) {// 已上传分片 = 分片总数,说明已全部上传完,不需要再上传this.$message.success("文件极速秒传成功!");} else {param.shardIndex = obj.shardIndex + 1;console.log("找到文件记录,从分片" + param.shardIndex + "开始上传");this.upload(param);}} else {this.$message.error("文件上传失败");}})},upload(param) {let shardIndex = param.shardIndex;let shardTotal = param.shardTotal;let shardSize = param.shardSize;let fileShard = this.getFileShard(shardIndex, shardSize);// 将图片转为 base64 进行传输let fileReader = new FileReader();fileReader.onload = (e => {let base64 = e.target.result;param.shard = base64;this.postRequest(this.url.upload, param).then(resp => {if (resp && resp.status) {this.fileName = "";this.fileList = []} else {this.$message.error(resp.msg)}let respData = resp.dataif (shardIndex < shardTotal) {// 上传下一个分片param.shardIndex = param.shardIndex + 1;this.upload(param);} else {this.$message.success("上传成功")}})})fileReader.readAsDataURL(fileShard);},getFileShard(shardIndex, shardSize) {let file = this.file;// 当前分片起始位置let start = (shardIndex - 1) * shardSize;//当前分片结束位置let end = Math.min(file.size, start + shardSize);let fileShard = file.slice(start, end);return fileShard;},handleRemove(file, fileList) {// 删除上传文件this.fileName = "";this.fileList = []},handleChange(file, fileList) {// 文件状态钩子,选择文件时触发this.fileList = fileList;this.fileName = file.name;this.file = this.fileList[0].raw;},handleExceed(files, fileList) {this.$message.warning(`当前限制选择 1 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + fileList.length} 个文件`);}}
}
</script><style scoped></style>

2. md5加密工具类

var chrsz = 8;  /* bits per input character. 8 - ASCII; 16 - Unicode      *//** These are the functions you'll usually want to call* They take string arguments and return either hex or base-64 encoded strings*/
export function hex_md5(s) {return binl2hex(core_md5(str2binl(s), s.length * chrsz));
}function str2binl(str) {var bin = Array();var mask = (1 << chrsz) - 1;for (var i = 0; i < str.length * chrsz; i += chrsz)bin[i >> 5] |= (str.charCodeAt(i / chrsz) & mask) << (i % 32);return bin;
}/** Calculate the MD5 of an array of little-endian words, and a bit length*/
function core_md5(x, len) {/* append padding */x[len >> 5] |= 0x80 << ((len) % 32);x[(((len + 64) >>> 9) << 4) + 14] = len;var a = 1732584193;var b = -271733879;var c = -1732584194;var d = 271733878;for (var i = 0; i < x.length; i += 16) {var olda = a;var oldb = b;var oldc = c;var oldd = d;a = md5_ff(a, b, c, d, x[i + 0], 7, -680876936);d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586);c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819);b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330);a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897);d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426);c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341);b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983);a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416);d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417);c = md5_ff(c, d, a, b, x[i + 10], 17, -42063);b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162);a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682);d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101);c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290);b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329);a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510);d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632);c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713);b = md5_gg(b, c, d, a, x[i + 0], 20, -373897302);a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691);d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083);c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335);b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848);a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438);d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690);c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961);b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501);a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467);d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784);c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473);b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734);a = md5_hh(a, b, c, d, x[i + 5], 4, -378558);d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463);c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562);b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556);a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060);d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353);c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632);b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640);a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174);d = md5_hh(d, a, b, c, x[i + 0], 11, -358537222);c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979);b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189);a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487);d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835);c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520);b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651);a = md5_ii(a, b, c, d, x[i + 0], 6, -198630844);d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415);c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905);b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055);a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571);d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606);c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523);b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799);a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359);d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744);c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380);b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649);a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070);d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379);c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259);b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551);a = safe_add(a, olda);b = safe_add(b, oldb);c = safe_add(c, oldc);d = safe_add(d, oldd);}return Array(a, b, c, d);}/** Convert an array of little-endian words to a hex string.*/
function binl2hex(binarray) {var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";var str = "";for (var i = 0; i < binarray.length * 4; i++) {str += hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8 + 4)) & 0xF) +hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8)) & 0xF);}return str;
}

3. 配置文件

我这里配置了一些基础配置:druid、log4j2、mybatis等。

集成log4j2可以看这里: https://blog.csdn.net/weixin_42201180/article/details/111028263
要是不想配置log4j2可以注释掉:

server:port: 8090servlet:context-path: /vhraddress:spring:profiles:active: devapplication:name: vhrservlet:multipart:maxFileSize: 100MBmaxRequestSize: 100MB# 数据源配置datasource:driver-class-name: com.mysql.jdbc.Drivertype: com.alibaba.druid.pool.DruidDataSourceurl: jdbc:mysql://127.0.0.1:3306/vhr?useUnicode=true&characterEncoding=utf-8&useSSL=false&autoReconnect=true&serverTimezone=UTCdata-username: rootdata-password: rootdruid:# 初始化时建立物理连接的个数,initial-size: 5# 最小连接池数量min-idle: 5# 最大连接池数量max-active: 20# 获取连接时最大等待时间,单位毫秒max-wait: 60000# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位毫秒time-between-eviction-runs-millis: 60000# 配置一个连接在池中最小生存的时间,单位毫秒min-evictable-idle-time-millis: 300000validation-query: SELECT 1 FROM DUAL# 申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。test-while-idle: true# 申请连接时会执行validationQuery检测连接是否有效,开启会降低性能,默认为truetest-on-borrow: false# 归还连接时会执行validationQuery检测连接是否有效,开启会降低性能,默认为truetest-on-return: false# 是否缓存preparedStatement,也就是PSCache,PSCache对支持游标的数据库性能提升巨大,比如说oracle,在mysql下建议关闭。mysql5.5+建议开启pool-prepared-statements: true# 当值大于0时poolPreparedStatements会自动修改为truemax-pool-prepared-statement-per-connection-size: 20# 通过别名的方式配置扩展插件: stat:监控统计,wall:防sql注入,log4j:日志filters: stat,wall,slf4j# 合并多个DruidDataSource的监控数据use-global-data-source-stat: true# 通过connectProperties属性来打开mergeSql功能;慢SQL记录connect-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000mybatis:# 注意:一定要对应mapper映射xml文件的所在路径mapper-locations: classpath:/mapper/*Mapper.xml# 注意:对应实体类的路径type-aliases-package: com.javaboy.vhr.entityconfiguration:map-underscore-to-camel-case: true# 日志配置
logging:level:com.javaboy.vhr.mapper: DEBUGconfig: classpath:log4j2.yml # 指定log4j配置文件的位置localUploadFilePath: D:/vhr/localUploadFilePath/

4. 实体类

package com.javaboy.vhr.entity;import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;import java.io.Serializable;
import java.util.Date;/*** @author: gaoyang* @date: 2021-03-23 10:46:31* @description: 文件(FileInfo)实体类*/
@Getter
@Setter
@ApiModel("文件实体类")
public class FileInfo implements Serializable {private static final long serialVersionUID = 694649584012557460L;@ApiModelProperty("id")private String id;@ApiModelProperty("相对路径")private String filePath;@ApiModelProperty("文件名")private String fileName;@ApiModelProperty("后缀")private String suffix;@ApiModelProperty("大小|字节B")private Integer fileSize;@ApiModelProperty("用途|枚举[FileUseEnum]:COURSE('C', '讲师'), TEACHER('T', '课程')")private String fileUse;@ApiModelProperty("创建时间")private Date createdAt;@ApiModelProperty("修改时间")private Date updatedAt;@ApiModelProperty("已上传分片")private Integer shardIndex;@ApiModelProperty("分片大小|B")private Integer shardSize;@ApiModelProperty("分片总数")private Integer shardTotal;@ApiModelProperty("文件标识")private String fileKey;@ApiModelProperty("base64")private String shard;@ApiModelProperty("vod|阿里云vod")private String vod;}

5. 后端接口-controller

package com.javaboy.vhr.controller;import com.github.pagehelper.PageInfo;
import com.javaboy.vhr.entity.FileInfo;
import com.javaboy.vhr.enums.FileUseEnum;
import com.javaboy.vhr.service.FileInfoService;
import com.javaboy.vhr.utils.Base64ToMultipartFile;
import com.javaboy.vhr.utils.result.ResultDTO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;import javax.annotation.Resource;
import java.io.*;/*** @author: gaoyang* @date: 2021-03-23 10:46:33* @description: 文件(FileInfo)表控制层*/
@Slf4j
@Api(tags = "文件API")
@RestController
@RequestMapping("/file")
public class FileInfoController {@Value("${localUploadFilePath}")private String FILE_PATH;@Resourceprivate FileInfoService fileInfoService;@ApiOperation(value = "文件上传")@PostMapping("/upload")public ResultDTO<FileInfo> upload(@RequestBody FileInfo fileInfo) throws InterruptedException {String use = fileInfo.getFileUse();String key = fileInfo.getFileKey();String suffix = fileInfo.getSuffix();String shardBase64 = fileInfo.getShard();MultipartFile shard = Base64ToMultipartFile.base64ToMultipart(shardBase64);// 保存文件到本地FileUseEnum useEnum = FileUseEnum.getByCode(use);// 如果目录不存在则创建String dir = useEnum.name().toLowerCase();File fullDir = new File(FILE_PATH + dir);if (!fullDir.exists()) {fullDir.mkdirs();}// course\6sfSqfOwzmik4A4icMYuUe.mp4String path = new StringBuffer(dir).append(File.separator).append(key).append(".").append(suffix).toString();// course\6sfSqfOwzmik4A4icMYuUe.mp4.1String localPath = new StringBuffer(path).append(".").append(fileInfo.getShardIndex()).toString();String fullPath = FILE_PATH + localPath;File dest = new File(fullPath);try {// 保存文件shard.transferTo(dest);} catch (IOException e) {log.error(e.getMessage());return ResultDTO.error("上传失败-" + e.getMessage(), null);}// 保存文件记录fileInfo.setFilePath(path);FileInfo model = this.fileInfoService.queryByKey(fileInfo.getFileKey());if (model == null) {this.fileInfoService.insert(fileInfo);} else {model.setShardIndex(fileInfo.getShardIndex());this.fileInfoService.update(model);}if (fileInfo.getShardIndex().equals(fileInfo.getShardTotal())) {this.merge(fileInfo);}return ResultDTO.success("上传成功", fileInfo);}/*** 文件合并*/public void merge(FileInfo fileInfo) throws InterruptedException {log.info("合并分片开始");// course\6sfSqfOwzmik4A4icMYuUe.mp4String path = fileInfo.getFilePath();Integer shardTotal = fileInfo.getShardTotal();File newFile = new File(FILE_PATH, path);// 文件追加写入FileOutputStream outputStream = null;try {outputStream = new FileOutputStream(newFile, true);} catch (FileNotFoundException e) {log.error(e.getMessage());}// 分片文件FileInputStream fileInputStream = null;byte[] bytes = new byte[10 * 1024 * 1024];int len;try {for (Integer i = 0; i < shardTotal; i++) {// 读取第 i 个分片fileInputStream = new FileInputStream(new File(FILE_PATH + path + "." + (i + 1)));while ((len = fileInputStream.read(bytes)) != -1) {outputStream.write(bytes, 0, len);}}} catch (IOException e) {log.error("合并分片异常-" + e.getMessage());} finally {try {if (fileInputStream != null) {fileInputStream.close();}outputStream.close();log.info("IO流关闭");} catch (IOException e) {log.error("IO流关闭失败-", e.getMessage());}}log.info("合并分片结束");// 释放虚拟机对文件的占用System.gc();Thread.sleep(100);log.info("删除分片开始");for (Integer i = 0; i < shardTotal; i++) {String filePath = FILE_PATH + path + "." + (i + 1);File file = new File(filePath);boolean result = file.delete();log.info("删除{},{}", filePath, result ? "成功" : "失败");}log.info("删除分片结束");}@ApiOperation(value = "文件分片检查")@GetMapping("/check")public ResultDTO<FileInfo> check(@RequestParam(name = "fileKey") String fileKey) {FileInfo fileInfo = this.fileInfoService.queryByKey(fileKey);return ResultDTO.success(fileInfo);}}

6. 接口实现类serviceImpl

这里就不贴service代码了,大家自动生成即可。

package com.javaboy.vhr.service.impl;import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.javaboy.vhr.entity.FileInfo;
import com.javaboy.vhr.mapper.FileInfoMapper;
import com.javaboy.vhr.service.FileInfoService;
import com.javaboy.vhr.utils.UuidUtil;
import org.springframework.stereotype.Service;import javax.annotation.Resource;
import java.util.Date;
import java.util.List;/*** @author: gaoyang* @date: 2021-03-23 10:46:35* @description: 文件(FileInfo)表服务实现类*/
@Service("fileInfoService")
public class FileInfoServiceImpl implements FileInfoService {@Resourceprivate FileInfoMapper fileInfoMapper;/*** 通过ID查询单条数据** @param id 主键* @return 实例对象*/@Overridepublic FileInfo queryById(String id) {return this.fileInfoMapper.queryById(id);}/*** 新增数据** @param fileInfo 实例对象* @return 实例对象*/@Overridepublic FileInfo insert(FileInfo fileInfo) {fileInfo.setId(UuidUtil.getShortUuid());fileInfo.setCreatedAt(new Date());fileInfo.setUpdatedAt(new Date());this.fileInfoMapper.insert(fileInfo);return fileInfo;}/*** 修改数据** @param fileInfo 实例对象* @return 实例对象*/@Overridepublic FileInfo update(FileInfo fileInfo) {fileInfo.setUpdatedAt(new Date());this.fileInfoMapper.update(fileInfo);return this.queryById(fileInfo.getId());}/*** 通过文件标识查询* @param fileKey* @return*/@Overridepublic FileInfo queryByKey(String fileKey) {return this.fileInfoMapper.queryByKey(fileKey);}
}

mybatis语句这里也不贴了,就是简单的增删改查。

源码地址:https://gitee.com/king-high/vhr-master.git

技术交流+微:JavaBoy_1024

SpringBoot+Vue.js实现大文件分片上传、断点续传与极速秒传相关推荐

  1. 大文件分片上传前端框架_基于Node.js的大文件分片上传

    基于Node.js的大文件分片上传 我们在做文件上传的时候,如果文件过大,可能会导致请求超时的情况.所以,在遇到需要对大文件进行上传的时候,就需要对文件进行分片上传的操作.同时如果文件过大,在网络不佳 ...

  2. Vue项目中遇到了大文件分片上传的问题

    Vue项目中遇到了大文件分片上传的问题,之前用过webuploader,索性就把Vue2.0与webuploader结合起来使用,封装了一个vue的上传组件,使用起来也比较舒爽. 上传就上传吧,为什么 ...

  3. 大文件分片上传,断点续传,秒传 实现

    前段时间做视频上传业务,通过网页上传视频到服务器. 视频大小 小则几十M,大则 1G+,以一般的HTTP请求发送数据的方式的话,会遇到的问题:1,文件过大,超出服务端的请求大小限制:2,请求时间过长, ...

  4. 使用webuploader组件实现大文件分片上传,断点续传

    无组件断点续传.gif 1. 组件简介 webuploader:是一个以HTML5为主, Flash为辅的文件上传组件,采用大文件分片/并发上传的方式,极大地提高了文件上传的效率,同时兼容多种浏览器版 ...

  5. 大文件分片上传前后端实现

    最近在做公司的视频业务,涉及到大视频的上传. 之前的图片.Excel等上传做的很简单,直接表单提交后端用MultipartFile接收保存到磁盘就行了. 但是针对大文件的上传,需要做额外的处理,否则可 ...

  6. AWS-S3通用存储操作,操作minio、oss、cos等所有兼容s3协议的云存储(含有大文件分片上传实现)

    一.介绍 通用存储操作common包,支持所有兼容amazon-s3协议的云存储,如minio.oss.cos等,以后客户用啥云储存一套代码都能搞定了,真棒~ 二.代码结构 三.代码实现 3.1 po ...

  7. java实现大文件分片上传

    java实现大文件分片上传 在项目中用到了大文件上传功能,最初从网上参考了一些代码来实现,但是最终的上传效果不是很好,速度比较慢. 之前的上传思路是: 前端利用webUploader分片大文件 后端接 ...

  8. jquery 分片上传php,php 大文件分片上传

    前端部分 上传 //上传控件 uploadBig('upload','zip,rar,7z,tar',{ id: '', type: 'upload_file', } ,(res)=>{ //t ...

  9. 大文件分片上传前端框架_无插件实现大文件分片上传,断点续传

    文件上传.gif 1. 简介: 本篇文章基于实际项目的开发,将介绍项目中关于大文件分片上传.文件验证.断点续传.手动重试上传等需求的使用场景及实现: 2. 项目需求 在一个音视频的添加中,既要有音视频 ...

最新文章

  1. 怎么绘制机械孔_机械图纸中常见的符号及意义,机械人必备!
  2. 没有搜索_没有明显足够搜索量关键词的类目产品应该怎么办?
  3. golang执行多个linux命令,golang执行系统command
  4. linux java解压文件怎么打开,linux下面的解压缩文件的命令
  5. 扬州大学广陵学院c语言试卷,扬州大学广陵学院交直流调速复习题答案(试卷)
  6. 计量芯片HLW8032在充电桩设备中的典型应用
  7. gcc -O0 -O1 -O2 -O3 -Os 编译优化等级
  8. 在家参加OCP考试(MySQL OCP和Oracle OCP)
  9. 搜狗大数据总监、Polarr 联合创始人关于深度学习的分享交流 | 架构师小组交流会...
  10. 安卓沉浸式状态栏_《宫廷秘传》今日安卓计费删档开测
  11. Mac 上必备的常用软件,你值得拥有
  12. 《英文科技论文写作与学术报告》网课第二章作业答案
  13. vue 项目 前端 模拟后端接口数据(vue2,vue3)
  14. 6763个gb2312汉字笔画分析
  15. channel error:reply-code=404, reply-text=NOT_FOUND - no exchange ‘console‘ in vhost ‘/‘, class-id=40
  16. ​兼具Swin和ViT的优势!可用于MAE预训练的超简单层次Transformer结构
  17. C语言实现RC4加密算法
  18. Java8集合过滤操作
  19. J2EE design decisions
  20. yamleasydict作为参数文件

热门文章

  1. POJ 2584 T-Shirt Gumbo 构图 最大流
  2. 远离疲倦,告别非理性思维
  3. UVA10427 Naughty Sleepy Boys【数学】
  4. CCF NOI1021 发放奖金
  5. C++ 多线程与并发
  6. 广义逆高斯分布(Generalized Inverse Gaussian Distribution)及修正贝塞尔函数
  7. Hopfield 神经网络及稳态性的证明
  8. Python 标准库 —— xml
  9. 传递给 left 或 substring 函数的长度参数无效_MySQL:函数入门实例
  10. 类worksheet的paste方法无效_英雄档案——类人体