FastDfs分片上传文件实战
1、引入的依赖
<!--redis依赖配置-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--FastDfs-->
<dependency> <groupId>com.github.tobato</groupId> <artifactId>fastdfs-client</artifactId> <version>1.26.7</version>
</dependency>
2、分片上传参数实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class MultipartFileParam {/** * 当前要上传第几分片 */private long chunkNumber; /** * 每个分片的大小 */ private long chunkSize; /** * 分片总数 */ private long totalChunks; /** * 文件唯一标识 */ private String identifier; /** * 分块文件传输对象 */ private MultipartFile file;
}
3、分片上传文件
分片上传文件的思想:首先,前端先加载检测文件大小,并将文件按照一定大小拆分成若干等分,同时为每一个分片文件按顺序标好序号;然后前端根据文件序号按顺序请求上传文件接口;最后,FastDFS将接收到的文件按顺序追加整合成完整的文件。
在实际工作中,分片上传文件会遇到一些问题,如:
- 前端请求上传文件不总是按照分片序号的顺序去请求
- 重复上传分片文件
以下代码主要解决这两个问题:
//先检查已经上传到第几片了 String checkUploadChunkNum = (String)redisService.get(CommonConstant.uploadChunkNum+identifier); if (checkUploadChunkNum==null && chunkNumber!=1){ //如果当前即将上传的分片不是第一片,而且又查询不到之前的之前已经存在的分片记录,则上传失败 throw new SystemException(ResultEnum.ERR.getCode(),"上传失败"); }else if (checkUploadChunkNum!=null && chunkNumber-1<Long.valueOf(checkUploadChunkNum)){//当前即将上传的分片序号-1小于已经上传的分片序号,说明已经重复上传了 throw new SystemException(ResultEnum.ERR.getCode(),"重复上传"); }else if (checkUploadChunkNum!=null && chunkNumber-1>Long.valueOf(checkUploadChunkNum)){ //如果当前即将上传的分片序号-1大于已经上传的分片序号,说明提前上传了,需要等待前面序号的分片上传完才能开始上传//循环最多执行100次,最多执行100*100/1000=10(秒)int time = 100;while (time>0){//每次循环休眠100毫秒Thread.sleep(100);time--;//每次循环检查已经上传分片的最新序号checkUploadChunkNum = (String) redisService.get(CommonConstant.uploadChunkNum+identifier);if (chunkNumber-1==Long.valueOf(checkUploadChunkNum)){ //如果当前准备上传的分片序号-1等于已经上传分片的最新序号,则跳出循环break; }}}
完整代码:
@RestController
public class FastDFSController {/** * 视频缓存时间,秒:1天; */ private final Integer cacheTime = 60 * 60 * 24; @Autowired private AppendFileStorageClient appendFileStorageClient; @Autowired private RedisService redisService;@PostMapping("/uploadFile")public String uploadFile(MultipartFileParam param){//当前第几分片 long chunkNumber = param.getChunkNumber(); //每个分片的大小 long chunkSize = param.getChunkSize(); //分片总数 long totalChunks = param.getTotalChunks(); //文件唯一标识 String identifier = param.getIdentifier(); //分块文件传输对象 MultipartFile file = param.getFile(); //文件后缀名 String fileName = FileUtil.extName(file.getOriginalFilename()); //历史上传文件大小 long historyUploadSize = (chunkNumber-1)*chunkSize; //包含组和服务器文件路径,例如:StorePath [group=group1, path=M00/00/00/xxx.xxx] StorePath storePath = null; //服务器文件路径,例如:M00/00/00/xxx.xxx String groundPath;try{ //先检查已经上传到第几片了 String checkUploadChunkNum = (String)redisService.get(CommonConstant.uploadChunkNum+identifier); if (checkUploadChunkNum==null && chunkNumber!=1){ //如果当前即将上传的分片不是第一片,而且又查询不到之前的之前已经存在的分片记录,则上传失败 throw new SystemException(ResultEnum.ERR.getCode(),"上传失败"); }else if (checkUploadChunkNum!=null && chunkNumber-1<Long.valueOf(checkUploadChunkNum)){//当前即将上传的分片序号-1小于已经上传的分片序号,说明已经重复上传了 throw new SystemException(ResultEnum.ERR.getCode(),"重复上传"); }else if (checkUploadChunkNum!=null && chunkNumber-1>Long.valueOf(checkUploadChunkNum)){ //如果当前即将上传的分片序号-1大于已经上传的分片序号,说明提前上传了,需要等待前面序号的分片上传完才能开始上传//循环最多执行100次,最多执行100*100/1000=10(秒)int time = 100;while (time>0){//每次循环休眠100毫秒Thread.sleep(100);time--;//每次循环检查已经上传分片的最新序号checkUploadChunkNum = (String) redisService.get(CommonConstant.uploadChunkNum+identifier);if (chunkNumber-1==Long.valueOf(checkUploadChunkNum)){ //如果当前准备上传的分片序号-1等于已经上传分片的最新序号,则跳出循环break; }}}//若上传的是第一片,且只有一片,上传完就结束if (chunkNumber == 1 ){ if (checkUploadChunkNum !=null){ throw new SystemException(ResultEnum.ERR.getCode(),"第一片已经上传"); } storePath = appendFileStorageClient.uploadAppenderFile(CommonConstant.DEFAULT_GROUP, file.getInputStream(),file.getSize(), fileName);//记录当前传入第一片redisService.set(CommonConstant.uploadChunkNum+identifier,String.valueOf(chunkNumber),cacheTime);if (storePath == null){ throw new SystemException(ResultEnum.ERR.getCode(),"第一片上传失败"); } //总共只有一片就返回 if (totalChunks == 1){ //如果只有一片,直接返回结果 return storePath.getPath(); }else { //记录已存存文件路径redisService.set(CommonConstant.fastDfsPath+identifier,storePath.getPath(),cacheTime); return "第:"+chunkNumber+"上传成功"; }} else {if (chunkNumber-1 == Long.valueOf(checkUploadChunkNum)){ //获取已存文件路径 groundPath = (String) redisService.get(CommonConstant.fastDfsPath+identifier);if (groundPath == null){ throw new SystemException(ResultEnum.ERR.getCode(),"获取文件路径失败"); } //追加文件appendFileStorageClient.modifyFile(CommonConstant.DEFAULT_GROUP, groundPath, file.getInputStream(),file.getSize(), historyUploadSize); //修改已存文件片数redisService.set(CommonConstant.uploadChunkNum+identifier,String.valueOf(chunkNumber),cacheTime);if (chunkNumber == totalChunks){ //最后一片,返回结果 return groundPath; } return "第:"+chunkNumber+"上传成功"; }else { logger.error("第:"+chunkNumber+"上传失败,原因:当前上传"); throw new SystemException(ResultEnum.ERR.getCode(),"第:"+chunkNumber+"上传失败");}}}catch (Exception e){ e.printStackTrace(); logger.error("第:"+chunkNumber+"上传失败,原因:{}",e); throw new SystemException(ResultEnum.ERR.getCode(),"第:"+chunkNumber+"上传失败"); }}
}
4、CommonConstant类
public class CommonConstant {private final static String uploading="Uploading:"; private final static String file=uploading+"file:"; /** * 记录当前文件上传了多少片 */ public final static String uploadChunkNum=file+"chunkNum:"; /** * 当前文件上传到fastdfs路径 * */ public final static String fastDfsPath=file+"fastDfsPath:"; /** * 默认分组 */ public final static String DEFAULT_GROUP = "group1";}
FastDfs分片上传文件实战相关推荐
- Python3爬取迅捷语音转文字(包含持久化登陆和分片上传文件)
前言 在这里我就不再一一介绍每个步骤的具体操作了,因为在上一次爬取今日头条数据的时候都已经讲的非常清楚了,所以在这里我只会在重点上讲述这个是这么实现的,如果想要看具体步骤请先去看我今日头条的文章内容, ...
- 上传文件慢,SpringBoot分片上传文件
Java上传文件慢,大文件上传卡顿,请求超时怎么办? 话不多说直接上代码,代码复制过去可以直接使用 第一步:创建后端代码 package cn.leon.demo.rest;import lombok ...
- 【转载】前端上传文件,python作为后端接收并保存到本地--Tornado上传文件--分片上传文件--更换pip下载源
背景:在改造caffe自带demo时,增加了一个更新模型的功能,需要将用户训练好的caffemodel上传到服务器,并替换到已经存在的caffemodel文件,重新加载上传的caffemodel文件并 ...
- fastdfs java上传文件_FastDFS java客户端文件上传demo
FastDFS不多讲,直接上java调用代码,以下代码是一个spring mvc中一个完整的上传请求,请参阅 @RequestMapping(value = "/upload", ...
- simple-uploader前端分片上传文件
前言 对于大型文件的上传处理,我们不可能只是单纯的把整个文件,通过一个请求去上传,这样效率很低,且上传速度很慢.所以这种时候就需要前端去对上传的文件做分割处理,将文件分成一小片一小片的,然后再同时发起 ...
- FastDFS 流上传文件缩略图保存
public Result<String> uploadFileThumbnail(MultipartFile file) {String fileNname = file.getOrig ...
- connect to server 192.168.xxx.xxx:22122 fail 使用FastDFS测试上传文件时报错
出现这种情况别着急 解决方法: 1.查看.conf文件 检查tracker_server ip地址是否正确 2.虚拟机中查看/etc/fdfs/中的storage.conf和client.conf配置 ...
- vue+element-ui大文件的分片上传和断点续传js-spark-md5和browser-md5-file
注意:以下共两份代码片段,第一份为原博主链接代码,第二份自己写的整体代码(比较乱) 1.参考 https://www.cnblogs.com/kelelipeng/p/10158599.html (j ...
- java web 断点上传_使用WebUploader实现分片断点上传文件功能(二)
写在前面: 这几天,有去研究一下WebUploader上传文件,前面的博客有记录下使用WebUploader简单上传文件的例子,今天就把分片断点上传的例子也记录下吧,在博客园中,也查看了一些资料,基本 ...
最新文章
- 一篇文章告诉你标准化和归一化的区别?
- 简单套路发高分文章--杨树内生和根际微生物组结构
- mysql 与 oracle 的连表update
- mysql 子查询优化一例
- oracle linux6 u盘安装,Oracle Enterprise Linux/Redhat Linux 6.0 U盘安装方法
- Z-blog拓源纯净主题
- 火爆全网的迁移学习简明手册全面更新,重磅出版上市!
- python队列来做什么_简单介绍python的双向队列
- 直线段的矢栅转换算法(DDA算法、中心画线算法、Bresenham算法)
- Win10安装乌班图18双系统
- 中国医药中间体行业盈利状况与竞争趋势预测报告(新版)2022-2027年
- DNS配置错误如何修复
- Spark技能成长,CSDN就go了!
- 摩拜创始人套现15亿:你的同龄人,正在抛弃你+韩寒回应
- http状态码大全,从100-505状态码详情
- STDP学习机制(使用Brian2仿真)
- deepin 命令行卸载软件
- CatchCat攻防世界 MISC
- 借贷记账法下的账户对应关系_借贷记账法下的账户对应关系,是指一个账户借方与另一个账户贷方之间的相互对应关系。...
- LinUx安装PSX模拟器,ePSXe-增强型PSX模拟器怎么用啊?