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分片上传文件实战相关推荐

  1. Python3爬取迅捷语音转文字(包含持久化登陆和分片上传文件)

    前言 在这里我就不再一一介绍每个步骤的具体操作了,因为在上一次爬取今日头条数据的时候都已经讲的非常清楚了,所以在这里我只会在重点上讲述这个是这么实现的,如果想要看具体步骤请先去看我今日头条的文章内容, ...

  2. 上传文件慢,SpringBoot分片上传文件

    Java上传文件慢,大文件上传卡顿,请求超时怎么办? 话不多说直接上代码,代码复制过去可以直接使用 第一步:创建后端代码 package cn.leon.demo.rest;import lombok ...

  3. 【转载】前端上传文件,python作为后端接收并保存到本地--Tornado上传文件--分片上传文件--更换pip下载源

    背景:在改造caffe自带demo时,增加了一个更新模型的功能,需要将用户训练好的caffemodel上传到服务器,并替换到已经存在的caffemodel文件,重新加载上传的caffemodel文件并 ...

  4. fastdfs java上传文件_FastDFS java客户端文件上传demo

    FastDFS不多讲,直接上java调用代码,以下代码是一个spring mvc中一个完整的上传请求,请参阅 @RequestMapping(value = "/upload", ...

  5. simple-uploader前端分片上传文件

    前言 对于大型文件的上传处理,我们不可能只是单纯的把整个文件,通过一个请求去上传,这样效率很低,且上传速度很慢.所以这种时候就需要前端去对上传的文件做分割处理,将文件分成一小片一小片的,然后再同时发起 ...

  6. FastDFS 流上传文件缩略图保存

    public Result<String> uploadFileThumbnail(MultipartFile file) {String fileNname = file.getOrig ...

  7. connect to server 192.168.xxx.xxx:22122 fail 使用FastDFS测试上传文件时报错

    出现这种情况别着急 解决方法: 1.查看.conf文件 检查tracker_server ip地址是否正确 2.虚拟机中查看/etc/fdfs/中的storage.conf和client.conf配置 ...

  8. vue+element-ui大文件的分片上传和断点续传js-spark-md5和browser-md5-file

    注意:以下共两份代码片段,第一份为原博主链接代码,第二份自己写的整体代码(比较乱) 1.参考 https://www.cnblogs.com/kelelipeng/p/10158599.html (j ...

  9. java web 断点上传_使用WebUploader实现分片断点上传文件功能(二)

    写在前面: 这几天,有去研究一下WebUploader上传文件,前面的博客有记录下使用WebUploader简单上传文件的例子,今天就把分片断点上传的例子也记录下吧,在博客园中,也查看了一些资料,基本 ...

最新文章

  1. 一篇文章告诉你标准化和归一化的区别?
  2. 简单套路发高分文章--杨树内生和根际微生物组结构
  3. mysql 与 oracle 的连表update
  4. mysql 子查询优化一例
  5. oracle linux6 u盘安装,Oracle Enterprise Linux/Redhat Linux 6.0 U盘安装方法
  6. Z-blog拓源纯净主题
  7. 火爆全网的迁移学习简明手册全面更新,重磅出版上市!
  8. python队列来做什么_简单介绍python的双向队列
  9. 直线段的矢栅转换算法(DDA算法、中心画线算法、Bresenham算法)
  10. Win10安装乌班图18双系统
  11. 中国医药中间体行业盈利状况与竞争趋势预测报告(新版)2022-2027年
  12. DNS配置错误如何修复
  13. Spark技能成长,CSDN就go了!
  14. 摩拜创始人套现15亿:你的同龄人,正在抛弃你+韩寒回应
  15. http状态码大全,从100-505状态码详情
  16. STDP学习机制(使用Brian2仿真)
  17. deepin 命令行卸载软件
  18. CatchCat攻防世界 MISC
  19. 借贷记账法下的账户对应关系_借贷记账法下的账户对应关系,是指一个账户借方与另一个账户贷方之间的相互对应关系。...
  20. LinUx安装PSX模拟器,ePSXe-增强型PSX模拟器怎么用啊?

热门文章

  1. JVM-内存溢出场景模拟
  2. DIY修改博客园背景用【保存图片用】
  3. Spring MVC静态资源实例
  4. 地铁建设 (Standard IO)
  5. 这是我用Microsoft Word 2010 直接发布的测试用博客
  6. 【转】win7 32位安装oracle10g步骤
  7. DX10 Shadow Volumn Sample Code的Bug修正
  8. MSDN Visual系列:利用关联来过滤MOSS中的BDC数据
  9. javascript基础系列:数组常用方法解析
  10. 基于meanshift的手势跟踪与电脑鼠标控制(手势交互系统)